import 'dart:convert'; import 'package:be_happy/domain/entities/point.dart'; class Zone { final int id; final String title; final String description; final String type; final bool isActive; final String shapeType; // Трехмерная структура для поддержки MultiPolygon и дыр (holes): // geometry[индекс_полигона][индекс_кольца][индекс_точки] // индекс_кольца == 0 — внешняя граница, > 0 — внутренние вырезы (дыры) final List>> geometry; final String speedLimit; Zone({ required this.id, required this.title, required this.description, required this.type, required this.isActive, required this.shapeType, required this.geometry, required this.speedLimit, }); // Геттер для обратной совместимости (возвращает внешнее кольцо первого полигона) List get points { if (geometry.isNotEmpty && geometry[0].isNotEmpty) { return geometry[0][0]; } return []; } factory Zone.fromJson(Map json) { final zoneCoordinates = json['coordinates'] as Map? ?? {}; final String coordsString = zoneCoordinates['coordinates'] ?? '[]'; final String shapeType = zoneCoordinates['type'] ?? 'Polygon'; List>> parsedGeometry = []; try { final dynamic decoded = jsonDecode(coordsString); if (decoded is List && decoded.isNotEmpty) { if (shapeType == 'Polygon') { // Структура: [[[lon, lat], [lon, lat], ...], [hole1], ...] List> polygonRings = []; for (var ring in decoded) { if (ring is List) { List ringPoints = []; for (var coord in ring) { if (coord is List && coord.length >= 2) { // В GeoJSON сначала идет Longitude, затем Latitude ringPoints.add(Point( (coord[1] as num).toDouble(), (coord[0] as num).toDouble(), )); } } if (ringPoints.isNotEmpty) polygonRings.add(ringPoints); } } if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings); } else if (shapeType == 'MultiPolygon') { // Структура: [[[[lon, lat], ...]], [[[lon, lat], ...]]] for (var poly in decoded) { if (poly is List) { List> polygonRings = []; for (var ring in poly) { if (ring is List) { List ringPoints = []; for (var coord in ring) { if (coord is List && coord.length >= 2) { ringPoints.add(Point( (coord[1] as num).toDouble(), (coord[0] as num).toDouble(), )); } } if (ringPoints.isNotEmpty) polygonRings.add(ringPoints); } } if (polygonRings.isNotEmpty) parsedGeometry.add(polygonRings); } } } else { // Fallback для LineString или плоских списков List ringPoints = []; for (var coord in decoded) { if (coord is List && coord.length >= 2) { ringPoints.add(Point( (coord[1] as num).toDouble(), (coord[0] as num).toDouble(), )); } } if (ringPoints.isNotEmpty) parsedGeometry.add([ringPoints]); } } } catch (e) { print("PARSE ERROR for Zone ID ${json['id']}: $e"); } return Zone( id: json['id'] ?? 0, title: json['title'] ?? 'Unknown', description: json['description'] ?? '', type: json['type'] ?? '', isActive: json['isActive'] ?? false, speedLimit: json['speedLimit'] ?? '', shapeType: shapeType, geometry: parsedGeometry, ); } @override String toString() { return 'Zone{id: $id, title: $title, type: $type, polygonsCount: ${geometry.length}}'; } }