Add WMS support and measurement functionality

- Implemented WMS layer handling for Slovenian aerial imagery and overlays for cadastral parcels and forest roads.
- Added distance measurement feature allowing users to measure distances on the map with long press interactions.
- Updated localization files for Croatian, Italian, and Slovenian languages to include new measurement and WMS-related strings.
- Enhanced the map layer model to support WMS-specific properties.
- Introduced a new tile provider for debugging WMS requests.
- Updated the drawing toolbar to include measurement mode and clear measurement functionality.
- Integrated SharedPreferences to persist overlay visibility states across app sessions.
- Added utility functions for handling the Slovenian coordinate reference system (EPSG:3794).
This commit is contained in:
Janez T
2025-10-27 21:49:58 +01:00
parent a03cc4a363
commit a4dc85d130
29 changed files with 3327 additions and 20 deletions

View File

@@ -6,7 +6,7 @@ import '../models/map_drawing.dart';
import '../utils/drawing_message_parser.dart';
/// Drawing mode state
enum DrawingMode { none, line, rectangle }
enum DrawingMode { none, line, rectangle, measure }
/// Provider for managing map drawings
class DrawingProvider with ChangeNotifier {
@@ -26,6 +26,11 @@ class DrawingProvider with ChangeNotifier {
List<LatLng> _currentLinePoints = [];
LatLng? _rectangleStartPoint;
// Distance measurement state
LatLng? _measurementPoint1;
LatLng? _measurementPoint2;
double? _measuredDistance; // in meters
// Getters
DrawingMode get drawingMode => _drawingMode;
Color get selectedColor => _selectedColor;
@@ -46,6 +51,9 @@ class DrawingProvider with ChangeNotifier {
List<LatLng> get currentLinePoints => List.unmodifiable(_currentLinePoints);
LatLng? get rectangleStartPoint => _rectangleStartPoint;
bool get isDrawing => _drawingMode != DrawingMode.none;
LatLng? get measurementPoint1 => _measurementPoint1;
LatLng? get measurementPoint2 => _measurementPoint2;
double? get measuredDistance => _measuredDistance;
/// Initialize and load saved drawings
Future<void> initialize() async {
@@ -126,8 +134,9 @@ class DrawingProvider with ChangeNotifier {
/// Update rectangle end point (for preview)
void updateRectangleEndPoint(LatLng endPoint) {
if (_drawingMode != DrawingMode.rectangle || _rectangleStartPoint == null)
if (_drawingMode != DrawingMode.rectangle || _rectangleStartPoint == null) {
return;
}
// Create preview rectangle
_currentDrawing = RectangleDrawing(
@@ -195,11 +204,47 @@ class DrawingProvider with ChangeNotifier {
notifyListeners();
}
/// Set first measurement point
void setMeasurementPoint1(LatLng point) {
if (_drawingMode != DrawingMode.measure) return;
_measurementPoint1 = point;
_measurementPoint2 = null;
_measuredDistance = null;
notifyListeners();
}
/// Set second measurement point and calculate distance
void setMeasurementPoint2(LatLng point) {
if (_drawingMode != DrawingMode.measure || _measurementPoint1 == null) return;
_measurementPoint2 = point;
_measuredDistance = _calculateDistance(_measurementPoint1!, point);
notifyListeners();
}
/// Calculate distance between two points using Haversine formula
double _calculateDistance(LatLng point1, LatLng point2) {
const Distance distance = Distance();
return distance.as(LengthUnit.Meter, point1, point2);
}
/// Clear measurement points
void clearMeasurement() {
_measurementPoint1 = null;
_measurementPoint2 = null;
_measuredDistance = null;
notifyListeners();
}
/// Cancel current drawing in progress
void _cancelCurrentDrawing() {
_currentLinePoints = [];
_rectangleStartPoint = null;
_currentDrawing = null;
_measurementPoint1 = null;
_measurementPoint2 = null;
_measuredDistance = null;
}
/// Clear current drawing (public method)

View File

@@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:latlong2/latlong.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/location_trail.dart';
import '../models/map_drawing.dart';
@@ -16,6 +17,10 @@ class MapProvider with ChangeNotifier {
bool _isTrailVisible = true;
final List<LocationTrail> _trailHistory = [];
// WMS overlay toggles
bool _showCadastralOverlay = false;
bool _showForestRoadsOverlay = false;
LatLng? get targetLocation => _targetLocation;
double? get targetZoom => _targetZoom;
bool get shouldAnimate => _shouldAnimate;
@@ -27,6 +32,10 @@ class MapProvider with ChangeNotifier {
List<LocationTrail> get trailHistory => List.unmodifiable(_trailHistory);
bool get isTrailActive => _currentTrail?.isActive ?? false;
// WMS overlay getters
bool get showCadastralOverlay => _showCadastralOverlay;
bool get showForestRoadsOverlay => _showForestRoadsOverlay;
void navigateToLocation({
required LatLng location,
double zoom = 15.0,
@@ -207,4 +216,33 @@ class MapProvider with ChangeNotifier {
if (_currentTrail == null) return Duration.zero;
return _currentTrail!.duration;
}
/// Toggle cadastral parcels overlay
Future<void> toggleCadastralOverlay() async {
_showCadastralOverlay = !_showCadastralOverlay;
notifyListeners();
await _saveOverlayState();
}
/// Toggle forest roads overlay
Future<void> toggleForestRoadsOverlay() async {
_showForestRoadsOverlay = !_showForestRoadsOverlay;
notifyListeners();
await _saveOverlayState();
}
/// Load overlay state from SharedPreferences
Future<void> loadOverlayState() async {
final prefs = await SharedPreferences.getInstance();
_showCadastralOverlay = prefs.getBool('map_show_cadastral_overlay') ?? false;
_showForestRoadsOverlay = prefs.getBool('map_show_forest_roads_overlay') ?? false;
notifyListeners();
}
/// Save overlay state to SharedPreferences
Future<void> _saveOverlayState() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('map_show_cadastral_overlay', _showCadastralOverlay);
await prefs.setBool('map_show_forest_roads_overlay', _showForestRoadsOverlay);
}
}