feat: major progress

This commit is contained in:
2024-04-20 16:32:01 +02:00
parent ba71707514
commit be359980bb
19 changed files with 5328 additions and 50 deletions

70
lib/data/geo/model.dart Normal file
View File

@ -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<GeoJsonPolygon>;
}
bool isPoint() {
return geometry is GeoJsonFeature<GeoJsonPoint>;
}
Result<Polygon> getPolygon({Polygon Function(List<LatLng>)? constructor}) {
if (isPolygon()) {
constructor ??= (pts) => Polygon(
points: pts, borderColor: Colors.black26, borderStrokeWidth: 2.0);
final polygon = geometry as GeoJsonFeature<GeoJsonPolygon>;
// 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<LatLng> getPoint() {
if (isPoint()) {
final point = geometry as GeoJsonFeature<GeoJsonPoint>;
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<String> connects) = Door;
const factory FeatureType.toilet(String toilet_type) = Toilet;
const factory FeatureType.stairs(List<int> connects_levels) = Stairs;
const factory FeatureType.lift(List<int> connects_levels) = Lift;
const factory FeatureType.publicTransport(
List<String> bus_lines, List<String> tram_lines) = PublicTransport;
}

File diff suppressed because it is too large Load Diff

142
lib/data/geo/parser.dart Normal file
View File

@ -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<Feature> parseFeature(
Map<String, dynamic> 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<int>(yaml, 'connects_levels')
.expect("Couldn't parse 'connects_levels' for feature $name");
type = FeatureType.lift(list);
break;
case 'stairs':
final list = getYamlList<int>(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<String>(yaml, 'connects')
.expect("Couldn't parse 'connects' for feature $name");
type = FeatureType.door(list);
break;
case 'toilet':
final toiletType = getYamlKey<String>(yaml, 'toilet_type')
.expect("Couldn't parse 'toilet_type' for feature $name");
type = FeatureType.toilet(toiletType);
break;
case 'public_transport':
final busLines = getYamlList<dynamic>(yaml, 'bus_lines')
.expect("Couldn't parse 'bus_lines' for feature $name");
final tramLines = getYamlList<dynamic>(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<List<String>> stringifyList(List<dynamic> tramLines) {
try {
return Ok(tramLines.map((e) => e.toString()).toList());
} catch (e) {
return bail("Couldn't stringify list: $e");
}
}
Result<List<T>> getYamlList<T>(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<T>());
} catch (e) {
return bail("Failed to parse yaml key $key as ${T.toString()}: $e");
}
}
Result<T> getYamlKey<T>(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");
}
}