import 'dart:math' as math; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import '../utils/custom_map_id.dart'; class CustomMapConfig { final String filePath; final String displayName; final String mapId; final int imageWidth; final int imageHeight; final double? metersPerPixel; final LatLng? calibrationPointA; final LatLng? calibrationPointB; const CustomMapConfig({ required this.filePath, required this.displayName, required this.mapId, required this.imageWidth, required this.imageHeight, this.metersPerPixel, this.calibrationPointA, this.calibrationPointB, }); bool get isCalibrated => metersPerPixel != null && metersPerPixel! > 0; double get _displayScale { final heightScale = imageHeight / 90.0; final widthScale = imageWidth / 180.0; return math.max(1.0, math.max(heightScale, widthScale)); } double get _displayHeight => imageHeight / _displayScale; double get _displayWidth => imageWidth / _displayScale; LatLngBounds get bounds => LatLngBounds(const LatLng(0, 0), LatLng(_displayHeight, _displayWidth)); LatLngBounds get displayBounds => LatLngBounds(LatLng(_displayHeight, 0), LatLng(0, _displayWidth)); LatLng toDisplayPoint(LatLng point) { return LatLng( _displayHeight - (point.latitude / _displayScale), point.longitude / _displayScale, ); } LatLng fromDisplayPoint(LatLng point) { return LatLng( (_displayHeight - point.latitude) * _displayScale, point.longitude * _displayScale, ); } Map toJson() { return { 'filePath': filePath, 'displayName': displayName, 'mapId': mapId, 'imageWidth': imageWidth, 'imageHeight': imageHeight, 'metersPerPixel': metersPerPixel, 'calibrationPointA': calibrationPointA != null ? { 'lat': calibrationPointA!.latitude, 'lon': calibrationPointA!.longitude, } : null, 'calibrationPointB': calibrationPointB != null ? { 'lat': calibrationPointB!.latitude, 'lon': calibrationPointB!.longitude, } : null, }; } CustomMapConfig copyWith({ String? filePath, String? displayName, String? mapId, int? imageWidth, int? imageHeight, double? metersPerPixel, bool clearMetersPerPixel = false, LatLng? calibrationPointA, bool clearCalibrationPointA = false, LatLng? calibrationPointB, bool clearCalibrationPointB = false, }) { return CustomMapConfig( filePath: filePath ?? this.filePath, displayName: displayName ?? this.displayName, mapId: normalizeCustomMapId(mapId) ?? this.mapId, imageWidth: imageWidth ?? this.imageWidth, imageHeight: imageHeight ?? this.imageHeight, metersPerPixel: clearMetersPerPixel ? null : (metersPerPixel ?? this.metersPerPixel), calibrationPointA: clearCalibrationPointA ? null : (calibrationPointA ?? this.calibrationPointA), calibrationPointB: clearCalibrationPointB ? null : (calibrationPointB ?? this.calibrationPointB), ); } static CustomMapConfig? fromJson(Map? json) { if (json == null) return null; final filePath = json['filePath']; final displayName = json['displayName']; final mapId = json['mapId']; final imageWidth = json['imageWidth']; final imageHeight = json['imageHeight']; if (filePath is! String || displayName is! String || mapId is! String || imageWidth is! int || imageHeight is! int) { return null; } LatLng? parsePoint(dynamic raw) { if (raw is! Map) return null; final lat = raw['lat']; final lon = raw['lon']; if (lat is! num || lon is! num) return null; return LatLng(lat.toDouble(), lon.toDouble()); } final metersPerPixel = json['metersPerPixel']; return CustomMapConfig( filePath: filePath, displayName: displayName, mapId: normalizeCustomMapId(mapId) ?? mapId, imageWidth: imageWidth, imageHeight: imageHeight, metersPerPixel: metersPerPixel is num ? metersPerPixel.toDouble() : null, calibrationPointA: parsePoint(json['calibrationPointA']), calibrationPointB: parsePoint(json['calibrationPointB']), ); } }