better metadata processing
This commit is contained in:
parent
040f592ca2
commit
d58008caef
3 changed files with 327 additions and 11 deletions
|
|
@ -6,16 +6,19 @@ import 'package:turf/turf.dart';
|
|||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
|
||||
class RugReefer {
|
||||
final String apiUrl;
|
||||
final bool enableCacheExpiration;
|
||||
final Duration cacheExpirationDuration;
|
||||
final http.Client httpClient;
|
||||
final String categoryMap;
|
||||
Directory? cacheDir;
|
||||
|
||||
RugReefer({
|
||||
required this.apiUrl,
|
||||
required this.categoryMap,
|
||||
this.enableCacheExpiration = false,
|
||||
this.cacheExpirationDuration = const Duration(days: 14),
|
||||
http.Client? client,
|
||||
|
|
@ -34,9 +37,13 @@ class RugReefer {
|
|||
|
||||
Future<List<Map<String, dynamic>>> lookup(double latitude, double longitude, {double distanceThreshold = 10.0}) async {
|
||||
final String geohash = GeoHasher().encode(latitude, longitude, precision: 4);
|
||||
return kIsWeb
|
||||
final jsonMap = await loadJsonFromAssets(categoryMap);
|
||||
|
||||
List<Map<String, dynamic>> rawData = kIsWeb
|
||||
? await _lookupWeb(geohash, latitude, longitude, distanceThreshold)
|
||||
: await _lookupFile(geohash, latitude, longitude, distanceThreshold);
|
||||
|
||||
return _processMetadata(rawData, jsonMap, latitude, longitude, distanceThreshold);
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> _lookupFile(String geohash, double latitude, double longitude, double distanceThreshold) async {
|
||||
|
|
@ -47,7 +54,7 @@ class RugReefer {
|
|||
await _updateLastAccessTime(geohash);
|
||||
}
|
||||
final String geoJsonStr = utf8.decode(GZipCodec().decode(cacheFile.readAsBytesSync()));
|
||||
return _findMetadata(latitude, longitude, jsonDecode(geoJsonStr), distanceThreshold);
|
||||
return jsonDecode(geoJsonStr)['features'];
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> _lookupWeb(String geohash, double latitude, double longitude, double distanceThreshold) async {
|
||||
|
|
@ -59,12 +66,12 @@ class RugReefer {
|
|||
final geoJsonStr = utf8.decode(response.bodyBytes);
|
||||
await prefs.setString('geojson_$geohash', geoJsonStr);
|
||||
await _updateLastAccessTime(geohash);
|
||||
return _findMetadata(latitude, longitude, jsonDecode(geoJsonStr), distanceThreshold);
|
||||
return jsonDecode(geoJsonStr)['features'];
|
||||
}
|
||||
throw Exception('Failed to download GeoJSON for geohash: $geohash');
|
||||
}
|
||||
await _updateLastAccessTime(geohash);
|
||||
return _findMetadata(latitude, longitude, jsonDecode(cachedGeoJson), distanceThreshold);
|
||||
return jsonDecode(cachedGeoJson)['features'];
|
||||
}
|
||||
|
||||
Future<void> _downloadGeoJson(String geohash, File cacheFile) async {
|
||||
|
|
@ -102,12 +109,20 @@ class RugReefer {
|
|||
}
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _findMetadata(double latitude, double longitude, Map<String, dynamic> geoJson, double distanceThreshold) {
|
||||
Future<Map<String, dynamic>> loadJsonFromAssets(String assetPath) async {
|
||||
final jsonString = await rootBundle.loadString(assetPath);
|
||||
return jsonDecode(jsonString);
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _processMetadata(List<Map<String, dynamic>> features, Map<String, dynamic> jsonMap, double latitude, double longitude, double distanceThreshold) {
|
||||
final Position point = Position(longitude, latitude);
|
||||
final List<Map<String, dynamic>> results = [];
|
||||
for (var feature in geoJson['features']) {
|
||||
Map<String, Map<String, List<String>>> groupedObjects = {};
|
||||
|
||||
for (var feature in features) {
|
||||
final geometry = feature['geometry'];
|
||||
final metadata = Map<String, dynamic>.from(feature['properties']['tags'] ?? {})..removeWhere((_, v) => v == null);
|
||||
String? mainKey;
|
||||
|
||||
switch (geometry['type']) {
|
||||
case 'Polygon':
|
||||
final polygon = Polygon(
|
||||
|
|
@ -117,7 +132,7 @@ class RugReefer {
|
|||
.toList())
|
||||
.toList(),
|
||||
);
|
||||
if (booleanPointInPolygon(point, polygon)) results.add({"type": "polygon", ...metadata});
|
||||
if (booleanPointInPolygon(point, polygon)) mainKey = 'in';
|
||||
break;
|
||||
case 'LineString':
|
||||
final line = LineString(
|
||||
|
|
@ -125,11 +140,26 @@ class RugReefer {
|
|||
.map((p) => Position(p[0].toDouble(), p[1].toDouble()))
|
||||
.toList(),
|
||||
);
|
||||
if (_isPointNearLine(Point(coordinates: point), line, distanceThreshold)) results.add({"type": "line", ...metadata});
|
||||
if (_isPointNearLine(Point(coordinates: point), line, distanceThreshold)) mainKey = 'by';
|
||||
break;
|
||||
}
|
||||
if (mainKey == null) continue;
|
||||
|
||||
groupedObjects.putIfAbsent(mainKey, () => {});
|
||||
for (var key in metadata.keys) {
|
||||
for (var category in jsonMap.keys) {
|
||||
var categoryMap = jsonMap[category];
|
||||
if (categoryMap is Map && categoryMap.containsKey(key)) {
|
||||
var rule = categoryMap[key];
|
||||
if (rule is String || (rule is List && rule.contains(metadata[key])) || rule == true) {
|
||||
groupedObjects[mainKey]!.putIfAbsent(category, () => []);
|
||||
groupedObjects[mainKey]![category]!.add(metadata[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
return groupedObjects.entries.map((entry) => {entry.key: entry.value}).toList();
|
||||
}
|
||||
|
||||
bool _isPointNearLine(Point point, LineString line, double distanceThreshold) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue