diff --git a/assets/geo/uulm_beta.geojson b/assets/geo/uulm_beta.geojson index a72e5fa..2a9def8 100644 --- a/assets/geo/uulm_beta.geojson +++ b/assets/geo/uulm_beta.geojson @@ -97,7 +97,8 @@ "type": "Feature", "properties": { "name": "O27", - "layer": "buildings" + "layer": "buildings", + "description": "connections: [o26, o28]" }, "geometry": { "type": "Polygon", @@ -294,7 +295,8 @@ "type": "Feature", "properties": { "name": "O28", - "layer": "buildings" + "layer": "buildings", + "description": "connections: [o27, o29]" }, "geometry": { "type": "Polygon", @@ -345,7 +347,8 @@ "type": "Feature", "properties": { "name": "O29", - "layer": "buildings" + "layer": "buildings", + "description": "connections: o28" }, "geometry": { "type": "Polygon", @@ -380,7 +383,8 @@ "type": "Feature", "properties": { "name": "O25", - "layer": "buildings" + "layer": "buildings", + "description": "connections: [o26, mensa]" }, "geometry": { "type": "Polygon", @@ -571,6 +575,146 @@ }, "id": "YzMDM" }, + { + "type": "Feature", + "properties": { + "name": "Mensa", + "layer": "buildings", + "description": "connections: o25\ndescription: food is served here\n" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 9.955229, + 48.422134 + ], + [ + 9.954885, + 48.422012 + ], + [ + 9.955021, + 48.42184 + ], + [ + 9.954997, + 48.421832 + ], + [ + 9.955088, + 48.421721 + ], + [ + 9.954936, + 48.421664 + ], + [ + 9.955182, + 48.421519 + ], + [ + 9.955235, + 48.421554 + ], + [ + 9.955456, + 48.421546 + ], + [ + 9.955441, + 48.421581 + ], + [ + 9.95562, + 48.421663 + ], + [ + 9.955571, + 48.421711 + ], + [ + 9.95561, + 48.42182 + ], + [ + 9.955515, + 48.421815 + ], + [ + 9.955567, + 48.421939 + ], + [ + 9.955548, + 48.421943 + ], + [ + 9.955587, + 48.422031 + ], + [ + 9.955931, + 48.422158 + ], + [ + 9.955878, + 48.422224 + ], + [ + 9.955548, + 48.422101 + ], + [ + 9.955539, + 48.422111 + ], + [ + 9.955502, + 48.422097 + ], + [ + 9.955507, + 48.422085 + ], + [ + 9.955441, + 48.422062 + ], + [ + 9.955428, + 48.42208 + ], + [ + 9.955402, + 48.422088 + ], + [ + 9.955409, + 48.422051 + ], + [ + 9.955358, + 48.422034 + ], + [ + 9.955306, + 48.422093 + ], + [ + 9.955278, + 48.422081 + ], + [ + 9.955229, + 48.422134 + ] + ] + ] + }, + "id": "AyNjM" + }, { "type": "Feature", "properties": { @@ -1130,7 +1274,7 @@ "type": "Feature", "properties": { "description": "type: public_transport\nbus_lines: [5, 8, 13, E, N3]\ntram_lines: [2]", - "name": "public_transport", + "name": "Universität Süd", "layer": "layer_public_transport" }, "geometry": { @@ -1174,7 +1318,7 @@ "type": "Feature", "properties": { "description": "type: public_transport\nbus_lines: [5, 13, E, N3]\ntram_lines: [2]", - "name": "public_transport", + "name": "Botanischer Garten", "layer": "layer_public_transport" }, "geometry": { diff --git a/lib/components/colorful_chips.dart b/lib/components/colorful_chips.dart new file mode 100644 index 0000000..fc4ebfd --- /dev/null +++ b/lib/components/colorful_chips.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +class ColorfulChip extends StatelessWidget { + final String label; + + const ColorfulChip({Key? key, required this.label}) : super(key: key); + + @override + Widget build(BuildContext context) { + final color = Color(((label.hashCode) & 0xFFFFFF) | 0xFF000000); + return Chip( + label: Text(label), + backgroundColor: color, + labelStyle: TextStyle( + color: color.computeLuminance() > 0.5 ? Colors.black : Colors.white, + ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ); + } +} + +class ColorfulActionChip extends StatelessWidget { + final String label; + final VoidCallback onPressed; + + const ColorfulActionChip({ + Key? key, + required this.label, + required this.onPressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final color = Color( + ((label.hashCode - 5 /* randomness - */) & 0xFFFFFF) | 0xFF000000); + return ActionChip( + label: Text(label), + backgroundColor: color, + labelStyle: TextStyle( + color: color.computeLuminance() > 0.5 ? Colors.black : Colors.white, + ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + onPressed: onPressed, + ); + } +} diff --git a/lib/components/feature_bottom_sheet.dart b/lib/components/feature_bottom_sheet.dart new file mode 100644 index 0000000..fd9687a --- /dev/null +++ b/lib/components/feature_bottom_sheet.dart @@ -0,0 +1,184 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; +import 'package:uninav/components/colorful_chips.dart'; +import 'package:uninav/controllers/map_controller.dart'; +import 'package:uninav/data/geo/model.dart'; +import 'package:uninav/util/util.dart'; + +final _colorfulBoxDeco = BoxDecoration( + color: Colors.black, + border: Border.all(color: Colors.orange, width: 2), + borderRadius: BorderRadius.circular(10), +); + +Future showFeatureBottomSheet( + Feature feature, List? closestFeatures) { + return Get.bottomSheet( + Theme( + data: ThemeData.light(), + child: Container( + height: 300, + width: Get.mediaQuery.size.width, + decoration: const BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), topRight: Radius.circular(30)), + ), + padding: const EdgeInsets.all(20), + child: Column(children: [ + Center( + child: Container( + width: 50, + height: 5, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + ), + ), + ), + const SizedBox(height: 10), + Text(formatFeatureTitle(feature), + style: + const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)), + const SizedBox(height: 14), + if (closestFeatures != null) ...[ + const Text('Did you mean:'), + Wrap( + spacing: 8, + children: closestFeatures + .map((nearFeature) => ColorfulActionChip( + label: formatFeatureTitle(nearFeature), + onPressed: () { + Get.back(); + final newClosestFeatures = closestFeatures + .where((element) => element != nearFeature) + .toList(); + newClosestFeatures.add(feature); + + Get.find().focusOnFeature( + nearFeature, + closestFeatures: newClosestFeatures); + }, + )) + .toList(), + ), + const SizedBox(height: 14), + ], + ..._buildFeatureContent(feature), + ]), + ), + ), + isScrollControlled: true, + enterBottomSheetDuration: const Duration(milliseconds: 150), + exitBottomSheetDuration: const Duration(milliseconds: 200), + ); +} + +List _buildFeatureContent(Feature feature) { + return feature.type.when( + building: () => _buildBuildingContent(feature), + lectureHall: () => _buildLectureHallContent(feature), + room: () => _buildRoomContent(feature), + door: (connects) => _buildDoorContent(feature, connects), + toilet: (toiletType) => _buildToiletContent(feature, toiletType), + stairs: (connectsLevels) => _buildStairsContent(feature, connectsLevels), + lift: (connectsLevels) => _buildLiftContent(feature, connectsLevels), + publicTransport: (busLines, tramLines) => + _buildPublicTransportContent(feature, busLines, tramLines), + ); +} + +/// Builds the content for the Building feature type. +List _buildBuildingContent(Feature feature) { + return [ + Text(feature.name), + ]; +} + +/// Builds the content for the LectureHall feature type. +List _buildLectureHallContent(Feature feature) { + return [Text('Lecture Hall: ${feature.name}')]; +} + +/// Builds the content for the Room feature type. +List _buildRoomContent(Feature feature) { + return [Text('Room: ${feature.name}')]; +} + +/// Builds the content for the Door feature type. +List _buildDoorContent(Feature feature, List connects) { + return [Text('Door: ${feature.name}\nConnects: $connects')]; +} + +/// Builds the content for the Toilet feature type. +List _buildToiletContent(Feature feature, String toiletType) { + return [Text('Toilet: ${feature.name}\nType: $toiletType')]; +} + +/// Builds the content for the Stairs feature type. +List _buildStairsContent(Feature feature, List connectsLevels) { + return [Text('Stairs: ${feature.name}\nConnects Levels: $connectsLevels')]; +} + +/// Builds the content for the Lift feature type. +List _buildLiftContent(Feature feature, List connectsLevels) { + return [Text('Lift: ${feature.name}\nConnects Levels: $connectsLevels')]; +} + +/// Builds the content for the PublicTransport feature type. +List _buildPublicTransportContent( + Feature feature, List busLines, List tramLines) { + return [ + Text( + feature.name, + style: const TextStyle(fontSize: 18), + ), + const SizedBox(height: 10), + if (busLines.isNotEmpty) ...[ + const Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.only(right: 4), + child: Text( + 'Bus Lines:', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + ), + Align( + alignment: Alignment.centerLeft, + child: Wrap( + spacing: 8, + runSpacing: 4, + children: busLines.map((line) { + return ColorfulChip(label: line); + }).toList(), + ), + ), + const SizedBox(height: 10), + ], + if (tramLines.isNotEmpty) ...[ + const Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.only(right: 4), + child: Text( + 'Tram Lines:', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + ), + Align( + alignment: Alignment.centerLeft, + child: Wrap( + spacing: 8, + runSpacing: 4, + children: tramLines.map((line) { + return ColorfulChip(label: line); + }).toList(), + ), + ), + ], + ]; +} diff --git a/lib/controllers/map_controller.dart b/lib/controllers/map_controller.dart index 6864a6f..6c8eef8 100644 --- a/lib/controllers/map_controller.dart +++ b/lib/controllers/map_controller.dart @@ -1,13 +1,20 @@ import 'dart:convert'; import 'package:anyhow/anyhow.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:flutter_map/src/gestures/positioned_tap_detector_2.dart'; import 'package:geojson_vi/geojson_vi.dart'; import 'package:get/get.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:uninav/components/feature_bottom_sheet.dart'; import 'package:uninav/data/geo/model.dart'; import 'package:uninav/data/geo/parser.dart'; +import 'package:uninav/util/geojson_util.dart'; +import 'package:uninav/util/geomath.dart'; class MyMapController extends GetxController { - // constructor that calls loadgeojson with a default geojson string + final MapController mapController = MapController(); + final RxList features = [].obs; final currentLevel = 1.obs; final levels = [1].obs; @@ -40,6 +47,39 @@ class MyMapController extends GetxController { return const Ok(()); } + List computeHits(LatLng position, {bool Function(Feature)? filter}) { + final hits = <(Feature, double)>[]; + for (final feature in features) { + if (filter != null && !filter(feature)) { + continue; + } + if (feature.isPolygon()) { + if ((feature.geometry as GeoJSONPolygon) + .isPointInside(latLonToGeoJSON(position))) { + // compute distance to center of polygon + final distance = distanceBetweenLatLng( + polygonCenterMinmax((feature.geometry as GeoJSONPolygon) + .coordinates[0] + .map(geoJSONToLatLon) + .toList()), + position, + 'meters'); + hits.add((feature, distance)); + } + } else if (feature.isPoint()) { + final distance = distanceBetweenLatLng( + geoJSONToLatLon((feature.geometry as GeoJSONPoint).coordinates), + position, + 'meters'); + if (distance <= 5) { + hits.add((feature, distance)); + } + } + } + hits.sort((a, b) => a.$2.compareTo(b.$2)); + return hits.map((e) => e.$1).toList(); + } + Future loadGeoJson(String geoJsonString) async { try { // print(geoJsonString); @@ -67,4 +107,35 @@ class MyMapController extends GetxController { print('Error parsing GeoJSON: $e'); } } + + void handleTap(TapPosition tapPosition, LatLng point) { + final hits = Get.find().computeHits(point, + filter: (feature) => + feature.isOnLevel(null) /* is not on a level */ || + feature.isOnLevel(Get.find().currentLevel.value)); + print('Hits: ${hits.map((e) => e.name)}'); + if (hits.isNotEmpty) { + focusOnFeature(hits[0], + move: false, + closestFeatures: + hits.length > 1 ? hits.skip(1).toList() : null); // closest match + } + } + + void focusOnFeature(Feature feature, + {bool move = true, List? closestFeatures}) { + try { + if (move) { + mapController.move( + feature + .getCenterPoint() + .expect("Couldn't find Center Point of target geometry"), + mapController.camera.zoom, + ); + } + } catch (e) { + print("Error moving map controller: $e"); + } + showFeatureBottomSheet(feature, closestFeatures); + } } diff --git a/lib/data/geo/model.dart b/lib/data/geo/model.dart index c8cf8ec..5e4c22c 100644 --- a/lib/data/geo/model.dart +++ b/lib/data/geo/model.dart @@ -4,6 +4,8 @@ import 'package:flutter_map/flutter_map.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:geojson_vi/geojson_vi.dart'; import 'package:latlong2/latlong.dart'; +import 'package:uninav/util/geojson_util.dart'; +import 'package:uninav/util/geomath.dart'; part 'model.freezed.dart'; @@ -17,6 +19,7 @@ class Feature with _$Feature { String? description, required GeoJSONGeometry geometry, int? level, + String? building, }) = _Feature; bool isPolygon() { @@ -33,12 +36,13 @@ class Feature with _$Feature { points: pts, borderColor: Colors.black26, borderStrokeWidth: 2.0, + hitValue: 'test${pts.length}', ); final polygon = geometry as GeoJSONPolygon; // print(polygon.geometry!.geoSeries[0].geoPoints); final points = // polygon.coordinates[0].map((e) => LatLng(e[0], e[1])).toList(); - polygon.coordinates[0].map((e) => LatLng(e[1], e[0])).toList(); + polygon.coordinates[0].map(geoJSONToLatLon).toList(); // print(points); return Ok(constructor(points)); @@ -50,11 +54,44 @@ class Feature with _$Feature { Result getPoint() { if (isPoint()) { final point = geometry as GeoJSONPoint; - return Ok(LatLng(point.coordinates[1], point.coordinates[0])); + return Ok(geoJSONToLatLon(point.coordinates)); } else { return bail("Feature Geometry is not a Point"); } } + + /// Checks if the current feature is on the specified layer. + /// + /// For features that represent lifts or stairs, this method checks if the + /// feature's `connects_levels` list contains the specified layer. + /// + /// For other feature types, this method simply checks if the feature's `level` + /// property matches the specified layer. + /// + /// @param layer The layer to check for. **Layer can be `null`!** + /// `null` matches things such as Buildings without a layer. + /// @return `true` if the feature is on the specified layer, `false` otherwise. + bool isOnLevel(int? layer) { + if (type is Lift) { + return (type as Lift).connects_levels.contains(layer); + } else if (type is Stairs) { + return (type as Stairs).connects_levels.contains(layer); + } + return level == layer; + } + + Result getCenterPoint() { + if (isPolygon()) { + final polygon = geometry as GeoJSONPolygon; + final points = polygon.coordinates[0].map(geoJSONToLatLon).toList(); + return Ok(polygonCenterMinmax(points)); + } else if (isPoint()) { + final point = geometry as GeoJSONPoint; + return Ok(geoJSONToLatLon(point.coordinates)); + } else { + return bail("Feature Geometry is not a Polygon or Point"); + } + } } @freezed diff --git a/lib/data/geo/model.freezed.dart b/lib/data/geo/model.freezed.dart index f414d1a..3c901d9 100644 --- a/lib/data/geo/model.freezed.dart +++ b/lib/data/geo/model.freezed.dart @@ -19,8 +19,9 @@ mixin _$Feature { String get name => throw _privateConstructorUsedError; FeatureType get type => throw _privateConstructorUsedError; String? get description => throw _privateConstructorUsedError; - dynamic get geometry => throw _privateConstructorUsedError; + GeoJSONGeometry get geometry => throw _privateConstructorUsedError; int? get level => throw _privateConstructorUsedError; + String? get building => throw _privateConstructorUsedError; @JsonKey(ignore: true) $FeatureCopyWith get copyWith => throw _privateConstructorUsedError; @@ -35,8 +36,9 @@ abstract class $FeatureCopyWith<$Res> { {String name, FeatureType type, String? description, - dynamic geometry, - int? level}); + GeoJSONGeometry geometry, + int? level, + String? building}); $FeatureTypeCopyWith<$Res> get type; } @@ -57,8 +59,9 @@ class _$FeatureCopyWithImpl<$Res, $Val extends Feature> Object? name = null, Object? type = null, Object? description = freezed, - Object? geometry = freezed, + Object? geometry = null, Object? level = freezed, + Object? building = freezed, }) { return _then(_value.copyWith( name: null == name @@ -73,14 +76,18 @@ class _$FeatureCopyWithImpl<$Res, $Val extends Feature> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String?, - geometry: freezed == geometry + geometry: null == geometry ? _value.geometry : geometry // ignore: cast_nullable_to_non_nullable - as dynamic, + as GeoJSONGeometry, level: freezed == level ? _value.level : level // ignore: cast_nullable_to_non_nullable as int?, + building: freezed == building + ? _value.building + : building // ignore: cast_nullable_to_non_nullable + as String?, ) as $Val); } @@ -104,8 +111,9 @@ abstract class _$$FeatureImplCopyWith<$Res> implements $FeatureCopyWith<$Res> { {String name, FeatureType type, String? description, - dynamic geometry, - int? level}); + GeoJSONGeometry geometry, + int? level, + String? building}); @override $FeatureTypeCopyWith<$Res> get type; @@ -125,8 +133,9 @@ class __$$FeatureImplCopyWithImpl<$Res> Object? name = null, Object? type = null, Object? description = freezed, - Object? geometry = freezed, + Object? geometry = null, Object? level = freezed, + Object? building = freezed, }) { return _then(_$FeatureImpl( name: null == name @@ -141,14 +150,18 @@ class __$$FeatureImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String?, - geometry: freezed == geometry + geometry: null == geometry ? _value.geometry : geometry // ignore: cast_nullable_to_non_nullable - as dynamic, + as GeoJSONGeometry, level: freezed == level ? _value.level : level // ignore: cast_nullable_to_non_nullable as int?, + building: freezed == building + ? _value.building + : building // ignore: cast_nullable_to_non_nullable + as String?, )); } } @@ -161,7 +174,8 @@ class _$FeatureImpl extends _Feature { required this.type, this.description, required this.geometry, - this.level}) + this.level, + this.building}) : super._(); @override @@ -171,13 +185,15 @@ class _$FeatureImpl extends _Feature { @override final String? description; @override - final dynamic geometry; + final GeoJSONGeometry geometry; @override final int? level; + @override + final String? building; @override String toString() { - return 'Feature(name: $name, type: $type, description: $description, geometry: $geometry, level: $level)'; + return 'Feature(name: $name, type: $type, description: $description, geometry: $geometry, level: $level, building: $building)'; } @override @@ -189,13 +205,16 @@ class _$FeatureImpl extends _Feature { (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)); + (identical(other.geometry, geometry) || + other.geometry == geometry) && + (identical(other.level, level) || other.level == level) && + (identical(other.building, building) || + other.building == building)); } @override - int get hashCode => Object.hash(runtimeType, name, type, description, - const DeepCollectionEquality().hash(geometry), level); + int get hashCode => Object.hash( + runtimeType, name, type, description, geometry, level, building); @JsonKey(ignore: true) @override @@ -209,8 +228,9 @@ abstract class _Feature extends Feature { {required final String name, required final FeatureType type, final String? description, - required final dynamic geometry, - final int? level}) = _$FeatureImpl; + required final GeoJSONGeometry geometry, + final int? level, + final String? building}) = _$FeatureImpl; const _Feature._() : super._(); @override @@ -220,10 +240,12 @@ abstract class _Feature extends Feature { @override String? get description; @override - dynamic get geometry; + GeoJSONGeometry get geometry; @override int? get level; @override + String? get building; + @override @JsonKey(ignore: true) _$$FeatureImplCopyWith<_$FeatureImpl> get copyWith => throw _privateConstructorUsedError; @@ -238,7 +260,6 @@ mixin _$FeatureType { 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) @@ -252,7 +273,6 @@ mixin _$FeatureType { 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)? @@ -266,7 +286,6 @@ mixin _$FeatureType { 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)? @@ -281,7 +300,6 @@ mixin _$FeatureType { 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, @@ -294,7 +312,6 @@ mixin _$FeatureType { 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, @@ -307,7 +324,6 @@ mixin _$FeatureType { 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, @@ -377,7 +393,6 @@ class _$BuildingImpl implements Building { 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) @@ -394,7 +409,6 @@ class _$BuildingImpl implements Building { 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)? @@ -411,7 +425,6 @@ class _$BuildingImpl implements Building { 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)? @@ -432,7 +445,6 @@ class _$BuildingImpl implements Building { 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, @@ -448,7 +460,6 @@ class _$BuildingImpl implements Building { 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, @@ -464,7 +475,6 @@ class _$BuildingImpl implements Building { 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, @@ -524,7 +534,6 @@ class _$LectureHallImpl implements 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) @@ -541,7 +550,6 @@ class _$LectureHallImpl implements 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)? @@ -558,7 +566,6 @@ class _$LectureHallImpl implements 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)? @@ -579,7 +586,6 @@ class _$LectureHallImpl implements 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, @@ -595,7 +601,6 @@ class _$LectureHallImpl implements 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, @@ -611,7 +616,6 @@ class _$LectureHallImpl implements 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, @@ -670,7 +674,6 @@ class _$RoomImpl implements Room { 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) @@ -687,7 +690,6 @@ class _$RoomImpl implements Room { 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)? @@ -704,7 +706,6 @@ class _$RoomImpl implements Room { 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)? @@ -725,7 +726,6 @@ class _$RoomImpl implements Room { 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, @@ -741,7 +741,6 @@ class _$RoomImpl implements Room { 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, @@ -757,7 +756,6 @@ class _$RoomImpl implements Room { 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, @@ -848,7 +846,6 @@ class _$DoorImpl implements Door { 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) @@ -865,7 +862,6 @@ class _$DoorImpl implements Door { 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)? @@ -882,7 +878,6 @@ class _$DoorImpl implements Door { 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)? @@ -903,7 +898,6 @@ class _$DoorImpl implements Door { 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, @@ -919,7 +913,6 @@ class _$DoorImpl implements Door { 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, @@ -935,7 +928,6 @@ class _$DoorImpl implements Door { 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, @@ -1027,7 +1019,6 @@ class _$ToiletImpl implements Toilet { 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) @@ -1044,7 +1035,6 @@ class _$ToiletImpl implements Toilet { 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)? @@ -1061,7 +1051,6 @@ class _$ToiletImpl implements Toilet { 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)? @@ -1082,7 +1071,6 @@ class _$ToiletImpl implements Toilet { 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, @@ -1098,7 +1086,6 @@ class _$ToiletImpl implements Toilet { 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, @@ -1114,7 +1101,6 @@ class _$ToiletImpl implements Toilet { 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, @@ -1136,153 +1122,6 @@ abstract class Toilet implements FeatureType { 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( @@ -1360,7 +1199,6 @@ class _$StairsImpl implements Stairs { 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) @@ -1377,7 +1215,6 @@ class _$StairsImpl implements Stairs { 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)? @@ -1394,7 +1231,6 @@ class _$StairsImpl implements Stairs { 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)? @@ -1415,7 +1251,6 @@ class _$StairsImpl implements Stairs { 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, @@ -1431,7 +1266,6 @@ class _$StairsImpl implements Stairs { 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, @@ -1447,7 +1281,6 @@ class _$StairsImpl implements Stairs { 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, @@ -1545,7 +1378,6 @@ class _$LiftImpl implements Lift { 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) @@ -1562,7 +1394,6 @@ class _$LiftImpl implements Lift { 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)? @@ -1579,7 +1410,6 @@ class _$LiftImpl implements Lift { 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)? @@ -1600,7 +1430,6 @@ class _$LiftImpl implements Lift { 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, @@ -1616,7 +1445,6 @@ class _$LiftImpl implements Lift { 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, @@ -1632,7 +1460,6 @@ class _$LiftImpl implements Lift { 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, @@ -1751,7 +1578,6 @@ class _$PublicTransportImpl implements PublicTransport { 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) @@ -1768,7 +1594,6 @@ class _$PublicTransportImpl implements PublicTransport { 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)? @@ -1785,7 +1610,6 @@ class _$PublicTransportImpl implements PublicTransport { 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)? @@ -1806,7 +1630,6 @@ class _$PublicTransportImpl implements PublicTransport { 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, @@ -1822,7 +1645,6 @@ class _$PublicTransportImpl implements PublicTransport { 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, @@ -1838,7 +1660,6 @@ class _$PublicTransportImpl implements PublicTransport { 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, diff --git a/lib/data/geo/parser.dart b/lib/data/geo/parser.dart index d4d8a74..e6481c1 100644 --- a/lib/data/geo/parser.dart +++ b/lib/data/geo/parser.dart @@ -36,6 +36,8 @@ Result parseFeature( yaml = yaml as YamlMap? ?? {}; final description = yaml['desription'] as String?; + final building = yaml['building'] as String?; + print("yaml: $yaml"); var raw_type = yaml['type'] as String?; @@ -105,6 +107,7 @@ Result parseFeature( description: description, geometry: geometry, level: level, + building: building, )); } diff --git a/lib/main.dart b/lib/main.dart index ac19f59..6ca9fb1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,24 +18,17 @@ class MyApp extends StatelessWidget { return GetMaterialApp( title: 'Flutter Demo', theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), + darkTheme: ThemeData.dark( + useMaterial3: true, + ).copyWith( + colorScheme: ColorScheme.fromSeed( + brightness: Brightness.dark, + seedColor: Colors.deepPurple, + ), + ), initialRoute: '/map', getPages: [ GetPage(name: '/map', page: () => const MapPage()), @@ -44,91 +37,3 @@ class MyApp extends StatelessWidget { ); } } - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // TRY THIS: Try changing the color here to a specific color (to - // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar - // change color while the other colors stay the same. - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. - ); - } -} diff --git a/lib/map.dart b/lib/map.dart index 5ec4977..5569515 100644 --- a/lib/map.dart +++ b/lib/map.dart @@ -10,6 +10,7 @@ import 'package:uninav/components/hamburger_menu.dart'; import 'package:uninav/components/map_render_level.dart'; import 'package:uninav/controllers/map_controller.dart'; import 'package:uninav/data/geo/model.dart'; +import 'package:uninav/util/geojson_util.dart'; import 'package:uninav/util/geomath.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -50,97 +51,66 @@ class MapPage extends StatelessWidget { body: Stack( children: [ FlutterMap( - mapController: MapController(), + mapController: Get.find().mapController, options: MapOptions( initialCenter: const LatLng(48.422766, 9.9564), initialZoom: 16.0, // camera constraints maxZoom: 19, - onTap: (tapPosition, latlng) => print(tapPosition), + onTap: (tapPosition, point) { + print('Tap: $tapPosition, $point'); + Get.find().handleTap(tapPosition, point); + }, ), children: [ TileLayer( urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png", maxZoom: 19, ), - GestureDetector( - onTap: () { - print("tap"); - final LayerHitResult? hit = hitNotifier.value; - if (hit == null) { - return; - } - - print("not null"); - print(hit.coordinate); - hit.printInfo(); - print(hit.hitValues); - - for (final hitValue in hit.hitValues) { - print(hitValue); - } - // Handle the hit, which in this case is a tap - // For example, see the example in Hit Handling (below) - }, - child: MouseRegion( - cursor: SystemMouseCursors.click, - child: Stack( - children: [ - // buildings - LevelLayer( - filter: (feature) => feature.type is Building, - notifier: hitNotifier, - ), - - // public transport - LevelLayer( - filter: (feature) => - feature.level == null && - feature.type is PublicTransport, - polyCenterMarkerConstructor: (center, name) => Marker( - width: 100, - height: 100, - point: center, - child: const Icon( - Icons.train, - color: Colors.black, - ), - alignment: Alignment.center, - ), - polyConstructor: (feature) => feature - .getPolygon( - constructor: (pts) => Polygon( - points: pts, - color: Colors.green.withOpacity(0.2), - borderColor: Colors.green, - borderStrokeWidth: 1, - hitValue: feature, - )) - .unwrap(), - notifier: hitNotifier, - ), - - // current level - Obx( - () => Stack( - children: renderLevel( - Get.find() - .currentLevel - .value, - hitNotifier: hitNotifier)), - ), - - // RichAttributionWidget(attributions: [ - // TextSourceAttribution( - // 'OpenStreetMap contributors', - // onTap: () => - // launchUrl(Uri.parse('https://openstreetmap.org/copyright')), - // ) - // ]), - ], - ), + TranslucentPointer( + child: LevelLayer( + filter: (feature) => feature.type is Building, + notifier: hitNotifier, ), ), + + // public transport + TranslucentPointer( + child: LevelLayer( + filter: (feature) => + feature.level == null && + feature.type is PublicTransport, + polyCenterMarkerConstructor: (center, name) => Marker( + width: 100, + height: 100, + point: center, + child: const Icon( + Icons.train, + color: Colors.black, + ), + alignment: Alignment.center, + ), + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.green.withOpacity(0.2), + borderColor: Colors.green, + borderStrokeWidth: 1, + hitValue: feature, + )) + .unwrap(), + notifier: hitNotifier, + ), + ), + + // current level + Obx( + () => Stack( + children: renderLevel( + Get.find().currentLevel.value, + hitNotifier: hitNotifier)), + ), ], ), Positioned( diff --git a/lib/util/geojson_util.dart b/lib/util/geojson_util.dart new file mode 100644 index 0000000..411883e --- /dev/null +++ b/lib/util/geojson_util.dart @@ -0,0 +1,96 @@ +import 'package:geojson_vi/geojson_vi.dart'; +import 'package:latlong2/latlong.dart'; +import 'dart:math'; + +void swapLatLonGeojsonGeometry(GeoJSONGeometry geometry) { + if (geometry is GeoJSONPolygon) { + geometry.coordinates[0] = + geometry.coordinates[0].map((e) => [e[1], e[0]]).toList(); + } else if (geometry is GeoJSONPoint) { + geometry.coordinates = [geometry.coordinates[1], geometry.coordinates[0]]; + } else { + throw UnimplementedError( + "Geometry of type ${geometry.runtimeType} point swapping is unimplemented"); + } +} + +List latLonToGeoJSON(LatLng point) { + return [point.longitude, point.latitude]; +} + +LatLng geoJSONToLatLon(List point) { + return LatLng(point[1], point[0]); +} + +double degreesToRadians(double degrees) { + return degrees * (pi / 180); +} + +double radiansToDegrees(double radians) { + return radians * (180 / pi); +} + +double bearingBetweenLatLng(LatLng point1, LatLng point2) { + return bearingBetween( + point1.latitude, + point1.longitude, + point2.latitude, + point2.longitude, + ); +} + +double bearingBetween(double lat1, double lon1, double lat2, double lon2) { + var dLon = degreesToRadians(lon2 - lon1); + var y = sin(dLon) * cos(degreesToRadians(lat2)); + var x = cos(degreesToRadians(lat1)) * sin(degreesToRadians(lat2)) - + sin(degreesToRadians(lat1)) * cos(degreesToRadians(lat2)) * cos(dLon); + var angle = atan2(y, x); + return (radiansToDegrees(angle) + 360) % 360; +} + +double distanceBetweenLatLng(LatLng point1, LatLng point2, String unit) { + return distanceBetween(point1.latitude, point1.longitude, point2.latitude, + point2.longitude, unit); +} + +double distanceBetween( + double lat1, double lon1, double lat2, double lon2, String unit) { + const earthRadius = 6371; // in km + // assuming earth is a perfect sphere(it's not) + + // Convert degrees to radians + final lat1Rad = degreesToRadians(lat1); + final lon1Rad = degreesToRadians(lon1); + final lat2Rad = degreesToRadians(lat2); + final lon2Rad = degreesToRadians(lon2); + + final dLat = lat2Rad - lat1Rad; + final dLon = lon2Rad - lon1Rad; + + // Haversine formula + final a = pow(sin(dLat / 2), 2) + + cos(lat1Rad) * cos(lat2Rad) * pow(sin(dLon / 2), 2); + final c = 2 * atan2(sqrt(a), sqrt(1 - a)); + + final distance = earthRadius * c; + + return toRequestedUnit(unit, distance); + + // return distance; // in km +} + +double toRequestedUnit(String unit, double distanceInKm) { + switch (unit) { + case 'kilometers': + return distanceInKm; + case 'meters': + return distanceInKm * 1000; + case 'miles': + return (distanceInKm * 1000) / 1609.344; + case 'yards': + return distanceInKm * 1093.61; + case '': + return distanceInKm; + } + return distanceInKm; +} diff --git a/lib/util/geomath.dart b/lib/util/geomath.dart index 29cad41..95e503f 100644 --- a/lib/util/geomath.dart +++ b/lib/util/geomath.dart @@ -35,3 +35,24 @@ LatLng polygonCenterAvg(List polygon) { return LatLng(centerLat, centerLng); } + +bool isPointInPolygonRaycast(LatLng point, List polygon) { + bool inside = false; + int len = polygon.length; + + for (int i = 0, j = len - 1; i < len; j = i++) { + LatLng pi = polygon[i]; + LatLng pj = polygon[j]; + + if (((pi.latitude > point.latitude) != (pj.latitude > point.latitude)) && + (point.longitude < + (pj.longitude - pi.longitude) * + (point.latitude - pi.latitude) / + (pj.latitude - pi.latitude) + + pi.longitude)) { + inside = !inside; + } + } + + return inside; +} diff --git a/lib/util/util.dart b/lib/util/util.dart new file mode 100644 index 0000000..06b961f --- /dev/null +++ b/lib/util/util.dart @@ -0,0 +1,67 @@ +import 'package:uninav/data/geo/model.dart'; + +String formatDuration(Duration duration) { + final days = duration.inDays; + final hours = duration.inHours.remainder(24); + final minutes = duration.inMinutes.remainder(60); + final seconds = duration.inSeconds.remainder(60); + + String plural(int thing) => thing == 1 ? '' : 's'; + + if (days > 0) { + return '$days day${plural(days)}, $hours hour${plural(hours)}'; + } else if (hours > 0) { + return '$hours hour${plural(hours)}, $minutes minute${plural(minutes)}'; + } else if (minutes > 0) { + return '$minutes minute${plural(minutes)}, $seconds second${plural(seconds)}'; + } else { + return '$seconds second${plural(seconds)}'; + } +} + +String formatFeatureTitle(Feature feature) { + return feature.type.when( + building: () => '${feature.name} (Building)', + lectureHall: () => '${feature.name} (Lecture Hall)', + room: () => 'Room ${feature.name}', + door: (_) => 'Door', + toilet: (type) => 'Toilet (${formatToiletType(feature.type as Toilet)})', + stairs: (_) => 'Stairs', + lift: (_) => 'Lift', + publicTransport: (_, __) => 'Public Transport', + ); +} + +String formatToiletType(Toilet toilet) { + final type = toilet.toilet_type.toLowerCase(); + switch (type) { + case 'male': + return 'Male'; + case 'female': + return 'Female'; + case 'handicap': + return 'Handicap'; + default: + return 'Unknown'; + } +} + +String formatDistance(int distanceInMeters) { + if (distanceInMeters < 1000) { + // If the distance is less than 1 kilometer, display it in meters. + return '${distanceInMeters}m'; + } else { + // If the distance is 1 kilometer or more, display it in kilometers and meters. + final kilometers = + distanceInMeters ~/ 1000; // Integer division to get whole kilometers. + final meters = + distanceInMeters % 1000; // Remainder to get the remaining meters. + if (meters == 0) { + // If there are no remaining meters, display only kilometers. + return '${kilometers}km'; + } else { + // If there are remaining meters, display both kilometers and meters. + return '${kilometers}km ${meters}m'; + } + } +}