uninav/lib/controllers/map_controller.dart

142 lines
4.2 KiB
Dart
Raw Normal View History

2024-04-20 14:32:01 +00:00
import 'dart:convert';
import 'package:anyhow/anyhow.dart';
2024-04-20 22:35:16 +00:00
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';
2024-04-20 14:32:01 +00:00
import 'package:get/get.dart';
2024-04-20 22:35:16 +00:00
import 'package:latlong2/latlong.dart';
import 'package:uninav/components/feature_bottom_sheet.dart';
2024-04-20 14:32:01 +00:00
import 'package:uninav/data/geo/model.dart';
import 'package:uninav/data/geo/parser.dart';
2024-04-20 22:35:16 +00:00
import 'package:uninav/util/geojson_util.dart';
import 'package:uninav/util/geomath.dart';
2024-04-20 14:32:01 +00:00
class MyMapController extends GetxController {
2024-04-20 22:35:16 +00:00
final MapController mapController = MapController();
2024-04-20 14:32:01 +00:00
final RxList<Feature> features = <Feature>[].obs;
final currentLevel = 1.obs;
final levels = <int>[1].obs;
@override
onInit() async {
print("init");
ever(features, refreshLevels);
super.onInit();
}
void refreshLevels(List<Feature> curFeatures) {
print("refreshLevels");
final newLevels = <int>[1];
for (final feature in curFeatures) {
if (feature.level != null && !newLevels.contains(feature.level)) {
newLevels.add(feature.level!);
}
}
newLevels.sort();
levels.value = newLevels;
}
Result<void> 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(());
}
2024-04-20 22:35:16 +00:00
List<Feature> 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();
}
2024-04-20 14:32:01 +00:00
Future<void> loadGeoJson(String geoJsonString) async {
try {
// print(geoJsonString);
final featuresList = <Feature>[];
2024-04-21 06:24:50 +00:00
// print('doing');
final geojson = GeoJSONFeatureCollection.fromJSON(geoJsonString);
2024-04-21 06:24:50 +00:00
// print('done');
2024-04-20 14:32:01 +00:00
for (final feature in geojson.features) {
2024-04-21 06:24:50 +00:00
// print(feature);
// print(feature?.properties);
if (feature == null) continue;
2024-04-21 06:24:50 +00:00
// print(feature.properties);
final parsed = parseFeature(
feature.properties ?? <String, dynamic>{}, feature.geometry);
2024-04-20 14:32:01 +00:00
if (parsed case Ok(:final ok)) {
featuresList.add(ok);
}
}
features.value = featuresList;
} catch (e) {
print('Error parsing GeoJSON: $e');
}
}
2024-04-20 22:35:16 +00:00
void handleTap(TapPosition tapPosition, LatLng point) {
final hits = Get.find<MyMapController>().computeHits(point,
filter: (feature) =>
feature.isOnLevel(null) /* is not on a level */ ||
feature.isOnLevel(Get.find<MyMapController>().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<Feature>? 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);
}
2024-04-20 14:32:01 +00:00
}