82 lines
2.9 KiB
Dart
82 lines
2.9 KiB
Dart
|
|
import 'dart:io';
|
||
|
|
import 'package:path_provider/path_provider.dart';
|
||
|
|
import '../models/track.dart';
|
||
|
|
import 'track_database.dart';
|
||
|
|
|
||
|
|
/// GPX 1.1 fájl generáló.
|
||
|
|
/// A GPX az összes standard alkalmazással kompatibilis (OsmAnd, Komoot,
|
||
|
|
/// QGIS, gpsvisualizer.com stb.).
|
||
|
|
class GpxExporter {
|
||
|
|
final TrackDatabase _db;
|
||
|
|
GpxExporter([TrackDatabase? db]) : _db = db ?? TrackDatabase.instance;
|
||
|
|
|
||
|
|
/// Elkészíti a GPX fájlt és visszaadja az elérési utat.
|
||
|
|
Future<String> export(Track track) async {
|
||
|
|
final points = await _db.getPoints(track.id!);
|
||
|
|
final xml = _buildGpx(track, points);
|
||
|
|
|
||
|
|
final dir = await getExternalStorageDirectory() ??
|
||
|
|
await getApplicationDocumentsDirectory();
|
||
|
|
final safeName =
|
||
|
|
track.name.replaceAll(RegExp(r'[^a-zA-Z0-9_\-]'), '_').toLowerCase();
|
||
|
|
final file = File('${dir.path}/${safeName}_${track.id}.gpx');
|
||
|
|
await file.writeAsString(xml, encoding: utf8_encoding);
|
||
|
|
return file.path;
|
||
|
|
}
|
||
|
|
|
||
|
|
String _buildGpx(Track track, List<TrackPoint> points) {
|
||
|
|
final buf = StringBuffer();
|
||
|
|
buf.writeln('<?xml version="1.0" encoding="UTF-8"?>');
|
||
|
|
buf.writeln('<gpx version="1.1" creator="Terepi Segéd"');
|
||
|
|
buf.writeln(' xmlns="http://www.topografix.com/GPX/1/1"');
|
||
|
|
buf.writeln(' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"');
|
||
|
|
buf.writeln(' xsi:schemaLocation="http://www.topografix.com/GPX/1/1 '
|
||
|
|
'http://www.topografix.com/GPX/1/1/gpx.xsd">');
|
||
|
|
|
||
|
|
buf.writeln(' <metadata>');
|
||
|
|
buf.writeln(' <name>${_esc(track.name)}</name>');
|
||
|
|
buf.writeln(
|
||
|
|
' <time>${track.startTime.toUtc().toIso8601String()}</time>');
|
||
|
|
buf.writeln(' </metadata>');
|
||
|
|
|
||
|
|
buf.writeln(' <trk>');
|
||
|
|
buf.writeln(' <name>${_esc(track.name)}</name>');
|
||
|
|
buf.writeln(' <desc>Forrás: ${_esc(track.source)}, '
|
||
|
|
'${track.pointCount} pont, '
|
||
|
|
'${track.distanceFormatted}</desc>');
|
||
|
|
buf.writeln(' <trkseg>');
|
||
|
|
|
||
|
|
for (final pt in points) {
|
||
|
|
buf.write(' <trkpt lat="${pt.latitude}" lon="${pt.longitude}">');
|
||
|
|
if (pt.altitude != null) {
|
||
|
|
buf.write('<ele>${pt.altitude!.toStringAsFixed(3)}</ele>');
|
||
|
|
}
|
||
|
|
buf.write('<time>${pt.timestamp.toUtc().toIso8601String()}</time>');
|
||
|
|
if (pt.speed != null) {
|
||
|
|
buf.write('<speed>${pt.speed!.toStringAsFixed(2)}</speed>');
|
||
|
|
}
|
||
|
|
if (pt.heading != null) {
|
||
|
|
buf.write('<course>${pt.heading!.toStringAsFixed(1)}</course>');
|
||
|
|
}
|
||
|
|
if (pt.accuracy != null) {
|
||
|
|
buf.write('<hdop>${pt.accuracy!.toStringAsFixed(2)}</hdop>');
|
||
|
|
}
|
||
|
|
buf.writeln('</trkpt>');
|
||
|
|
}
|
||
|
|
|
||
|
|
buf.writeln(' </trkseg>');
|
||
|
|
buf.writeln(' </trk>');
|
||
|
|
buf.writeln('</gpx>');
|
||
|
|
return buf.toString();
|
||
|
|
}
|
||
|
|
|
||
|
|
String _esc(String s) => s
|
||
|
|
.replaceAll('&', '&')
|
||
|
|
.replaceAll('<', '<')
|
||
|
|
.replaceAll('>', '>')
|
||
|
|
.replaceAll('"', '"');
|
||
|
|
}
|
||
|
|
|
||
|
|
// ignore: non_constant_identifier_names
|
||
|
|
final utf8_encoding = const SystemEncoding();
|