From be359980bb0e7f9e05aafa9b7a53396826dbfdb2 Mon Sep 17 00:00:00 2001 From: Yandrik Date: Sat, 20 Apr 2024 16:32:01 +0200 Subject: [PATCH] feat: major progress --- .metadata | 30 + README.md | 16 +- analysis_options.yaml | 4 + assets/geo/uulm_beta.geojson | 2070 ++++++++++++++++++ lib/components/{drawer..dart => drawer.dart} | 11 +- lib/components/hamburger_menu.dart | 17 + lib/components/map_render_level.dart | 256 +++ lib/controllers/map_controller.dart | 67 + lib/data/geo/model.dart | 70 + lib/data/geo/model.freezed.dart | 1864 ++++++++++++++++ lib/data/geo/parser.dart | 142 ++ lib/main.dart | 11 +- lib/map.dart | 397 +++- lib/settings copy.dart | 21 + lib/settings.dart | 21 + lib/util/geomath.dart | 37 + pubspec.lock | 328 +++ pubspec.yaml | 15 +- test/geojson_tests.dart | 1 + 19 files changed, 5328 insertions(+), 50 deletions(-) create mode 100644 .metadata create mode 100644 assets/geo/uulm_beta.geojson rename lib/components/{drawer..dart => drawer.dart} (70%) create mode 100644 lib/components/hamburger_menu.dart create mode 100644 lib/components/map_render_level.dart create mode 100644 lib/controllers/map_controller.dart create mode 100644 lib/data/geo/model.dart create mode 100644 lib/data/geo/model.freezed.dart create mode 100644 lib/data/geo/parser.dart create mode 100644 lib/settings copy.dart create mode 100644 lib/settings.dart create mode 100644 lib/util/geomath.dart create mode 100644 test/geojson_tests.dart diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..faee040 --- /dev/null +++ b/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + - platform: android + create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/README.md b/README.md index 7a8b409..46d3b43 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,8 @@ # uninav -A new Flutter project. +App to navigate in Universities. Developed at Uni Ulm, but made to be adaptable for all other universities, or complex indoor navigation environments -## Getting Started +## Building and such -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +run `flutter run` for running the app on your device. +run `dart run build_runner build` to run the code generator \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index 0d29021..f69f114 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -26,3 +26,7 @@ linter: # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options + +analyzer: + errors: + invalid_annotation_target: ignore \ No newline at end of file diff --git a/assets/geo/uulm_beta.geojson b/assets/geo/uulm_beta.geojson new file mode 100644 index 0000000..cc80dc7 --- /dev/null +++ b/assets/geo/uulm_beta.geojson @@ -0,0 +1,2070 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "O26", + "description": "connections: [O25, O27]", + "layer": "buildings" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.956487, + 48.422766 + ], + [ + 9.956754, + 48.422869 + ], + [ + 9.956875, + 48.422724 + ], + [ + 9.956864, + 48.422719 + ], + [ + 9.956912, + 48.422659 + ], + [ + 9.956663, + 48.422563 + ], + [ + 9.956805, + 48.422393 + ], + [ + 9.956499, + 48.422281 + ], + [ + 9.956359, + 48.42245 + ], + [ + 9.956106, + 48.422355 + ], + [ + 9.956057, + 48.422414 + ], + [ + 9.95607, + 48.422419 + ], + [ + 9.955976, + 48.42253 + ], + [ + 9.955959, + 48.422526 + ], + [ + 9.955931, + 48.422559 + ], + [ + 9.95619, + 48.422653 + ], + [ + 9.956046, + 48.422825 + ], + [ + 9.956348, + 48.422933 + ], + [ + 9.956487, + 48.422766 + ] + ] + ] + }, + "id": "E0NjM" + }, + { + "type": "Feature", + "properties": { + "name": "O27", + "layer": "buildings" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.957511, + 48.422725 + ], + [ + 9.95749, + 48.422716 + ], + [ + 9.957505, + 48.422703 + ], + [ + 9.957501, + 48.422687 + ], + [ + 9.95752, + 48.422666 + ], + [ + 9.957304, + 48.42259 + ], + [ + 9.95714, + 48.422781 + ], + [ + 9.957071, + 48.422793 + ], + [ + 9.956872, + 48.422723 + ], + [ + 9.956754, + 48.422869 + ], + [ + 9.957041, + 48.422971 + ], + [ + 9.957057, + 48.42301 + ], + [ + 9.957013, + 48.423063 + ], + [ + 9.956992, + 48.423067 + ], + [ + 9.956977, + 48.423086 + ], + [ + 9.956978, + 48.423105 + ], + [ + 9.956937, + 48.423155 + ], + [ + 9.956951, + 48.423159 + ], + [ + 9.956942, + 48.423163 + ], + [ + 9.957128, + 48.423232 + ], + [ + 9.957134, + 48.423228 + ], + [ + 9.957148, + 48.423235 + ], + [ + 9.957313, + 48.423032 + ], + [ + 9.957367, + 48.423022 + ], + [ + 9.957596, + 48.423104 + ], + [ + 9.957717, + 48.422963 + ], + [ + 9.957557, + 48.422903 + ], + [ + 9.95758, + 48.422903 + ], + [ + 9.957604, + 48.422864 + ], + [ + 9.957598, + 48.422852 + ], + [ + 9.957604, + 48.422853 + ], + [ + 9.957634, + 48.422817 + ], + [ + 9.95761, + 48.422752 + ], + [ + 9.957552, + 48.422732 + ], + [ + 9.957516, + 48.422737 + ], + [ + 9.957511, + 48.422725 + ] + ] + ] + }, + "id": "QwNzY" + }, + { + "type": "Feature", + "properties": { + "name": "O28", + "layer": "buildings" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.957694, + 48.42299 + ], + [ + 9.957633, + 48.423065 + ], + [ + 9.957685, + 48.423083 + ], + [ + 9.957655, + 48.423117 + ], + [ + 9.957988, + 48.423238 + ], + [ + 9.958181, + 48.423011 + ], + [ + 9.957855, + 48.422888 + ], + [ + 9.957753, + 48.423011 + ], + [ + 9.957694, + 48.42299 + ] + ] + ] + }, + "id": "g2OTc" + }, + { + "type": "Feature", + "properties": { + "name": "O29", + "layer": "buildings" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.957469, + 48.423339 + ], + [ + 9.957796, + 48.423461 + ], + [ + 9.957907, + 48.423329 + ], + [ + 9.957583, + 48.423205 + ], + [ + 9.957469, + 48.423339 + ] + ] + ] + }, + "id": "gwNDk" + }, + { + "type": "Feature", + "properties": { + "name": "O25", + "layer": "buildings" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.955818, + 48.422616 + ], + [ + 9.955785, + 48.422601 + ], + [ + 9.95577, + 48.422642 + ], + [ + 9.955799, + 48.422687 + ], + [ + 9.955697, + 48.422756 + ], + [ + 9.955543, + 48.422697 + ], + [ + 9.955557, + 48.422639 + ], + [ + 9.955538, + 48.422633 + ], + [ + 9.955527, + 48.422642 + ], + [ + 9.955314, + 48.422563 + ], + [ + 9.955325, + 48.422551 + ], + [ + 9.955048, + 48.42245 + ], + [ + 9.955055, + 48.422444 + ], + [ + 9.955036, + 48.422436 + ], + [ + 9.955056, + 48.422407 + ], + [ + 9.955237, + 48.422373 + ], + [ + 9.95524, + 48.422384 + ], + [ + 9.955286, + 48.422377 + ], + [ + 9.955311, + 48.422345 + ], + [ + 9.955327, + 48.422336 + ], + [ + 9.955121, + 48.422257 + ], + [ + 9.955229, + 48.422134 + ], + [ + 9.955276, + 48.42208 + ], + [ + 9.955304, + 48.422091 + ], + [ + 9.955358, + 48.422031 + ], + [ + 9.955408, + 48.422053 + ], + [ + 9.955404, + 48.422089 + ], + [ + 9.955424, + 48.422081 + ], + [ + 9.95544, + 48.422062 + ], + [ + 9.955503, + 48.422086 + ], + [ + 9.955498, + 48.422097 + ], + [ + 9.955538, + 48.422112 + ], + [ + 9.955548, + 48.422102 + ], + [ + 9.955877, + 48.422225 + ], + [ + 9.955889, + 48.422207 + ], + [ + 9.955986, + 48.42224 + ], + [ + 9.955944, + 48.422297 + ], + [ + 9.956104, + 48.422357 + ], + [ + 9.956058, + 48.422415 + ], + [ + 9.956069, + 48.422422 + ], + [ + 9.955976, + 48.422532 + ], + [ + 9.955959, + 48.422527 + ], + [ + 9.955933, + 48.422558 + ], + [ + 9.955913, + 48.422553 + ], + [ + 9.955818, + 48.422616 + ] + ] + ] + }, + "id": "YzMDM" + }, + { + "type": "Feature", + "properties": { + "layer": "buildings" + }, + "geometry": { + "type": "LineString", + "coordinates": [] + }, + "id": "Y2OTY" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: male\nbuilding: o29\n\n", + "layer": "level_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957543, + 48.423354 + ] + }, + "id": "AzNzU" + }, + { + "type": "Feature", + "properties": { + "name": "stairs", + "description": "type: stairs\nbuilding: o29\nconnects_levels: [1,2,3]", + "layer": "stairs" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957509, + 48.423328 + ] + }, + "id": "E5MDQ" + }, + { + "type": "Feature", + "properties": { + "layer": "stairs", + "name": "stairs", + "description": "type: stairs\nbuilding: o29\nconnects_levels: [1,2,3]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957828, + 48.42339 + ] + }, + "id": "I1Njk" + }, + { + "type": "Feature", + "properties": { + "name": "lift", + "layer": "lift", + "description": "type: lift\nbuilding: o29\nconnects_levels: [1, 2, 3]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957559, + 48.423315 + ] + }, + "id": "c0NDc" + }, + { + "type": "Feature", + "properties": { + "name": "stairs", + "description": "type: stairs\nbuilding: o28\nconnects_levels: [1, 2]", + "layer": "stairs" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957705, + 48.423024 + ] + }, + "id": "gwNTI" + }, + { + "type": "Feature", + "properties": { + "name": "stairs", + "description": "type: stairs\nbuilding: o27\nconnects_levels: [1, 2, 3, 4, 5]", + "layer": "stairs" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957215, + 48.422917 + ] + }, + "id": "EzODk" + }, + { + "type": "Feature", + "properties": { + "name": "lift", + "description": "type: lift\nbuilding: o27\nconnects_levels: [1, 2, 3, 4, 5]", + "layer": "lift" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957325, + 48.422964 + ] + }, + "id": "g1NjU" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: male\nbuilding: o27\n", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957029, + 48.422951 + ] + }, + "id": "Y0NDM" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: handicap\nbuilding: o27", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957162, + 48.422794 + ] + }, + "id": "QzNjE" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: female\nbuilding: o27", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957179, + 48.422783 + ] + }, + "id": "A2MTA" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: female\nbuilding: o26", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956392, + 48.42254 + ] + }, + "id": "cxNTM" + }, + { + "type": "Feature", + "properties": { + "name": "stairs", + "description": "type: stairs\nbuilding: o26\nconnects_levels: [1, 2]", + "layer": "stairs" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956448, + 48.422549 + ] + }, + "id": "MwOTA" + }, + { + "type": "Feature", + "properties": { + "name": "lift", + "layer": "lift", + "description": "type: lift\nbuilding: o26\nconnects_levels: [1, 2, 3, 4, 5]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956493, + 48.422605 + ] + }, + "id": "YzNDY" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "layer": "layer_3", + "description": "type: toilet\nlevel: 3\ntoilet_type: male\nbuilding: o29" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957544, + 48.423355 + ] + }, + "id": "g0MzY" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 2\ntoilet_type: handicap\nbuilding: o29", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957545, + 48.423342 + ] + }, + "id": "k1ODA" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: female\nbuilding: o29", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957547, + 48.423343 + ] + }, + "id": "MzNjc" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 3\ntoilet_type: female\nbuilding: o29", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957551, + 48.423339 + ] + }, + "id": "I2MTE" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 2\ntoilet_type: male\nbuilding: o27", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957029, + 48.42295 + ] + }, + "id": "IzMDg" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 2\ntoilet_type: female\nbuilding: o27", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95704, + 48.422941 + ] + }, + "id": "k4Njg" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 3\ntoilet_type: male\nbuilding: o27", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957201, + 48.422991 + ] + }, + "id": "MxNjQ" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 3\ntoilet_type: female\nbuilding: o27", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95724, + 48.422844 + ] + }, + "id": "M1ODg" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 4\ntoilet_type: male\nbuilding: o27", + "layer": "layer_4" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957203, + 48.422989 + ] + }, + "id": "I3Nzk" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 4\ntoilet_type: female\nbuilding: o27", + "layer": "layer_4" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95724, + 48.422844 + ] + }, + "id": "Y1MTU" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 5\ntoilet_type: male\nbuilding: o27", + "layer": "layer_5" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957201, + 48.422991 + ] + }, + "id": "kyOTM" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 5\ntoilet_type: female\nbuilding: o27", + "layer": "layer_5" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957242, + 48.422843 + ] + }, + "id": "gzMzY" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o29, outside]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957527, + 48.423267 + ] + }, + "id": "A1NDQ" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o28, outside]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957663, + 48.423077 + ] + }, + "id": "A0MTY" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 1\nconnects: [o28, outside]", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957729, + 48.422999 + ] + }, + "id": "I3MjA" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o28, outside]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.958054, + 48.42316 + ] + }, + "id": "kyNTc" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 1\nconnects: [o28, o27]", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957643, + 48.423046 + ] + }, + "id": "g2Mzc" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o28, o27]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957645, + 48.423047 + ] + }, + "id": "E2MTk" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 1\nconnects: [o27, outside]", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957454, + 48.422637 + ] + }, + "id": "gwMTE" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o27, outside]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95701, + 48.423186 + ] + }, + "id": "IzMDU" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: male\nbuilding: o26", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95649, + 48.422643 + ] + }, + "id": "I1NjU" + }, + { + "type": "Feature", + "properties": { + "name": "stairs", + "description": "type: stairs\nbuilding: o26\nconnects_levels: [2, 3, 4, 5]", + "layer": "stairs" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956426, + 48.422602 + ] + }, + "id": "k0NTQ" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 2\ntoilet_type: female\nbuilding: o26", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956459, + 48.422644 + ] + }, + "id": "QwMTM" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 2\ntoilet_type: male\nbuilding: o26", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956471, + 48.422635 + ] + }, + "id": "UwMTk" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 3\ntoilet_type: female\nbuilding: o26", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956471, + 48.422638 + ] + }, + "id": "AwNzg" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 3\ntoilet_type: male\nbuilding: o26", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956501, + 48.422642 + ] + }, + "id": "Y4ODI" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 5\ntoilet_type: male\nbuilding: o26", + "layer": "layer_5" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956503, + 48.422639 + ] + }, + "id": "c3Nzc" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 5\ntoilet_type: female\nbuilding: o26", + "layer": "layer_5" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956471, + 48.422633 + ] + }, + "id": "QwMTc" + }, + { + "type": "Feature", + "properties": { + "name": "food_drink", + "description": "type: food_drink\nbuilding: o27", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95736, + 48.422972 + ] + }, + "id": "Q1MTY" + }, + { + "type": "Feature", + "properties": { + "name": "lift", + "description": "type: lift\nbuilding: o25\nconnects_levels: [1, 2, 3, 4, 5, 6]", + "layer": "lift" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955672, + 48.422277 + ] + }, + "id": "c0Nzk" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: female\nbuilding: o25", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955547, + 48.422256 + ] + }, + "id": "c1NjM" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 1\ntoilet_type: male\nbuilding: รถ26", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955476, + 48.422234 + ] + }, + "id": "UyNjA" + }, + { + "type": "Feature", + "properties": { + "name": "stairs", + "description": "type: stairs\nbuilding: o25\nconnecting_levels: [1, 2]", + "layer": "stairs" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955645, + 48.422265 + ] + }, + "id": "M3Njc" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 2\ntoilet_type: male\nbuilding: o25", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955672, + 48.422339 + ] + }, + "id": "M2NTA" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 2\ntoilet_type: female\nbuilding: o25", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955696, + 48.422312 + ] + }, + "id": "g0OTM" + }, + { + "type": "Feature", + "properties": { + "description": "type: public_transport\nbus_lines: [5, 8, 13, E, N3]\ntram_lines: [2]", + "name": "public_transport", + "layer": "layer_public_transport" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.956899, + 48.422292 + ], + [ + 9.956365, + 48.421983 + ], + [ + 9.956195, + 48.421858 + ], + [ + 9.956258, + 48.421767 + ], + [ + 9.956371, + 48.421696 + ], + [ + 9.957063, + 48.422208 + ], + [ + 9.956899, + 48.422292 + ] + ] + ] + }, + "id": "Y4NjA" + }, + { + "type": "Feature", + "properties": { + "description": "type: public_transport\nbus_lines: [5, 13, E, N3]\ntram_lines: [2]", + "name": "public_transport", + "layer": "layer_public_transport" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.956491, + 48.425174 + ], + [ + 9.956648, + 48.425245 + ], + [ + 9.957028, + 48.424888 + ], + [ + 9.956888, + 48.424832 + ], + [ + 9.956679, + 48.424985 + ], + [ + 9.956491, + 48.425174 + ] + ] + ] + }, + "id": "QyMjQ" + }, + { + "type": "Feature", + "properties": { + "name": "stairs", + "layer": "stairs", + "description": "type: stairs\nbuilding: o25\nconnects_levels: [2, 3, 4, 5, 6]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955629, + 48.42231 + ] + }, + "id": "c1MzM" + }, + { + "type": "Feature", + "properties": { + "layer": "layer_2", + "description": "type: food_drink\nbuilding: o25", + "name": "food_drink" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955884, + 48.422395 + ] + }, + "id": "M5OTg" + }, + { + "type": "Feature", + "properties": { + "name": "food_drink", + "description": "type: food_drink\nbuilding: o25", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955599, + 48.422217 + ] + }, + "id": "I3MTA" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 3\ntoilet_type: female\nbuilding: o25", + "layer": "laye_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955642, + 48.422266 + ] + }, + "id": "EyNjk" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "description": "type: toilet\nlevel: 3\ntoilet_type: male\nbuilding: o25\n" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955657, + 48.422252 + ] + }, + "id": "UxNjU" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "layer": "layer_4", + "description": "type: toilet\nlevel: 4\ntoilet_type: female\nbuilding: o25" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955644, + 48.422266 + ] + }, + "id": "I4MjE" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "layer": "layer_4", + "description": "type: toilet\nlevel: 4\ntoilet_type: male\nbuilding: o25" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955656, + 48.422252 + ] + }, + "id": "Q3MTg" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "layer": "layer_5", + "description": "type: toilet\nlevel: 5\ntoilet_type: male\nbuilding: o25" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955657, + 48.422253 + ] + }, + "id": "I0NzE" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "layer": "layer_5", + "description": "type: toilet\nlevel: 5\ntoilet_type: female\nbuilding: o25" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955642, + 48.422266 + ] + }, + "id": "M4NzY" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "layer": "layer_6", + "description": "type: toilet\nlevel: 6\ntoilet_type: male\nbuilding: o25" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955657, + 48.422253 + ] + }, + "id": "M5Njk" + }, + { + "type": "Feature", + "properties": { + "name": "toilet", + "layer": "layer_6", + "description": "type: toilet\nlevel: 6\ntoilet_type: female\nbuilding: o25" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955642, + 48.422266 + ] + }, + "id": "U2Mjc" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 1\nconnects: [o26, o27]", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956836, + 48.422768 + ] + }, + "id": "Q3ODk" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 1\nconnects: [o26, o25]", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956043, + 48.422448 + ] + }, + "id": "U0OTA" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "layer": "layer_2", + "description": "type: door\nlevel: 2\nconnects: [o26, o27]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956847, + 48.422754 + ] + }, + "id": "UwOTg" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o26, o25]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956003, + 48.422497 + ] + }, + "id": "U3NzE" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 3\nconnects: [o26, o25]", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956051, + 48.42244 + ] + }, + "id": "EyMjg" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "layer": "layer_4", + "description": "type: door\nlevel: 4\nconnects: [o26, o25]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956026, + 48.422464 + ] + }, + "id": "IxMTA" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "layer": "layer_5", + "description": "type: door\nlevel: 5\nconnects: [o26, o27]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95679, + 48.422821 + ] + }, + "id": "gzMDQ" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "layer": "layer_5", + "description": "type: door\nlevel: 5\nconnects: [o26, o25]" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.956034, + 48.422457 + ] + }, + "id": "I4OTg" + }, + { + "type": "Feature", + "properties": { + "name": "lecture_hall", + "description": "type: lecture_hall\nlevel: 2\nbuilding: o28\ndescription: Big Lecture Hall, often used for Info lectures" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957997, + 48.423037 + ] + }, + "id": "EzMzc" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "description": "type: seminar_room\nlevel: 1\nbuilding: o29\nnumber: 1001", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.9576, + 48.423238 + ] + }, + "id": "UwMDc" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_1", + "description": "type: seminar_room\nlevel: 1\nbuilding: o29\nnumber: 1002" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957674, + 48.423266 + ] + }, + "id": "cxODg" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_1", + "description": "type: seminar_room\nlevel: 1\nbuilding: o29\nnumber: 1003" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957759, + 48.423297 + ] + }, + "id": "IxMTM" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_1", + "description": "type: seminar_room\nlevel: 1\nbuilding: o29\nnumber: 1004" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957835, + 48.423322 + ] + }, + "id": "cwODM" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "description": "type: seminar_room\nlevel: 2\nbuilding: o29\nnumber: 2001", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957598, + 48.423239 + ] + }, + "id": "k4MDk" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "description": "type: seminar_room\nlevel: 2\nbuilding: o29\nnumber: 2002", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957675, + 48.423267 + ] + }, + "id": "UyMDc" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "description": "type: seminar_room\nlevel: 2\nbuilding: o29\nnumber: 2003", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957757, + 48.423296 + ] + }, + "id": "U3MDE" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_2", + "description": "type: seminar_room\nlevel: 2\nbuilding: o29\nnumber: 2004" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957834, + 48.423323 + ] + }, + "id": "czNjM" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_2", + "description": "type: seminar_room\nlevel: 2\nbuilding: o29\nnumber: 2005" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957764, + 48.423412 + ] + }, + "id": "IyNTc" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_2", + "description": "type: seminar_room\nlevel: 2\nbuilding: o29\nnumber: 2006" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957678, + 48.423377 + ] + }, + "id": "EwODc" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "description": "type: seminar_room\nlevel: 3\nbuilding: o29\nnumber: 3001", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957599, + 48.423238 + ] + }, + "id": "g2NjA" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_3", + "description": "type: seminar_room\nlevel: 3\nbuilding: o29\nnumber: 3002" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957677, + 48.423266 + ] + }, + "id": "U3MTQ" + }, + { + "type": "Feature", + "properties": { + "name": "seminar_room", + "layer": "layer_3", + "description": "type: seminar_room\nlevel: 3\nbuilding: o29\nnumber: 3003" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957757, + 48.423297 + ] + }, + "id": "UwMzg" + }, + { + "type": "Feature", + "properties": { + "description": "type: seminar_room\nlevel: 3\nbuilding: o29\nnumber: 3004", + "name": "seminar_room", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957832, + 48.423322 + ] + }, + "id": "kzMzA" + }, + { + "type": "Feature", + "properties": { + "name": "lecture_hall", + "description": "type: lecture_hall\nlevel: 2\nbuilding: o27\ndescription: H20", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957559, + 48.422785 + ] + }, + "id": "A1NzM" + }, + { + "type": "Feature", + "properties": { + "name": "lecture_hall", + "description": "type: lecture_hall\nlevel: 2\nbuilding: o25\ndescription: H1", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955834, + 48.422465 + ] + }, + "id": "A3NzQ" + }, + { + "type": "Feature", + "properties": { + "name": "lecture_hall", + "layer": "layer_2", + "description": "type: lecture_hall\nlevel: 2\nbuilding: o25\ndescription: H2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955669, + 48.422647 + ] + }, + "id": "IyMTg" + }, + { + "type": "Feature", + "properties": { + "name": "lecture_hall", + "description": "type: lecture_hall\nlevel: 2\nbuilding: o25\ndescription: H4", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955217, + 48.422437 + ] + }, + "id": "EzNTY" + }, + { + "type": "Feature", + "properties": { + "name": "pc_pool", + "description": "type: pc_pool\nlevel: 1\nbuilding: o28\nnumber: 1001", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957823, + 48.423141 + ] + }, + "id": "YzNzE" + }, + { + "type": "Feature", + "properties": { + "name": "pc_pool", + "layer": "layer_3", + "description": "type: pc_pool\nlevel: 3\nbuilding: o29\nnumber: 3005" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957764, + 48.423412 + ] + }, + "id": "UyMzQ" + }, + { + "type": "Feature", + "properties": { + "name": "pc_pool", + "description": "type: pc_pool\nlevel: 3\nbuilding: o29\nnumber: 3006", + "layer": "layer_3" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.95768, + 48.423376 + ] + }, + "id": "M4MDA" + }, + { + "type": "Feature", + "properties": { + "name": "pc_pool", + "description": "type: pc_pool\nlevel: 1\nbuilding: o27\nnumber: 133", + "layer": "layer_1" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.957253, + 48.42271 + ] + }, + "id": "U1MzI" + } + ] +} \ No newline at end of file diff --git a/lib/components/drawer..dart b/lib/components/drawer.dart similarity index 70% rename from lib/components/drawer..dart rename to lib/components/drawer.dart index b4e64cd..d604b9a 100644 --- a/lib/components/drawer..dart +++ b/lib/components/drawer.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:get/get_navigation/get_navigation.dart'; +import 'package:uninav/map.dart'; class MyDrawer extends StatelessWidget { @override @@ -20,9 +23,11 @@ class MyDrawer extends StatelessWidget { ), ), ListTile( - leading: Icon(Icons.home), - title: Text('Home'), + leading: Icon(Icons.map), + title: Text('Map Page'), onTap: () { + Get.back(); // close drawer + Get.toNamed('/map'); // Handle menu item tap }, ), @@ -30,6 +35,8 @@ class MyDrawer extends StatelessWidget { leading: Icon(Icons.settings), title: Text('Settings'), onTap: () { + Get.back(); // close drawer + Get.toNamed('/settings'); // Handle menu item tap }, ), diff --git a/lib/components/hamburger_menu.dart b/lib/components/hamburger_menu.dart new file mode 100644 index 0000000..d69a93a --- /dev/null +++ b/lib/components/hamburger_menu.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +class HamburgerMenu extends StatelessWidget { + const HamburgerMenu({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: Icon(Icons.menu), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ); + } +} diff --git a/lib/components/map_render_level.dart b/lib/components/map_render_level.dart new file mode 100644 index 0000000..6ae3b36 --- /dev/null +++ b/lib/components/map_render_level.dart @@ -0,0 +1,256 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:get/get.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:uninav/controllers/map_controller.dart'; +import 'package:uninav/data/geo/model.dart'; +import 'package:uninav/map.dart'; +import 'package:uninav/util/geomath.dart'; + +List renderLevel(int level) { + return [ + LevelLayer( + filter: (feature) => + feature.level == level && feature.type is LectureHall, + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.orange.withOpacity(0.2), + borderColor: Colors.orange, + isFilled: true, + borderStrokeWidth: 1, + ), + ) + .unwrap(), + markerConstructor: (feature) => Marker( + width: 150, + height: 60, + point: feature.getPoint().unwrap(), + builder: (cx) => Center( + child: Column( + children: [ + Icon( + Icons.class_, + color: Colors.black, + ), + Text('${feature.name}'), + ], + ), + ), + )), + LevelLayer( + filter: (feature) => feature.level == level && feature.type is Room, + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.green.withOpacity(0.2), + borderColor: Colors.green, + isFilled: true, + borderStrokeWidth: 1, + ), + ) + .unwrap(), + ), + LevelLayer( + filter: (feature) => feature.level == level && feature.type is Door, + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => const Icon( + Icons.door_front_door, + color: Colors.brown, + ), + ); + }, + ), + LevelLayer( + filter: (feature) => feature.level == level && feature.type is Toilet, + markerConstructor: (feature) { + final type = (feature.type as Toilet).toilet_type; + IconData icon; + switch (type.toLowerCase()) { + case 'male': + icon = Icons.male; + break; + case 'female': + icon = Icons.female; + break; + case 'handicap': + icon = Icons.wheelchair_pickup; + break; + default: + print("WARN: Toilet didn't have recognizable type! " + "(Level ${feature.level}, Name ${feature.name}, " + "Location: ${feature.getPoint().unwrap()})"); + icon = Icons.wc; + break; + } + + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => Icon( + icon, + color: Colors.purple, + ), + rotateAlignment: Alignment.center, + ); + }, + ), + LevelLayer( + filter: (feature) => + feature.type is Stairs && + (feature.type as Stairs).connects_levels.contains(level), + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => Icon( + Icons.stairs_outlined, + color: Colors.deepPurple.shade300, + ), + ); + }, + ), + LevelLayer( + filter: (feature) => + feature.type is Lift && + (feature.type as Lift).connects_levels.contains(level), + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => const Icon( + Icons.elevator_outlined, + color: Colors.deepPurple, + ), + ); + }, + ), + ]; +} + +class LevelLayer extends StatelessWidget { + final bool Function(Feature)? filter; + final Polygon Function(Feature)? polyConstructor; + final Marker Function(LatLng, String)? polyCenterMarkerConstructor; + final Marker Function(Feature)? markerConstructor; + final int? level; + + const LevelLayer({ + this.level, + this.filter, + this.polyConstructor, + this.polyCenterMarkerConstructor, + this.markerConstructor, + super.key, + }); + + @override + Widget build(BuildContext context) { + final myMapController = Get.find(); + + return Obx(() { + final List filteredPolygons = []; + final List polygonCenterMarkers = []; + final List filteredMarkers = []; + + for (final feature in myMapController.features) { + if (filter == null || filter!(feature)) { + if (feature.isPolygon()) { + if (polyConstructor != null) { + filteredPolygons.add(polyConstructor!(feature)); + } else { + filteredPolygons.add(feature.getPolygon().unwrap()); + } + + // calculate polygon center + final center = + polygonCenterMinmax(feature.getPolygon().unwrap().points); + if (polyCenterMarkerConstructor != null) { + polygonCenterMarkers + .add(polyCenterMarkerConstructor!(center, feature.name)); + } else { + polygonCenterMarkers.add(Marker( + width: 100, + height: 100, + point: center, + builder: (cx) => Center( + child: Text( + feature.name, + style: const TextStyle( + color: Colors.black54, + // backgroundColor: Colors.white, + ), + ), + ), + )); + } + } else if (feature.isPoint()) { + if (markerConstructor != null) { + filteredMarkers.add(markerConstructor!(feature)); + } else { + final point = feature.getPoint().unwrap(); + filteredMarkers.add(Marker( + width: 100, + height: 100, + point: point, + builder: (cx) => Center( + child: Text( + feature.name, + style: const TextStyle( + color: Colors.black54, + // backgroundColor: Colors.white, + ), + ), + ), + )); + } + } + } + } + // print(filteredPolygons.length); + // print(filteredPolygons); + + // print(filteredPolygons[0].points[0]); + // print(myMapController.features.length); + + final List widgets = []; + if (filteredPolygons.isNotEmpty) { + if (polyConstructor != null) { + widgets.add(PolygonLayer(polygons: filteredPolygons)); + } else { + widgets.add(PolygonLayer( + polygons: filteredPolygons + .map((poly) => Polygon( + points: poly.points, + borderColor: Colors.black26, + borderStrokeWidth: 2.0, + )) + .toList())); + } + widgets.add(MarkerLayer( + markers: polygonCenterMarkers, + rotate: true, + )); + } + + if (filteredMarkers.isNotEmpty) { + widgets.add(MarkerLayer(markers: filteredMarkers, rotate: true)); + } + + return Stack(children: widgets); + }); + } +} diff --git a/lib/controllers/map_controller.dart b/lib/controllers/map_controller.dart new file mode 100644 index 0000000..0e133dc --- /dev/null +++ b/lib/controllers/map_controller.dart @@ -0,0 +1,67 @@ +import 'dart:convert'; + +import 'package:anyhow/anyhow.dart'; +import 'package:geojson/geojson.dart'; +import 'package:get/get.dart'; +import 'package:uninav/data/geo/model.dart'; +import 'package:uninav/data/geo/parser.dart'; + +class MyMapController extends GetxController { + // constructor that calls loadgeojson with a default geojson string + final RxList features = [].obs; + final currentLevel = 1.obs; + final levels = [1].obs; + @override + onInit() async { + print("init"); + ever(features, refreshLevels); + super.onInit(); + } + + void refreshLevels(List curFeatures) { + print("refreshLevels"); + final newLevels = [1]; + for (final feature in curFeatures) { + if (feature.level != null && !newLevels.contains(feature.level)) { + newLevels.add(feature.level!); + } + } + newLevels.sort(); + levels.value = newLevels; + } + + Result setLevel(int level) { + // check that level is in features + if (!levels.contains(level)) { + return bail('Level $level is not in features'); + } + + currentLevel.value = level; + return const Ok(()); + } + + Future loadGeoJson(String geoJsonString) async { + try { + // print(geoJsonString); + + final featuresList = []; + + final geojson = GeoJson(); + + await geojson.parse(geoJsonString); + + for (final feature in geojson.features) { + print(feature.properties); + final parsed = + parseFeature(feature.properties ?? {}, feature); + if (parsed case Ok(:final ok)) { + featuresList.add(ok); + } + } + + features.value = featuresList; + } catch (e) { + print('Error parsing GeoJSON: $e'); + } + } +} diff --git a/lib/data/geo/model.dart b/lib/data/geo/model.dart new file mode 100644 index 0000000..261adbd --- /dev/null +++ b/lib/data/geo/model.dart @@ -0,0 +1,70 @@ +import 'package:anyhow/anyhow.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:geojson/geojson.dart'; +import 'package:latlong2/latlong.dart'; + +part 'model.freezed.dart'; + +@freezed +class Feature with _$Feature { + const Feature._(); + + const factory Feature({ + required String name, + required FeatureType type, + String? description, + required dynamic geometry, + int? level, + }) = _Feature; + + bool isPolygon() { + return geometry is GeoJsonFeature; + } + + bool isPoint() { + return geometry is GeoJsonFeature; + } + + Result getPolygon({Polygon Function(List)? constructor}) { + if (isPolygon()) { + constructor ??= (pts) => Polygon( + points: pts, borderColor: Colors.black26, borderStrokeWidth: 2.0); + final polygon = geometry as GeoJsonFeature; + // print(polygon.geometry!.geoSeries[0].geoPoints); + final points = polygon.geometry!.geoSeries[0].geoPoints + .map((e) => LatLng(e.latitude, e.longitude)) + .toList(); + + // print(points); + return Ok(constructor(points)); + } else { + return bail("Feature Geometry is not a Polygon"); + } + } + + Result getPoint() { + if (isPoint()) { + final point = geometry as GeoJsonFeature; + return Ok(LatLng(point.geometry!.geoPoint.latitude, + point.geometry!.geoPoint.longitude)); + } else { + return bail("Feature Geometry is not a Point"); + } + } +} + +@freezed +class FeatureType with _$FeatureType { + // multiple feature types like lecture hall, toliet, ... + const factory FeatureType.building() = Building; + const factory FeatureType.lectureHall() = LectureHall; + const factory FeatureType.room() = Room; + const factory FeatureType.door(List connects) = Door; + const factory FeatureType.toilet(String toilet_type) = Toilet; + const factory FeatureType.stairs(List connects_levels) = Stairs; + const factory FeatureType.lift(List connects_levels) = Lift; + const factory FeatureType.publicTransport( + List bus_lines, List tram_lines) = PublicTransport; +} diff --git a/lib/data/geo/model.freezed.dart b/lib/data/geo/model.freezed.dart new file mode 100644 index 0000000..f414d1a --- /dev/null +++ b/lib/data/geo/model.freezed.dart @@ -0,0 +1,1864 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$Feature { + String get name => throw _privateConstructorUsedError; + FeatureType get type => throw _privateConstructorUsedError; + String? get description => throw _privateConstructorUsedError; + dynamic get geometry => throw _privateConstructorUsedError; + int? get level => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $FeatureCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FeatureCopyWith<$Res> { + factory $FeatureCopyWith(Feature value, $Res Function(Feature) then) = + _$FeatureCopyWithImpl<$Res, Feature>; + @useResult + $Res call( + {String name, + FeatureType type, + String? description, + dynamic geometry, + int? level}); + + $FeatureTypeCopyWith<$Res> get type; +} + +/// @nodoc +class _$FeatureCopyWithImpl<$Res, $Val extends Feature> + implements $FeatureCopyWith<$Res> { + _$FeatureCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? type = null, + Object? description = freezed, + Object? geometry = freezed, + Object? level = freezed, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as FeatureType, + description: freezed == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String?, + geometry: freezed == geometry + ? _value.geometry + : geometry // ignore: cast_nullable_to_non_nullable + as dynamic, + level: freezed == level + ? _value.level + : level // ignore: cast_nullable_to_non_nullable + as int?, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $FeatureTypeCopyWith<$Res> get type { + return $FeatureTypeCopyWith<$Res>(_value.type, (value) { + return _then(_value.copyWith(type: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$FeatureImplCopyWith<$Res> implements $FeatureCopyWith<$Res> { + factory _$$FeatureImplCopyWith( + _$FeatureImpl value, $Res Function(_$FeatureImpl) then) = + __$$FeatureImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String name, + FeatureType type, + String? description, + dynamic geometry, + int? level}); + + @override + $FeatureTypeCopyWith<$Res> get type; +} + +/// @nodoc +class __$$FeatureImplCopyWithImpl<$Res> + extends _$FeatureCopyWithImpl<$Res, _$FeatureImpl> + implements _$$FeatureImplCopyWith<$Res> { + __$$FeatureImplCopyWithImpl( + _$FeatureImpl _value, $Res Function(_$FeatureImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? type = null, + Object? description = freezed, + Object? geometry = freezed, + Object? level = freezed, + }) { + return _then(_$FeatureImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as FeatureType, + description: freezed == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String?, + geometry: freezed == geometry + ? _value.geometry + : geometry // ignore: cast_nullable_to_non_nullable + as dynamic, + level: freezed == level + ? _value.level + : level // ignore: cast_nullable_to_non_nullable + as int?, + )); + } +} + +/// @nodoc + +class _$FeatureImpl extends _Feature { + const _$FeatureImpl( + {required this.name, + required this.type, + this.description, + required this.geometry, + this.level}) + : super._(); + + @override + final String name; + @override + final FeatureType type; + @override + final String? description; + @override + final dynamic geometry; + @override + final int? level; + + @override + String toString() { + return 'Feature(name: $name, type: $type, description: $description, geometry: $geometry, level: $level)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FeatureImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.type, type) || other.type == type) && + (identical(other.description, description) || + other.description == description) && + const DeepCollectionEquality().equals(other.geometry, geometry) && + (identical(other.level, level) || other.level == level)); + } + + @override + int get hashCode => Object.hash(runtimeType, name, type, description, + const DeepCollectionEquality().hash(geometry), level); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$FeatureImplCopyWith<_$FeatureImpl> get copyWith => + __$$FeatureImplCopyWithImpl<_$FeatureImpl>(this, _$identity); +} + +abstract class _Feature extends Feature { + const factory _Feature( + {required final String name, + required final FeatureType type, + final String? description, + required final dynamic geometry, + final int? level}) = _$FeatureImpl; + const _Feature._() : super._(); + + @override + String get name; + @override + FeatureType get type; + @override + String? get description; + @override + dynamic get geometry; + @override + int? get level; + @override + @JsonKey(ignore: true) + _$$FeatureImplCopyWith<_$FeatureImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$FeatureType { + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FeatureTypeCopyWith<$Res> { + factory $FeatureTypeCopyWith( + FeatureType value, $Res Function(FeatureType) then) = + _$FeatureTypeCopyWithImpl<$Res, FeatureType>; +} + +/// @nodoc +class _$FeatureTypeCopyWithImpl<$Res, $Val extends FeatureType> + implements $FeatureTypeCopyWith<$Res> { + _$FeatureTypeCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$BuildingImplCopyWith<$Res> { + factory _$$BuildingImplCopyWith( + _$BuildingImpl value, $Res Function(_$BuildingImpl) then) = + __$$BuildingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$BuildingImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$BuildingImpl> + implements _$$BuildingImplCopyWith<$Res> { + __$$BuildingImplCopyWithImpl( + _$BuildingImpl _value, $Res Function(_$BuildingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$BuildingImpl implements Building { + const _$BuildingImpl(); + + @override + String toString() { + return 'FeatureType.building()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$BuildingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return building(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return building?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (building != null) { + return building(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return building(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return building?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (building != null) { + return building(this); + } + return orElse(); + } +} + +abstract class Building implements FeatureType { + const factory Building() = _$BuildingImpl; +} + +/// @nodoc +abstract class _$$LectureHallImplCopyWith<$Res> { + factory _$$LectureHallImplCopyWith( + _$LectureHallImpl value, $Res Function(_$LectureHallImpl) then) = + __$$LectureHallImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$LectureHallImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$LectureHallImpl> + implements _$$LectureHallImplCopyWith<$Res> { + __$$LectureHallImplCopyWithImpl( + _$LectureHallImpl _value, $Res Function(_$LectureHallImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$LectureHallImpl implements LectureHall { + const _$LectureHallImpl(); + + @override + String toString() { + return 'FeatureType.lectureHall()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$LectureHallImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return lectureHall(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return lectureHall?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (lectureHall != null) { + return lectureHall(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return lectureHall(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return lectureHall?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (lectureHall != null) { + return lectureHall(this); + } + return orElse(); + } +} + +abstract class LectureHall implements FeatureType { + const factory LectureHall() = _$LectureHallImpl; +} + +/// @nodoc +abstract class _$$RoomImplCopyWith<$Res> { + factory _$$RoomImplCopyWith( + _$RoomImpl value, $Res Function(_$RoomImpl) then) = + __$$RoomImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$RoomImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$RoomImpl> + implements _$$RoomImplCopyWith<$Res> { + __$$RoomImplCopyWithImpl(_$RoomImpl _value, $Res Function(_$RoomImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$RoomImpl implements Room { + const _$RoomImpl(); + + @override + String toString() { + return 'FeatureType.room()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$RoomImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return room(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return room?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (room != null) { + return room(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return room(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return room?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (room != null) { + return room(this); + } + return orElse(); + } +} + +abstract class Room implements FeatureType { + const factory Room() = _$RoomImpl; +} + +/// @nodoc +abstract class _$$DoorImplCopyWith<$Res> { + factory _$$DoorImplCopyWith( + _$DoorImpl value, $Res Function(_$DoorImpl) then) = + __$$DoorImplCopyWithImpl<$Res>; + @useResult + $Res call({List connects}); +} + +/// @nodoc +class __$$DoorImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$DoorImpl> + implements _$$DoorImplCopyWith<$Res> { + __$$DoorImplCopyWithImpl(_$DoorImpl _value, $Res Function(_$DoorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? connects = null, + }) { + return _then(_$DoorImpl( + null == connects + ? _value._connects + : connects // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$DoorImpl implements Door { + const _$DoorImpl(final List connects) : _connects = connects; + + final List _connects; + @override + List get connects { + if (_connects is EqualUnmodifiableListView) return _connects; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_connects); + } + + @override + String toString() { + return 'FeatureType.door(connects: $connects)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DoorImpl && + const DeepCollectionEquality().equals(other._connects, _connects)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_connects)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DoorImplCopyWith<_$DoorImpl> get copyWith => + __$$DoorImplCopyWithImpl<_$DoorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return door(connects); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return door?.call(connects); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (door != null) { + return door(connects); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return door(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return door?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (door != null) { + return door(this); + } + return orElse(); + } +} + +abstract class Door implements FeatureType { + const factory Door(final List connects) = _$DoorImpl; + + List get connects; + @JsonKey(ignore: true) + _$$DoorImplCopyWith<_$DoorImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ToiletImplCopyWith<$Res> { + factory _$$ToiletImplCopyWith( + _$ToiletImpl value, $Res Function(_$ToiletImpl) then) = + __$$ToiletImplCopyWithImpl<$Res>; + @useResult + $Res call({String toilet_type}); +} + +/// @nodoc +class __$$ToiletImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$ToiletImpl> + implements _$$ToiletImplCopyWith<$Res> { + __$$ToiletImplCopyWithImpl( + _$ToiletImpl _value, $Res Function(_$ToiletImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? toilet_type = null, + }) { + return _then(_$ToiletImpl( + null == toilet_type + ? _value.toilet_type + : toilet_type // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$ToiletImpl implements Toilet { + const _$ToiletImpl(this.toilet_type); + + @override + final String toilet_type; + + @override + String toString() { + return 'FeatureType.toilet(toilet_type: $toilet_type)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ToiletImpl && + (identical(other.toilet_type, toilet_type) || + other.toilet_type == toilet_type)); + } + + @override + int get hashCode => Object.hash(runtimeType, toilet_type); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ToiletImplCopyWith<_$ToiletImpl> get copyWith => + __$$ToiletImplCopyWithImpl<_$ToiletImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return toilet(toilet_type); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return toilet?.call(toilet_type); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (toilet != null) { + return toilet(toilet_type); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return toilet(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return toilet?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (toilet != null) { + return toilet(this); + } + return orElse(); + } +} + +abstract class Toilet implements FeatureType { + const factory Toilet(final String toilet_type) = _$ToiletImpl; + + String get toilet_type; + @JsonKey(ignore: true) + _$$ToiletImplCopyWith<_$ToiletImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$EntranceImplCopyWith<$Res> { + factory _$$EntranceImplCopyWith( + _$EntranceImpl value, $Res Function(_$EntranceImpl) then) = + __$$EntranceImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$EntranceImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$EntranceImpl> + implements _$$EntranceImplCopyWith<$Res> { + __$$EntranceImplCopyWithImpl( + _$EntranceImpl _value, $Res Function(_$EntranceImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$EntranceImpl implements Entrance { + const _$EntranceImpl(); + + @override + String toString() { + return 'FeatureType.entrance()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$EntranceImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return entrance(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return entrance?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (entrance != null) { + return entrance(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return entrance(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return entrance?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (entrance != null) { + return entrance(this); + } + return orElse(); + } +} + +abstract class Entrance implements FeatureType { + const factory Entrance() = _$EntranceImpl; +} + +/// @nodoc +abstract class _$$StairsImplCopyWith<$Res> { + factory _$$StairsImplCopyWith( + _$StairsImpl value, $Res Function(_$StairsImpl) then) = + __$$StairsImplCopyWithImpl<$Res>; + @useResult + $Res call({List connects_levels}); +} + +/// @nodoc +class __$$StairsImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$StairsImpl> + implements _$$StairsImplCopyWith<$Res> { + __$$StairsImplCopyWithImpl( + _$StairsImpl _value, $Res Function(_$StairsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? connects_levels = null, + }) { + return _then(_$StairsImpl( + null == connects_levels + ? _value._connects_levels + : connects_levels // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$StairsImpl implements Stairs { + const _$StairsImpl(final List connects_levels) + : _connects_levels = connects_levels; + + final List _connects_levels; + @override + List get connects_levels { + if (_connects_levels is EqualUnmodifiableListView) return _connects_levels; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_connects_levels); + } + + @override + String toString() { + return 'FeatureType.stairs(connects_levels: $connects_levels)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$StairsImpl && + const DeepCollectionEquality() + .equals(other._connects_levels, _connects_levels)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_connects_levels)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$StairsImplCopyWith<_$StairsImpl> get copyWith => + __$$StairsImplCopyWithImpl<_$StairsImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return stairs(connects_levels); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return stairs?.call(connects_levels); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (stairs != null) { + return stairs(connects_levels); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return stairs(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return stairs?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (stairs != null) { + return stairs(this); + } + return orElse(); + } +} + +abstract class Stairs implements FeatureType { + const factory Stairs(final List connects_levels) = _$StairsImpl; + + List get connects_levels; + @JsonKey(ignore: true) + _$$StairsImplCopyWith<_$StairsImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$LiftImplCopyWith<$Res> { + factory _$$LiftImplCopyWith( + _$LiftImpl value, $Res Function(_$LiftImpl) then) = + __$$LiftImplCopyWithImpl<$Res>; + @useResult + $Res call({List connects_levels}); +} + +/// @nodoc +class __$$LiftImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$LiftImpl> + implements _$$LiftImplCopyWith<$Res> { + __$$LiftImplCopyWithImpl(_$LiftImpl _value, $Res Function(_$LiftImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? connects_levels = null, + }) { + return _then(_$LiftImpl( + null == connects_levels + ? _value._connects_levels + : connects_levels // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$LiftImpl implements Lift { + const _$LiftImpl(final List connects_levels) + : _connects_levels = connects_levels; + + final List _connects_levels; + @override + List get connects_levels { + if (_connects_levels is EqualUnmodifiableListView) return _connects_levels; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_connects_levels); + } + + @override + String toString() { + return 'FeatureType.lift(connects_levels: $connects_levels)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LiftImpl && + const DeepCollectionEquality() + .equals(other._connects_levels, _connects_levels)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_connects_levels)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LiftImplCopyWith<_$LiftImpl> get copyWith => + __$$LiftImplCopyWithImpl<_$LiftImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return lift(connects_levels); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return lift?.call(connects_levels); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (lift != null) { + return lift(connects_levels); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return lift(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return lift?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (lift != null) { + return lift(this); + } + return orElse(); + } +} + +abstract class Lift implements FeatureType { + const factory Lift(final List connects_levels) = _$LiftImpl; + + List get connects_levels; + @JsonKey(ignore: true) + _$$LiftImplCopyWith<_$LiftImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$PublicTransportImplCopyWith<$Res> { + factory _$$PublicTransportImplCopyWith(_$PublicTransportImpl value, + $Res Function(_$PublicTransportImpl) then) = + __$$PublicTransportImplCopyWithImpl<$Res>; + @useResult + $Res call({List bus_lines, List tram_lines}); +} + +/// @nodoc +class __$$PublicTransportImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$PublicTransportImpl> + implements _$$PublicTransportImplCopyWith<$Res> { + __$$PublicTransportImplCopyWithImpl( + _$PublicTransportImpl _value, $Res Function(_$PublicTransportImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? bus_lines = null, + Object? tram_lines = null, + }) { + return _then(_$PublicTransportImpl( + null == bus_lines + ? _value._bus_lines + : bus_lines // ignore: cast_nullable_to_non_nullable + as List, + null == tram_lines + ? _value._tram_lines + : tram_lines // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$PublicTransportImpl implements PublicTransport { + const _$PublicTransportImpl( + final List bus_lines, final List tram_lines) + : _bus_lines = bus_lines, + _tram_lines = tram_lines; + + final List _bus_lines; + @override + List get bus_lines { + if (_bus_lines is EqualUnmodifiableListView) return _bus_lines; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_bus_lines); + } + + final List _tram_lines; + @override + List get tram_lines { + if (_tram_lines is EqualUnmodifiableListView) return _tram_lines; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_tram_lines); + } + + @override + String toString() { + return 'FeatureType.publicTransport(bus_lines: $bus_lines, tram_lines: $tram_lines)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PublicTransportImpl && + const DeepCollectionEquality() + .equals(other._bus_lines, _bus_lines) && + const DeepCollectionEquality() + .equals(other._tram_lines, _tram_lines)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_bus_lines), + const DeepCollectionEquality().hash(_tram_lines)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PublicTransportImplCopyWith<_$PublicTransportImpl> get copyWith => + __$$PublicTransportImplCopyWithImpl<_$PublicTransportImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function() room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function() entrance, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + }) { + return publicTransport(bus_lines, tram_lines); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function()? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function()? entrance, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + }) { + return publicTransport?.call(bus_lines, tram_lines); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function()? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function()? entrance, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + required TResult orElse(), + }) { + if (publicTransport != null) { + return publicTransport(bus_lines, tram_lines); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Entrance value) entrance, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(PublicTransport value) publicTransport, + }) { + return publicTransport(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Entrance value)? entrance, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(PublicTransport value)? publicTransport, + }) { + return publicTransport?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Entrance value)? entrance, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(PublicTransport value)? publicTransport, + required TResult orElse(), + }) { + if (publicTransport != null) { + return publicTransport(this); + } + return orElse(); + } +} + +abstract class PublicTransport implements FeatureType { + const factory PublicTransport( + final List bus_lines, final List tram_lines) = + _$PublicTransportImpl; + + List get bus_lines; + List get tram_lines; + @JsonKey(ignore: true) + _$$PublicTransportImplCopyWith<_$PublicTransportImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/data/geo/parser.dart b/lib/data/geo/parser.dart new file mode 100644 index 0000000..9e5b716 --- /dev/null +++ b/lib/data/geo/parser.dart @@ -0,0 +1,142 @@ +import 'package:anyhow/anyhow.dart'; +import 'package:geojson/geojson.dart'; +import 'package:uninav/data/geo/model.dart'; +import 'package:yaml/yaml.dart'; + +Result parseFeature( + Map properties, dynamic geometry) { + final name = properties['name'] as String?; + final description_yaml = properties['description'] as String? ?? ''; + final layer = properties['layer'] as String?; + + int? level; + + // check if layer key contains a digit using \d+ regex + + final layerNum = RegExp(r'\d+').firstMatch(layer ?? ''); + if (layerNum != null) { + level = int.parse(layerNum.group(0)!); + } + + // try parse yaml + if (description_yaml == null) { + print("warn: Description key is missing for feature $name"); + } + + if (layer == null) { + return bail("Layer key \'layer\' is missing for feature $name"); + } + dynamic yaml; + try { + yaml = loadYaml(description_yaml); + } on YamlException catch (e) { + return bail("Couldn't parse YAML in description for feature $name: $e"); + } + + yaml = yaml as YamlMap? ?? {}; + final description = yaml['desription'] as String?; + + print("yaml: $yaml"); + + var raw_type = yaml['type'] as String?; + if (raw_type == null && layer?.toLowerCase() == 'buildings') { + raw_type = 'building'; + } + + if (raw_type == null) { + return bail("Type key \'type\' is missing for feature $name"); + } + + FeatureType type; + + try { + switch (raw_type) { + case 'building': + type = FeatureType.building(); + case 'lift': + final list = getYamlList(yaml, 'connects_levels') + .expect("Couldn't parse 'connects_levels' for feature $name"); + type = FeatureType.lift(list); + break; + case 'stairs': + final list = getYamlList(yaml, 'connects_levels') + .expect("Couldn't parse 'connects_levels' for feature $name"); + type = FeatureType.stairs(list); + break; + case 'lecture_hall': + type = FeatureType.lectureHall(); + break; + case 'room': + type = FeatureType.room(); + break; + case 'door': + final list = getYamlList(yaml, 'connects') + .expect("Couldn't parse 'connects' for feature $name"); + type = FeatureType.door(list); + break; + case 'toilet': + final toiletType = getYamlKey(yaml, 'toilet_type') + .expect("Couldn't parse 'toilet_type' for feature $name"); + type = FeatureType.toilet(toiletType); + break; + case 'public_transport': + final busLines = getYamlList(yaml, 'bus_lines') + .expect("Couldn't parse 'bus_lines' for feature $name"); + final tramLines = getYamlList(yaml, 'tram_lines') + .expect("Couldn't parse 'tram_lines' for feature $name"); + + type = FeatureType.publicTransport( + stringifyList(busLines) + .expect('Couldn\'t stringify \'bus_lines\' for feature $name'), + stringifyList(tramLines) + .expect('Couldn\'t stringify \'tram_lines\' for feature $name'), + ); + break; + default: + return bail("Unknown feature type $raw_type for feature $name"); + } + } catch (e) { + return bail("Failed to parse feature type for feature $name: $e"); + } + + return Ok(Feature( + name: name ?? 'Unknown', + type: type, + description: description, + geometry: geometry, + level: level, + )); +} + +Result> stringifyList(List tramLines) { + try { + return Ok(tramLines.map((e) => e.toString()).toList()); + } catch (e) { + return bail("Couldn't stringify list: $e"); + } +} + +Result> getYamlList(YamlMap yaml, String key) { + try { + print('yaml is ${yaml[key]}'); + final val = (yaml[key] as YamlList?); + if (val == null) { + return bail("Key $key is missing in yaml"); + } + return Ok(val.cast()); + } catch (e) { + return bail("Failed to parse yaml key $key as ${T.toString()}: $e"); + } +} + +Result getYamlKey(YamlMap yaml, String key) { + try { + final val = yaml[key] as T?; + if (val == null) { + return bail("Key $key is missing in yaml"); + } + return Ok(val); + } catch (e) { + return bail("Failed to parse yaml key $key as ${T.toString()}: $e"); + } +} diff --git a/lib/main.dart b/lib/main.dart index 1107328..ac19f59 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:get/get_navigation/src/root/get_material_app.dart'; +import 'package:get/get.dart'; +import 'package:uninav/controllers/map_controller.dart'; import 'package:uninav/map.dart'; +import 'package:uninav/settings.dart'; void main() { + Get.put(MyMapController()); runApp(const MyApp()); } @@ -33,7 +36,11 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), - home: MapPage(), + initialRoute: '/map', + getPages: [ + GetPage(name: '/map', page: () => const MapPage()), + GetPage(name: '/settings', page: () => const SettingsPage()), + ], ); } } diff --git a/lib/map.dart b/lib/map.dart index 4c14a07..01598c2 100644 --- a/lib/map.dart +++ b/lib/map.dart @@ -1,9 +1,16 @@ import 'package:anim_search_bar/anim_search_bar.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/plugin_api.dart'; +import 'package:get/get.dart'; import 'package:latlong2/latlong.dart'; -import 'package:uninav/components/drawer..dart'; +import 'package:rust_core/slice.dart'; +import 'package:uninav/components/drawer.dart'; +import 'package:uninav/components/hamburger_menu.dart'; +import 'package:uninav/controllers/map_controller.dart'; +import 'package:uninav/data/geo/model.dart'; +import 'package:uninav/util/geomath.dart'; import 'package:url_launcher/url_launcher.dart'; class MapPage extends StatelessWidget { @@ -12,18 +19,10 @@ class MapPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( + drawer: MyDrawer(), appBar: AppBar( title: const Text('Map'), - leading: Builder( - builder: (context) { - return IconButton( - icon: Icon(Icons.menu), - onPressed: () { - Scaffold.of(context).openDrawer(); - }, - ); - } - ), + leading: HamburgerMenu(), // right side expanding search bar widget actions: [ @@ -39,29 +38,365 @@ class MapPage extends StatelessWidget { }, ), ]), - drawer: MyDrawer(), - body: FlutterMap( - mapController: MapController(), - options: MapOptions( - center: LatLng(51.5, -0.09), - zoom: 13.0, - ), + floatingActionButton: FloatingActionButton( + onPressed: () async { + // Add onPressed logic here + await Get.find().loadGeoJson( + await rootBundle.loadString('assets/geo/uulm_beta.geojson')); + }, + child: const Icon(Icons.add), + ), + body: Stack( children: [ - TileLayer( - urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", - subdomains: const ['a', 'b', 'c'], + FlutterMap( + mapController: MapController(), + options: MapOptions( + center: LatLng(48.422766, 9.9564), + zoom: 16.0, + // camera constraints + maxZoom: 19, + ), + children: [ + TileLayer( + urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + maxZoom: 19, + ), + + // buildings + LevelLayer( + filter: (feature) => feature.type is Building, + ), + + // public transport + LevelLayer( + filter: (feature) => + feature.level == null && feature.type is PublicTransport, + polyCenterMarkerConstructor: (center, name) => Marker( + width: 100, + height: 100, + point: center, + builder: (cx) => const Center( + child: Icon( + Icons.train, + color: Colors.black, + ), + ), + ), + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.green.withOpacity(0.2), + borderColor: Colors.green, + isFilled: true, + borderStrokeWidth: 1, + )) + .unwrap(), + ), + + // current level + Obx( + () => Stack( + children: renderLevel( + Get.find().currentLevel.value), + ), + ) + + // RichAttributionWidget(attributions: [ + // TextSourceAttribution( + // 'OpenStreetMap contributors', + // onTap: () => + // launchUrl(Uri.parse('https://openstreetmap.org/copyright')), + // ) + // ]), + ], ), - RichAttributionWidget(attributions: [ - TextSourceAttribution( - 'OpenStreetMap contributors', - onTap: () => - launchUrl(Uri.parse('https://openstreetmap.org/copyright')), - ) - ]) - // PolygonLayer(polygons: myGeoJson.polygons), - // PolylineLayer(polylines: myGeoJson.polylines), - // MarkerLayer(markers: myGeoJson.markers) + Positioned( + left: 16, + bottom: 16, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Colors.grey, + width: 1, + ), + ), + padding: + const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Obx( + () => DropdownButton( + value: Get.find().currentLevel.value, + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface), + dropdownColor: Theme.of(context).colorScheme.surface, + onChanged: (int? newValue) { + if (newValue != null) { + Get.find().setLevel(newValue); + } + // Handle dropdown value change + }, + items: Get.find() + .levels + .map>((int value) { + return DropdownMenuItem( + value: value, + child: Text("Level $value"), + ); + }).toList(), + ), + ), + )), ], )); } } + +List renderLevel(int level) { + return [ + LevelLayer( + filter: (feature) => + feature.level == level && feature.type is LectureHall, + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.orange.withOpacity(0.2), + borderColor: Colors.orange, + isFilled: true, + borderStrokeWidth: 1, + ), + ) + .unwrap(), + markerConstructor: (feature) => Marker( + width: 150, + height: 60, + point: feature.getPoint().unwrap(), + builder: (cx) => Center( + child: Column( + children: [ + Icon( + Icons.class_, + color: Colors.black, + ), + Text('${feature.name}'), + ], + ), + ), + )), + LevelLayer( + filter: (feature) => feature.level == level && feature.type is Room, + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.green.withOpacity(0.2), + borderColor: Colors.green, + isFilled: true, + borderStrokeWidth: 1, + ), + ) + .unwrap(), + ), + LevelLayer( + filter: (feature) => feature.level == level && feature.type is Door, + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => const Icon( + Icons.door_front_door, + color: Colors.brown, + ), + ); + }, + ), + LevelLayer( + filter: (feature) => feature.level == level && feature.type is Toilet, + markerConstructor: (feature) { + final type = (feature.type as Toilet).toilet_type; + IconData icon; + switch (type.toLowerCase()) { + case 'male': + icon = Icons.male; + break; + case 'female': + icon = Icons.female; + break; + case 'handicap': + icon = Icons.wheelchair_pickup; + break; + default: + print("WARN: Toilet didn't have recognizable type! " + "(Level ${feature.level}, Name ${feature.name}, " + "Location: ${feature.getPoint().unwrap()})"); + icon = Icons.wc; + break; + } + + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => Icon( + icon, + color: Colors.purple, + ), + rotateAlignment: Alignment.center, + ); + }, + ), + LevelLayer( + filter: (feature) => + feature.type is Stairs && + (feature.type as Stairs).connects_levels.contains(level), + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => Icon( + Icons.stairs_outlined, + color: Colors.deepPurple.shade300, + ), + ); + }, + ), + LevelLayer( + filter: (feature) => + feature.type is Lift && + (feature.type as Lift).connects_levels.contains(level), + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 20, + height: 20, + point: point, + builder: (ctx) => const Icon( + Icons.elevator_outlined, + color: Colors.deepPurple, + ), + ); + }, + ), + ]; +} + +class LevelLayer extends StatelessWidget { + final bool Function(Feature)? filter; + final Polygon Function(Feature)? polyConstructor; + final Marker Function(LatLng, String)? polyCenterMarkerConstructor; + final Marker Function(Feature)? markerConstructor; + final int? level; + + const LevelLayer({ + this.level, + this.filter, + this.polyConstructor, + this.polyCenterMarkerConstructor, + this.markerConstructor, + super.key, + }); + + @override + Widget build(BuildContext context) { + final myMapController = Get.find(); + + return Obx(() { + final List filteredPolygons = []; + final List polygonCenterMarkers = []; + final List filteredMarkers = []; + + for (final feature in myMapController.features) { + if (filter == null || filter!(feature)) { + if (feature.isPolygon()) { + if (polyConstructor != null) { + filteredPolygons.add(polyConstructor!(feature)); + } else { + filteredPolygons.add(feature.getPolygon().unwrap()); + } + + // calculate polygon center + final center = + polygonCenterMinmax(feature.getPolygon().unwrap().points); + if (polyCenterMarkerConstructor != null) { + polygonCenterMarkers + .add(polyCenterMarkerConstructor!(center, feature.name)); + } else { + polygonCenterMarkers.add(Marker( + width: 100, + height: 100, + point: center, + builder: (cx) => Center( + child: Text( + feature.name, + style: const TextStyle( + color: Colors.black54, + // backgroundColor: Colors.white, + ), + ), + ), + )); + } + } else if (feature.isPoint()) { + if (markerConstructor != null) { + filteredMarkers.add(markerConstructor!(feature)); + } else { + final point = feature.getPoint().unwrap(); + filteredMarkers.add(Marker( + width: 100, + height: 100, + point: point, + builder: (cx) => Center( + child: Text( + feature.name, + style: const TextStyle( + color: Colors.black54, + // backgroundColor: Colors.white, + ), + ), + ), + )); + } + } + } + } + // print(filteredPolygons.length); + // print(filteredPolygons); + + // print(filteredPolygons[0].points[0]); + // print(myMapController.features.length); + + final List widgets = []; + if (filteredPolygons.isNotEmpty) { + if (polyConstructor != null) { + widgets.add(PolygonLayer(polygons: filteredPolygons)); + } else { + widgets.add(PolygonLayer( + polygons: filteredPolygons + .map((poly) => Polygon( + points: poly.points, + borderColor: Colors.black26, + borderStrokeWidth: 2.0, + )) + .toList())); + } + widgets.add(MarkerLayer( + markers: polygonCenterMarkers, + rotate: true, + )); + } + + if (filteredMarkers.isNotEmpty) { + widgets.add(MarkerLayer(markers: filteredMarkers, rotate: true)); + } + + return Stack(children: widgets); + }); + } +} diff --git a/lib/settings copy.dart b/lib/settings copy.dart new file mode 100644 index 0000000..1ebd1ea --- /dev/null +++ b/lib/settings copy.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:uninav/components/drawer.dart'; +import 'package:uninav/components/hamburger_menu.dart'; + +class SettingsPage extends StatelessWidget { + const SettingsPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Settings'), + leading: HamburgerMenu(), + ), + drawer: MyDrawer(), + body: const Center( + child: Text('TODO'), + ), + ); + } +} diff --git a/lib/settings.dart b/lib/settings.dart new file mode 100644 index 0000000..1ebd1ea --- /dev/null +++ b/lib/settings.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:uninav/components/drawer.dart'; +import 'package:uninav/components/hamburger_menu.dart'; + +class SettingsPage extends StatelessWidget { + const SettingsPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Settings'), + leading: HamburgerMenu(), + ), + drawer: MyDrawer(), + body: const Center( + child: Text('TODO'), + ), + ); + } +} diff --git a/lib/util/geomath.dart b/lib/util/geomath.dart new file mode 100644 index 0000000..29cad41 --- /dev/null +++ b/lib/util/geomath.dart @@ -0,0 +1,37 @@ +import 'dart:math'; + +import 'package:latlong2/latlong.dart'; + +LatLng polygonCenterMinmax(List polygon) { + double minLat = double.infinity; + double maxLat = double.negativeInfinity; + double minLng = double.infinity; + double maxLng = double.negativeInfinity; + + for (LatLng point in polygon) { + minLat = min(minLat, point.latitude); + maxLat = max(maxLat, point.latitude); + minLng = min(minLng, point.longitude); + maxLng = max(maxLng, point.longitude); + } + + double centerLat = (minLat + maxLat) / 2; + double centerLng = (minLng + maxLng) / 2; + + return LatLng(centerLat, centerLng); +} + +LatLng polygonCenterAvg(List polygon) { + double sumLat = 0; + double sumLng = 0; + + for (LatLng point in polygon) { + sumLat += point.latitude; + sumLng += point.longitude; + } + + double centerLat = sumLat / polygon.length; + double centerLng = sumLng / polygon.length; + + return LatLng(centerLat, centerLng); +} diff --git a/pubspec.lock b/pubspec.lock index 372cc3b..3e67040 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,22 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" anim_search_bar: dependency: "direct main" description: @@ -9,6 +25,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + anyhow: + dependency: "direct main" + description: + name: anyhow + sha256: "8fcd8a16ab1dadcae0d77b880c4cda85367876ef9da6ca7fd68ce6ce51679bbe" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" async: dependency: transitive description: @@ -25,6 +57,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + url: "https://pub.dev" + source: hosted + version: "2.4.9" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + url: "https://pub.dev" + source: hosted + version: "7.3.0" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" characters: dependency: transitive description: @@ -33,6 +129,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" clock: dependency: transitive description: @@ -41,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" collection: dependency: transitive description: @@ -49,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" crypto: dependency: transitive description: @@ -65,6 +185,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" extra_pedantic: dependency: transitive description: @@ -81,6 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" fixnum: dependency: transitive description: @@ -120,6 +256,30 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: a434911f643466d78462625df76fd9eb13e57348ff43fe1f77bbe909522c67a1 + url: "https://pub.dev" + source: hosted + version: "2.5.2" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" geodesy: dependency: transitive description: @@ -152,6 +312,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.6.6" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" http: dependency: transitive description: @@ -160,6 +336,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.6" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" http_parser: dependency: transitive description: @@ -176,6 +360,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.19.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" iso: dependency: transitive description: @@ -184,6 +376,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + url: "https://pub.dev" + source: hosted + version: "6.7.1" latlong2: dependency: "direct main" description: @@ -232,6 +448,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" matcher: dependency: transitive description: @@ -264,6 +488,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -296,6 +536,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" proj4dart: dependency: transitive description: @@ -304,6 +552,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + rust_core: + dependency: "direct main" + description: + name: rust_core + sha256: "3b61f6e32dc8af47dc8fa27b662c5ace9db713fd4dd5e9fd77400e6577d51fb8" + url: "https://pub.dev" + source: hosted + version: "0.5.3" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" sky_engine: dependency: transitive description: flutter @@ -317,6 +605,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" source_span: dependency: transitive description: @@ -349,6 +653,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -381,6 +693,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" tuple: dependency: transitive description: @@ -493,6 +813,14 @@ packages: url: "https://pub.dev" source: hosted version: "13.0.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 077abfa..977f972 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,10 +39,14 @@ dependencies: yaml: ^3.1.2 surrealdb: ^0.8.0 geojson: ^1.0.0 - flutter_map: ^4.0.0 - latlong2: ^0.8.2 + flutter_map: 7.0.0-dev.1 + # latlong2: ^0.9.0 url_launcher: ^6.2.6 anim_search_bar: ^2.0.3 + freezed_annotation: ^2.4.1 + json_annotation: ^4.8.1 + rust_core: ^0.5.3 + anyhow: ^1.3.0 dev_dependencies: flutter_test: @@ -54,6 +58,9 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^3.0.0 + build_runner: ^2.4.9 + freezed: ^2.5.2 + json_serializable: ^6.7.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -67,7 +74,9 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: + assets: + # - assets/geo/ + - assets/geo/uulm_beta.geojson # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg diff --git a/test/geojson_tests.dart b/test/geojson_tests.dart new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/test/geojson_tests.dart @@ -0,0 +1 @@ +