Files
be_happy_public/lib/domain/entities/zone.dart
2026-07-13 01:38:13 +03:00

123 lines
4.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<List<List<Point>>> 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<Point> get points {
if (geometry.isNotEmpty && geometry[0].isNotEmpty) {
return geometry[0][0];
}
return [];
}
factory Zone.fromJson(Map<String, dynamic> json) {
final zoneCoordinates = json['coordinates'] as Map<String, dynamic>? ?? {};
final String coordsString = zoneCoordinates['coordinates'] ?? '[]';
final String shapeType = zoneCoordinates['type'] ?? 'Polygon';
List<List<List<Point>>> parsedGeometry = [];
try {
final dynamic decoded = jsonDecode(coordsString);
if (decoded is List && decoded.isNotEmpty) {
if (shapeType == 'Polygon') {
// Структура: [[[lon, lat], [lon, lat], ...], [hole1], ...]
List<List<Point>> polygonRings = [];
for (var ring in decoded) {
if (ring is List) {
List<Point> 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<List<Point>> polygonRings = [];
for (var ring in poly) {
if (ring is List) {
List<Point> 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<Point> 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}}';
}
}