Terepbejárás geometriák szerkesztése: kontrollpontok és tulajdonságok.
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
import '../enums/note_type.dart';
|
||||
|
||||
class NoteItem {
|
||||
final int? id;
|
||||
final int? projectId;
|
||||
final NoteType type;
|
||||
final List<LatLng> points; // ← szerkesztéshez mindig elérhető
|
||||
final Color color;
|
||||
final double opacity;
|
||||
final double strokeWidth;
|
||||
final Color strokeColor;
|
||||
final String label;
|
||||
final DateTime createdAt;
|
||||
|
||||
const NoteItem(
|
||||
{this.id,
|
||||
this.projectId,
|
||||
required this.type,
|
||||
required this.points,
|
||||
required this.color,
|
||||
this.opacity = 0.5,
|
||||
this.strokeWidth = 3.0,
|
||||
required this.strokeColor,
|
||||
this.label = '',
|
||||
required this.createdAt});
|
||||
|
||||
NoteItem copyWith({
|
||||
List<LatLng>? points,
|
||||
Color? color,
|
||||
double? opacity,
|
||||
double? strokeWidth,
|
||||
Color? strokeColor,
|
||||
String? label,
|
||||
}) =>
|
||||
NoteItem(
|
||||
id: id,
|
||||
projectId: projectId,
|
||||
type: type,
|
||||
points: points ?? this.points,
|
||||
color: color ?? this.color,
|
||||
opacity: opacity ?? this.opacity,
|
||||
strokeWidth: strokeWidth ?? this.strokeWidth,
|
||||
strokeColor: strokeColor ?? this.strokeColor,
|
||||
label: label ?? this.label,
|
||||
createdAt: createdAt,
|
||||
);
|
||||
// ── Koordináta ↔ GeoJSON ────────────────────────────────────────
|
||||
|
||||
static List<LatLng> _parsePoints(String json) {
|
||||
final geom = jsonDecode(json) as Map<String, dynamic>;
|
||||
final gType = geom['type'] as String;
|
||||
final coords = geom['coordinates'];
|
||||
|
||||
switch (gType) {
|
||||
case 'Point':
|
||||
final c = coords as List;
|
||||
return [
|
||||
LatLng(
|
||||
(c[1] as num).toDouble(),
|
||||
(c[0] as num).toDouble(),
|
||||
)
|
||||
];
|
||||
|
||||
case 'LineString':
|
||||
return (coords as List)
|
||||
.map((c) => LatLng(
|
||||
(c[1] as num).toDouble(),
|
||||
(c[0] as num).toDouble(),
|
||||
))
|
||||
.toList();
|
||||
|
||||
case 'Polygon':
|
||||
// Külső gyűrű (index 0)
|
||||
return ((coords as List)[0] as List)
|
||||
.map((c) => LatLng(
|
||||
(c[1] as num).toDouble(),
|
||||
(c[0] as num).toDouble(),
|
||||
))
|
||||
.toList();
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
String _toPointsJson() {
|
||||
List<dynamic> coords;
|
||||
String gType;
|
||||
|
||||
switch (type) {
|
||||
case NoteType.point:
|
||||
// GeoJSON: [lon, lat]
|
||||
gType = 'Point';
|
||||
coords = [points.first.longitude, points.first.latitude];
|
||||
|
||||
case NoteType.line:
|
||||
gType = 'LineString';
|
||||
coords = points.map((p) => [p.longitude, p.latitude]).toList();
|
||||
|
||||
case NoteType.polygon:
|
||||
gType = 'Polygon';
|
||||
final ring = points.map((p) => [p.longitude, p.latitude]).toList();
|
||||
// Polygon zárt: első = utolsó pont
|
||||
if (ring.isNotEmpty) {
|
||||
final first = ring.first;
|
||||
final last = ring.last;
|
||||
final isClosed = first[0] == last[0] && first[1] == last[1];
|
||||
|
||||
if (!isClosed) ring.add(List.from(first));
|
||||
}
|
||||
coords = [ring];
|
||||
}
|
||||
|
||||
return jsonEncode({'type': gType, 'coordinates': coords});
|
||||
}
|
||||
// ── SQLite ↔ Map ────────────────────────────────────────────────
|
||||
|
||||
static Color _parseColor(String hex) {
|
||||
final h = hex.replaceFirst('#', '');
|
||||
return Color(int.parse(h.length == 6 ? 'FF$h' : h, radix: 16));
|
||||
}
|
||||
|
||||
static String _colorHex(Color c) =>
|
||||
'#${c.value.toRadixString(16).padLeft(8, '0').substring(2).toUpperCase()}';
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
if (id != null) 'id': id,
|
||||
if (projectId != null) 'project_id': projectId,
|
||||
'type': type.name,
|
||||
'points_json': _toPointsJson(),
|
||||
'color': _colorHex(color),
|
||||
'opacity': opacity,
|
||||
'stroke_width': strokeWidth,
|
||||
'stroke_color': _colorHex(strokeColor),
|
||||
'label': label,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
};
|
||||
|
||||
factory NoteItem.fromMap(Map<String, dynamic> m) => NoteItem(
|
||||
id: m['id'] as int?,
|
||||
projectId: m['project_id'] as int?,
|
||||
type: NoteType.values.firstWhere((t) => t.name == (m['type'] as String),
|
||||
orElse: () => NoteType.point),
|
||||
points: _parsePoints(m['points_json'] as String),
|
||||
color: _parseColor(m['color'] as String? ?? '#185FA5'),
|
||||
opacity: (m['opacity'] as num?)?.toDouble() ?? 0.5,
|
||||
strokeWidth: (m['stroke_width'] as num?)?.toDouble() ?? 3.0,
|
||||
strokeColor: _parseColor(m['stroke_color'] as String? ?? '#FFD700'),
|
||||
label: m['label'] as String? ?? '',
|
||||
createdAt: DateTime.parse(m['created_at'] as String),
|
||||
);
|
||||
|
||||
/// Kitöltési szín az opacity-val alkalmazva.
|
||||
Color get fillColor => Color.fromARGB(
|
||||
(opacity * 255).round(),
|
||||
color.red,
|
||||
color.green,
|
||||
color.blue,
|
||||
);
|
||||
|
||||
// Rendereléshez — a hitValue hordozza az id-t a tap detektáláshoz
|
||||
Polyline<int> toPolyline() => Polyline(
|
||||
points: points,
|
||||
color: color,
|
||||
strokeWidth: strokeWidth,
|
||||
hitValue: id!,
|
||||
);
|
||||
|
||||
Polygon<int> toPolygon() => Polygon(
|
||||
points: points,
|
||||
color: color.withOpacity(opacity),
|
||||
borderColor: strokeColor,
|
||||
borderStrokeWidth: strokeWidth,
|
||||
label: label.isEmpty ? null : label,
|
||||
hitValue: id!,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user