MobilApp/lib/pages/map/presentation/controllers/map_controller.dart

1153 lines
40 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:flutter_map/flutter_map.dart';
// import 'package:flutter_map_geojson/flutter_map_geojson.dart';
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:location/location.dart';
import 'package:latlong2/latlong.dart';
import 'package:nmea/nmea.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'
as permission_handler;
import 'package:share_plus/share_plus.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:terepi_seged/eov/convert_coordinate.dart';
import 'package:terepi_seged/eov/eov.dart';
import 'package:terepi_seged/gnss_sentences/gngga.dart';
import 'package:terepi_seged/gnss_sentences/gngst.dart';
import 'package:terepi_seged/gnss_sentences/gnrmc.dart';
import 'package:terepi_seged/models/point_to_measure.dart';
import 'package:terepi_seged/models/point_with_description_model.dart';
import 'package:proj4dart/proj4dart.dart' as proj4;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:terepi_seged/pages/map/presentation/views/measured_points_table_dialog.dart';
class MapViewController extends GetxController {
// String gpsAddress = "E8:31:CD:14:8B:B2";
// String gpsAddress = "98:CD:AC:62:FF:4E";
RxString gpsAddress = "98:CD:AC:62:FF:36".obs;
RxString gpsName = "TiGNSS Rover-FF4E".obs;
// String gpsName = "TiGNSS Rover-8BB2";
static const double maxZoomValue = 25.0;
Rx<bool> gpsIsConnected = false.obs;
RxBool ntripIsConnected = false.obs;
RxInt ntripDataPacketNumbers = 0.obs;
RxInt ggaSenDataPacketNumber = 0.obs;
RxString ggaSendLastTimeStr = "".obs;
String _messageBuffer = "";
late BluetoothConnection connection;
late Socket socket;
late StreamSubscription socketStreamSubscription;
RxInt gpsReceivedData = 0.obs;
RxBool hasGpsValidData = false.obs;
RxBool isMapMoveToCenter = true.obs;
DateTime lastGpsRefreshTime = DateTime.now();
String utcOfPositionFix = "";
String utcDateOfPositionFix = "";
RxInt ntripReceivedData = 0.obs;
final NmeaDecoder nmeaDecoder = NmeaDecoder();
String lastGgaMessage = '';
DateTime lastSendTimeGgaMessage =
DateTime.now().add(const Duration(seconds: -30));
NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
NumberFormat formatEovZ = NumberFormat("###0.0", "hu-HU");
NumberFormat formatAltitudeError = NumberFormat("####0.000", "hu-HU");
NumberFormat formatEovForFile = NumberFormat("#####0.0", "hu-HU");
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
RxDouble gpsLatitude = 0.0.obs;
RxString gpsLatitudeDirection = "".obs;
RxDouble gpsLongitude = 0.0.obs;
RxString gpsLongitudeDirection = "".obs;
RxDouble gpsAltitude = 0.0.obs;
RxDouble gpsGeoidSeparation = 0.0.obs;
RxInt gpsQuality = 0.obs;
RxDouble gpsLatitudeError = 0.0.obs;
RxDouble gpsLongitudeError = 0.0.obs;
RxDouble gpsAltitudeError = 0.0.obs;
Rx<DateTime> gpsDateTime = DateTime(2000).obs;
Rx<Eov> eov = Eov(0, 0).obs;
RxInt latDegree = 0.obs;
RxInt latMin = 0.obs;
RxDouble latSec = 0.0.obs;
RxInt longDegree = 0.obs;
RxInt longMin = 0.obs;
RxDouble longSec = 0.0.obs;
RxDouble currentLongitude = 0.0.obs;
RxDouble currentLatitude = 0.0.obs;
RxDouble currentZoom = 12.0.obs;
late final MapController mapController;
final currentLocationMarker = <Marker>[];
final pointNotesMarker = <Marker>[];
List<PointToMeasure> pointsToMeasure = <PointToMeasure>[];
final pointsToMeasureMarker = <Marker>[];
final pointsToMeasureLabel = <PolyWidget>[];
final pointsToMeasureDropDownMenuItem = <DropdownMenuItem<int>>[];
RxInt pointsToMeasureSelectedValue = (-1).obs;
RxDouble distance = 0.0.obs;
TextEditingController pointIdController = TextEditingController();
TextEditingController pointDescriptionController = TextEditingController();
TextEditingController gpsHeightController = TextEditingController();
TextEditingController pointPrefixController = TextEditingController();
TextEditingController pointPostfixController = TextEditingController();
TextEditingController ntripUsernameController = TextEditingController();
TextEditingController ntripPasswordController = TextEditingController();
int pointId = 1;
String pointIdPrefix = "";
String pointIdPostfix = "";
RxString ntripUserName = "".obs;
RxString ntripPassword = "".obs;
Rx<bool> pointMeasuringDirectionForward = true.obs;
List<PointWithDescription> pointWithDescriptionList = [];
late Directory? directory;
late File dataFile;
late proj4.Projection eovProj, wgsProj;
RxBool mapIsInitialized = false.obs;
// GeoJsonParser parser =
// GeoJsonParser(defaultMarkerColor: const Color.fromARGB(255, 85, 34, 49));
final CollectionReference _measuredPoints =
FirebaseFirestore.instance.collection('measuredPoints');
// late SMIBool gpsTrigger;
// late StateMachineController riveGpsIconController;
late SharedPreferences prefs;
Rx<bool> isShowPassword = false.obs;
final passwordFieldFocusNode = FocusNode();
late AuthResponse authResponse;
late Session? session;
late User? user;
@override
void onInit() async {
super.onInit();
final bytes = (await rootBundle.load('assets/Grids/etrs2eov_notowgs.gsb'))
.buffer
.asUint8List();
proj4.Projection.nadgrid('Etrs2Eov', bytes);
// var def =
// '+proj=somerc +lat_0=47.14439372222222 +lon_0=19.04857177777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +towgs84=52.17,-71.82,-14.9,0,0,0,0 +units=m +nadgrids=@ignorable,Etrs2Eov,null +no_defs';
var def =
'+proj=somerc +lat_0=47.14439372222222 +lon_0=19.04857177777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +towgs84=52.17,-71.82,-14.9,0,0,0,0 +units=m +nadgrids=Etrs2Eov +no_defs';
// Named Projection signature, later find it from anywhere via Projection.get('EPSG:23700')
eovProj = proj4.Projection.add('EPSG:23700', def);
wgsProj = proj4.Projection.WGS84;
//Loading, Success, Error handle with 1 line of code
nmeaDecoder
..registerTalkerSentence("GGA", (line) => Gngga(raw: line))
..registerTalkerSentence("RMC", (line) => Gnrmc(raw: line))
..registerTalkerSentence("GST", (line) => Gngst(raw: line));
prefs = await SharedPreferences.getInstance();
authResponse = await Supabase.instance.client.auth
.signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
session = authResponse.session;
user = authResponse.user;
Supabase.instance.client
.channel('public:TerepiSeged_Receiver')
.onPostgresChanges(
event: PostgresChangeEvent.update,
schema: 'public',
table: 'TerepiSeged_Receiver',
callback: (playload) {
var id = playload.newRecord['pointNumber'] as int;
print('Change received: ${id}');
updatePointStatus(id);
})
.subscribe();
mapController = MapController();
// riveGpsIconController = RiveUtils.getRiveController(Artboard(),
// stateMachineName: "gps_Interactivity");
// gpsTrigger = riveGpsIconController.findSMI("active");
mapIsInitialized.value = true;
}
@override
void onClose() async {
super.onClose();
FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
if (gpsIsConnected.value) {
connection.close();
// connection = null;
print("BluetoothTestController dispose ....");
}
pointDescriptionController.dispose();
pointIdController.dispose();
gpsHeightController.dispose();
pointPrefixController.dispose();
pointPostfixController.dispose();
ntripUsernameController.dispose();
ntripPasswordController.dispose();
await Supabase.instance.client
.channel('public:TerepiSeged_Receiver')
.unsubscribe();
}
@override
void onReady() async {
super.onReady();
_getInitialLocation();
// String data = await rootBundle.loadString('assets/Files/transzekt.geojson');
// parser.parseGeoJsonAsString(data);
if (await permission_handler.Permission.storage.isGranted) {
print("Storage permission is ok ...");
} else {
var result = await permission_handler.Permission.storage.request();
if (result == permission_handler.PermissionStatus.granted) {
print("Storage permission request is ok ....");
} else {
print("No storage permission");
}
}
if (await permission_handler.Permission.manageExternalStorage.isGranted) {
print("External storage permission is ok ...");
} else {
var result =
await permission_handler.Permission.manageExternalStorage.request();
if (result == permission_handler.PermissionStatus.granted) {
print("External storage permission request is ok ....");
} else {
print("No external storage permission");
}
if (prefs.containsKey('gpsAddress')) {
var address = prefs.getString('gpsAddress');
if (address != null) {
gpsAddress.value = address;
}
}
if (prefs.containsKey('gpsName')) {
var name = prefs.getString('gpsName');
if (name != null) {
gpsName.value = name;
}
}
if (prefs.containsKey('ntripUserName')) {
var userName = prefs.getString('ntripUserName');
if (userName != null) {
ntripUserName.value = userName;
}
}
if (prefs.containsKey('ntripPassword')) {
var password = prefs.getString('ntripPassword');
if (password != null) {
ntripPassword.value = password;
}
}
}
directory = await getExternalStorageDirectory();
print(directory!.path);
// String newPath = '';
// List<String> folders = directory!.path.split("/");
// for (int i = 1; i < folders.length; i++) {
// String folder = folders[i];
// if (folder != "Android") {
// newPath += "/" + folder;
// } else {
// break;
// }
// }
// newPath = newPath + "/TerepisSegedApp";
// directory = Directory(newPath);
if (!await directory!.exists()) {
await directory!.create(recursive: true);
}
dataFile = File("${directory!.path}/data.txt");
if (await directory!.exists()) {
if (!await dataFile.exists()) {
dataFile.writeAsString(
"Id;DateTime;Description;EovX;EovY;Latitude;Longitude;Altitude;Hor.Err;Vert.Err\r\n");
}
}
gpsHeightController.text = '1.8';
}
void _getInitialLocation() async {
bool servicedEnabled;
PermissionStatus permissionGranted;
LocationData locationData;
Location location = Location();
servicedEnabled = await location.serviceEnabled();
if (!servicedEnabled) {
servicedEnabled = await location.requestService();
if (!servicedEnabled) {
return;
}
}
permissionGranted = await location.hasPermission();
if (permissionGranted == PermissionStatus.denied) {
permissionGranted = await location.requestPermission();
if (permissionGranted != PermissionStatus.granted) {
return;
}
}
locationData = await location.getLocation();
currentLatitude.value = locationData.latitude ?? 0.0;
currentLongitude.value = locationData.longitude ?? 0.0;
print("Current location initialized -> $currentLatitude $currentLongitude");
mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
currentZoom.value);
_updateCurrentLocationMarker();
}
void connectToGps() {
if (gpsIsConnected == false) {
BluetoothConnection.toAddress(gpsAddress.value).then((value) {
connection = value;
gpsIsConnected.value = true;
print("GPS is connected ...");
connection.input!.listen(_onDataReceived);
});
}
}
void disconnectFromGps() {
if (gpsIsConnected.value) {
connection.close();
gpsIsConnected.value = false;
print("GPS is disconnected ....");
}
if (ntripIsConnected.value) {
disconnectFromNtripServer();
}
}
void connectToNtripServer() async {
// socket = await Socket.connect(InternetAddress('3.23.52.207'), 2101,
// timeout: const Duration(seconds: 5));
socket = await Socket.connect(InternetAddress('84.206.45.44'), 2101,
timeout: const Duration(seconds: 5));
socket.asBroadcastStream;
ntripIsConnected.value = true;
socket.encoding = ascii;
print("Connected to ntrip server ....");
// String header = "GET /KOVARIK HTTP/1.1\r\n";
String header = "GET /SGO_RTK3.2 HTTP/1.1\r\n";
header += "User-Agent: SharpGps iter.dk\r\n";
header += "Accept: */*\r\nConnection: close\r\n";
// header += "Authorization: Basic ${_toBase64("info@mail.app-dev.hu:")}\r\n";
//header += "Authorization: Basic ${_toBase64("elgi08:Laszl0stef1")}\r\n";
header +=
"Authorization: Basic ${_toBase64("${ntripUserName.value}:${ntripPassword.value}")}\r\n";
// header += "Host:rtk2go.com:2101\r\n";
header += "Host:gnssnet.hu:2101\r\n";
header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
header += "\r\n";
// listen for responses from the server
socketStreamSubscription = socket.listen(
// handle data from the server
(Uint8List data) {
// "ICY 200 OK" - first response
final serverResponse = String.fromCharCodes(data);
ntripReceivedData.value = data.length;
ntripDataPacketNumbers.value++;
if (gpsIsConnected.value) {
if (data.length > 14) {
connection.output.add(data);
}
}
print('Server: $ntripReceivedData');
},
// handle errors
onError: (error) {
print(error);
socket.destroy();
},
// handle server ending connection
onDone: () async {
print('Server left.');
socketStreamSubscription.cancel();
await socket.flush();
ntripIsConnected.value = false;
ntripReceivedData.value = 0;
socket.destroy();
},
);
socket.add(_convertStringToUint8List(header));
// sendGgaMessage(lastGgaMessage);
}
void disconnectFromNtripServer() async {
socketStreamSubscription.cancel();
await socket.flush();
socket.close();
socket.destroy();
ntripReceivedData.value = 0;
ntripIsConnected.value = false;
print("Disconnect from ntrip server....");
}
void _onDataReceived(Uint8List data) {
String sentence = "";
print("Bluetooth received -> ${data.length} byte(s)");
String dataString = String.fromCharCodes(data);
int index = data.indexOf(13);
if (~index != 0) {
sentence = _messageBuffer + dataString.substring(0, index);
_messageBuffer = dataString.substring(index);
} else {
_messageBuffer = _messageBuffer + dataString;
}
// print("Message ($count): $sentence");
_processGnssMessage(sentence);
}
String _toBase64(String str) {
final bytes = ascii.encode(str);
final base64Str = base64.encode(bytes);
return base64Str;
}
Uint8List _convertStringToUint8List(String str) {
final List<int> codeUnits = str.codeUnits;
final Uint8List unit8List = Uint8List.fromList(codeUnits);
return unit8List;
}
void _processGnssMessage(String message) {
LineSplitter lineSplitter = const LineSplitter();
List<String> lines = lineSplitter.convert(message);
if (lines.isEmpty) {
return;
}
for (String line in lines) {
if (line.trim().isEmpty) {
continue;
}
if (line.startsWith("\$GNGGA")) {
final sentence = nmeaDecoder.decode(line);
if (sentence!.valid && sentence is Gngga) {
hasGpsValidData.value = sentence.gpsQualityIndicator > 0;
if (hasGpsValidData.value) {
if (DateTime.now().difference(lastGpsRefreshTime).inSeconds >= 0) {
lastGpsRefreshTime = DateTime.now();
utcOfPositionFix = sentence.utcOfPositionFix;
gpsLatitude.value = sentence.latitude;
gpsLatitudeDirection.value = sentence.latitudeDirection;
gpsLongitude.value = sentence.longitude;
gpsLongitudeDirection.value = sentence.longitudeDirection;
gpsAltitude.value = sentence.altitudeAboveMeanSeaLevel;
gpsGeoidSeparation.value = sentence.geoidSeparation;
gpsQuality.value = sentence.gpsQualityIndicator;
eov.value = ConvertCoordinate.ConvertWgsToEov(
gpsLatitude.value, gpsLongitude.value);
if (pointsToMeasureSelectedValue.value >= 0) {
double coordX =
pointsToMeasure[pointsToMeasureSelectedValue.value].coordX;
double coordY =
pointsToMeasure[pointsToMeasureSelectedValue.value].coordY;
var eovCoord = proj4.Point(x: coordX, y: coordY);
var wgsCoord = eovProj.transform(wgsProj, eovCoord);
distance.value = calculateDistance(
LatLng(gpsLatitude.value, gpsLongitude.value),
LatLng(wgsCoord.y, wgsCoord.x));
}
latDegree.value = ConvertCoordinate.toDegree(gpsLatitude.value);
latMin.value = ConvertCoordinate.toMinute(gpsLatitude.value);
latSec.value = ConvertCoordinate.toSecond(gpsLatitude.value);
longDegree.value = ConvertCoordinate.toDegree(gpsLongitude.value);
longMin.value = ConvertCoordinate.toMinute(gpsLongitude.value);
longSec.value = ConvertCoordinate.toSecond(gpsLongitude.value);
currentLatitude.value = gpsLatitude.value;
currentLongitude.value = gpsLongitude.value;
_updateCurrentLocationMarker();
lastGgaMessage = line;
if (ntripIsConnected.value &&
(DateTime.now()
.difference(lastSendTimeGgaMessage)
.inSeconds >=
5)) {
sendGgaMessage(lastGgaMessage);
print("Send GGA message: $lastGgaMessage");
ggaSenDataPacketNumber.value++;
ggaSendLastTimeStr.value = utcOfPositionFix;
lastSendTimeGgaMessage = DateTime.now();
}
}
}
}
}
if (line.startsWith("\$GNGST") && hasGpsValidData.value) {
final sentence = nmeaDecoder.decode(line);
if (sentence!.valid && sentence is Gngst) {
gpsLatitudeError.value = sentence.latitudeError;
gpsLongitudeError.value = sentence.longitudeError;
gpsAltitudeError.value = sentence.heightError;
}
}
if (line.startsWith("\$GNRMC") && hasGpsValidData.value) {
final sentence = nmeaDecoder.decode(line);
if (sentence!.valid && sentence is Gnrmc) {
utcDateOfPositionFix = sentence.date;
if (utcDateOfPositionFix.isNotEmpty && utcOfPositionFix.isNotEmpty) {
gpsDateTime.value = DateTime(
2000 +
int.parse(
"${utcDateOfPositionFix[4]}${utcDateOfPositionFix[5]}"),
int.parse(
"${utcDateOfPositionFix[2]}${utcDateOfPositionFix[3]}"),
int.parse(
"${utcDateOfPositionFix[0]}${utcDateOfPositionFix[1]}"),
int.parse("${utcOfPositionFix[0]}${utcOfPositionFix[1]}"),
int.parse("${utcOfPositionFix[2]}${utcOfPositionFix[3]}"),
int.parse("${utcOfPositionFix[4]}${utcOfPositionFix[5]}"));
}
}
}
}
}
String getGpsQualityIndicator({required int quality}) {
String qualityStr = "Invalid";
switch (quality) {
case 0:
{
qualityStr = "Invalid";
}
break;
case 1:
{
qualityStr = "Standard GPS (2D/3D)";
}
break;
case 2:
{
qualityStr = "Differential GPS";
}
break;
case 4:
{
qualityStr = "RTK Fix";
}
break;
case 5:
{
qualityStr = "RTK Float";
}
break;
case 6:
{
qualityStr = "Estimated (DR) Fix";
}
break;
default:
{
qualityStr = "Invalid (-1)";
}
}
return qualityStr;
}
void mapZoomOut() {
double cLat, cLong;
if (currentZoom.value > 0) {
currentZoom.value = currentZoom.value - 1;
cLat = isMapMoveToCenter.value
? currentLatitude.value
: mapController.camera.center.latitude;
cLong = isMapMoveToCenter.value
? currentLongitude.value
: mapController.camera.center.longitude;
mapController.move(LatLng(cLat, cLong), currentZoom.value);
}
}
void mapZoomIn() {
double cLat, cLong;
if (currentZoom.value < maxZoomValue) {
currentZoom.value++;
cLat = isMapMoveToCenter.value
? currentLatitude.value
: mapController.camera.center.latitude;
cLong = isMapMoveToCenter.value
? currentLongitude.value
: mapController.camera.center.longitude;
mapController.move(LatLng(cLat, cLong), currentZoom.value);
}
}
void _updateCurrentLocationMarker() {
currentLocationMarker.clear();
currentLocationMarker.add(Marker(
point: LatLng(currentLatitude.value, currentLongitude.value),
width: 15.0,
height: 15.0,
child: Container(
width: 15.0,
height: 15.0,
decoration: BoxDecoration(
color: getCurrentLocationMarkerColor(quality: gpsQuality.value),
shape: BoxShape.circle,
border: Border.all(width: 1.5, color: Colors.white)),
)));
if (isMapMoveToCenter.value) {
mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
currentZoom.value);
}
}
Color getCurrentLocationMarkerColor({required int quality}) {
Color qualityStr = Colors.black;
switch (quality) {
case 0:
{
qualityStr = Colors.black;
}
break;
case 1:
{
qualityStr = Colors.red;
}
break;
case 2:
{
qualityStr = Colors.blue;
}
break;
case 4:
{
qualityStr = Colors.green;
}
break;
case 5:
{
qualityStr = Colors.orange;
}
break;
case 6:
{
qualityStr = Colors.yellow;
}
break;
default:
{
qualityStr = Colors.white;
}
}
return qualityStr;
}
void onBottomNavigationBarTap(int index) async {
bool noMorePoint = false;
print("OnBottomNavTap -> $index");
if (index == 0) {
pointIdController.text =
'${pointsToMeasure[pointsToMeasureSelectedValue.value].id}';
// pointIdController.text = pointId.toString();
pointDescriptionController.text = "";
Get.dialog(
AlertDialog(
title: const Text("Pont rögzítése"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: pointIdController,
autofocus: true,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
border: OutlineInputBorder(), labelText: 'Azonosító'),
),
const SizedBox(
height: 20.0,
),
TextField(
controller: pointDescriptionController,
decoration: const InputDecoration(
border: OutlineInputBorder(), labelText: 'Leírás'),
),
const SizedBox(
height: 20,
),
TextField(
controller: gpsHeightController,
autofocus: true,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
border: OutlineInputBorder(), labelText: 'GPS magasság'),
),
],
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
OutlinedButton(
style: OutlinedButton.styleFrom(
minimumSize: const Size(120.0, 40.0)),
child: const Text(
"Mégsem",
style: TextStyle(color: Colors.red),
),
onPressed: () {
Get.back();
},
),
OutlinedButton(
style: OutlinedButton.styleFrom(
minimumSize: const Size(120.0, 40.0)),
child: const Text(
"Ment",
style: TextStyle(
color: Colors.green, fontWeight: FontWeight.bold),
),
onPressed: () async {
pointId = int.parse(pointIdController.text);
pointWithDescriptionList.add(PointWithDescription(
pointId,
gpsDateTime.value,
pointDescriptionController.text,
eov.value.Y,
eov.value.X,
gpsLatitude.value,
gpsLongitude.value,
max(gpsLatitudeError.value, gpsLongitudeError.value),
gpsAltitudeError.value));
print(
"pointWithDescriptionList -> ${pointWithDescriptionList.length}");
pointNotesMarker.add(Marker(
point: LatLng(gpsLatitude.value, gpsLongitude.value),
width: 15.0,
height: 15.0,
child: Container(
width: 15.0,
height: 15.0,
decoration: BoxDecoration(
color: Colors.amber[700],
shape: BoxShape.circle,
border:
Border.all(width: 1.0, color: Colors.black)),
)));
await dataFile.writeAsString(
"$pointId;$gpsDateTime;${pointDescriptionController.text};${formatEovForFile.format(eov.value.Y)};${formatEovForFile.format(eov.value.X)};$gpsLatitude;$gpsLongitude;$gpsAltitude;${max(gpsLatitudeError.value, gpsLongitudeError.value)};$gpsAltitudeError;${gpsHeightController.text}\r\n",
mode: FileMode.append);
_measuredPoints.add({
"id": pointId,
"dateAndTime": gpsDateTime.value,
"latitude": gpsLatitude.value,
"longitude": gpsLongitude.value,
"altitude": gpsAltitude.value,
"eovY": formatEovForFile.format(eov.value.Y),
"eovX": formatEovForFile.format(eov.value.X),
"description": pointDescriptionController.text,
"horizontalError":
max(gpsLatitudeError.value, gpsLongitudeError.value),
"verticalError": gpsAltitudeError.value,
"gpsHeight": gpsHeightController.text
});
await Supabase.instance.client
.from('TerepiSeged_MeasuredPoints')
.insert({
'pointNumber': pointId,
'gnssNumber': gpsName.value,
'latitude': gpsLatitude.value,
'longitude': gpsLongitude.value,
'altitude': gpsAltitude.value,
'heightOfGeoid': gpsGeoidSeparation.value,
'eovX': eov.value.X,
'eovY': eov.value.Y,
'poleHeight': double.tryParse(gpsHeightController.text),
'horizontalError':
max(gpsLatitudeError.value, gpsLongitudeError.value),
'verticalError': gpsAltitudeError.value,
'description': pointDescriptionController.text,
'isDeleted': false,
'projectId': 2
});
await Supabase.instance.client
.from('TerepiSeged_Receiver')
.update({'isMeasured': true}).eq(
'pointNumber', pointId);
if (pointMeasuringDirectionForward.isTrue) {
if (pointsToMeasureSelectedValue.value <
pointsToMeasure.length - 1) {
pointId++;
pointsToMeasureSelectedValue.value += 1;
noMorePoint = false;
} else {
noMorePoint = true;
// Get.snackbar("Információ", "Nincs több bemérendő pont.",
// colorText: Colors.white,
// backgroundColor: Colors.lightBlue);
ScaffoldMessenger.of(Get.context!).showSnackBar(
const SnackBar(
content: Text('Nincs több bemérendő pont.')));
}
} else {
if (pointsToMeasureSelectedValue.value > 0) {
pointId--;
pointsToMeasureSelectedValue.value -= 1;
noMorePoint = false;
} else {
noMorePoint = true;
ScaffoldMessenger.of(Get.context!).showSnackBar(
const SnackBar(
content: Text('Nincs több bemérendő pont.')));
}
}
Get.back();
},
),
],
)
],
),
barrierDismissible: false,
);
}
}
void sendGgaMessage(String ggaMessage) {
if (ntripIsConnected.value && ggaMessage.isNotEmpty) {
socket.add(_convertStringToUint8List("$ggaMessage\r\n"));
}
}
void setIsMapMoveToCenter() {
isMapMoveToCenter.value = !isMapMoveToCenter.value;
// onBottomNavigationBarTap(0);
}
void ReadPointsFromFile() async {
File? file;
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
file = File(result.files.single.path!);
} else {
print("No file selected");
}
if (await file!.exists()) {
pointsToMeasure.clear();
final content = await file.readAsLines();
print('Length: -> ${content.length}');
for (final (index, item) in content.indexed) {
if (index == 0) {
continue;
}
var items = item.split(";");
if (items.length >= 3) {
var id = int.tryParse(items[0]);
var coordX = double.tryParse(items[1].replaceAll(',', '.'));
var coordY = double.tryParse(items[2].replaceAll(',', '.'));
if (id != null && coordX != null && coordY != null) {
pointsToMeasure
.add(PointToMeasure(id: id, coordX: coordX, coordY: coordY));
var eovCoord = proj4.Point(x: coordX, y: coordY);
var wgsCoord = eovProj.transform(wgsProj, eovCoord);
print("Lat -> ${wgsCoord.x}, Long -> ${wgsCoord.y}");
pointsToMeasureMarker.add(Marker(
point: LatLng(wgsCoord.y, wgsCoord.x),
width: 15.0,
height: 15.0,
child: Container(
width: 15.0,
height: 15.0,
decoration: BoxDecoration(
color: Colors.purple,
shape: BoxShape.circle,
border: Border.all(width: 1.0, color: Colors.black)),
)));
pointsToMeasureLabel.add(PolyWidget(
center: LatLng(wgsCoord.y + 0.0000075, wgsCoord.x + 0.0000075),
widthInMeters: 3,
heightInMeters: 3,
// constraints: const BoxConstraints(
// minWidth: 250,
// maxWidth: 350,
// ),
child: FittedBox(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
' $id ',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.yellow,
fontSize: 12.0),
),
),
)));
pointsToMeasureDropDownMenuItem.add(DropdownMenuItem<int>(
value: index - 1,
child: Text('$id'),
));
}
}
}
pointsToMeasureSelectedValue.value = 0;
print('Converted points number -> ${pointsToMeasure.length}');
}
}
void readPointsFromSupa() async {
// final AuthResponse res = await Supabase.instance.client.auth
// .signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
// final Session? session = res.session;
// final User? user = res.user;
final data =
await Supabase.instance.client.from('TerepiSeged_Receiver').select();
print('supa count ->${data.length}');
for (int i = 0; i < data.length; i++) {
var items = data[i];
if (items.length >= 3) {
var id = items['pointNumber'];
num numEovX = items['eovX'];
var coordX = numEovX.toDouble();
num numEovY = items['eovY'];
var coordY = numEovY.toDouble();
if (id != null && coordX != null && coordY != null) {
pointsToMeasure
.add(PointToMeasure(id: id, coordX: coordX, coordY: coordY));
var eovCoord = proj4.Point(x: coordX, y: coordY);
var wgsCoord = eovProj.transform(wgsProj, eovCoord);
print("Lat -> ${wgsCoord.x}, Long -> ${wgsCoord.y}");
pointsToMeasureMarker.add(Marker(
point: LatLng(wgsCoord.y, wgsCoord.x),
width: 15.0,
height: 15.0,
child: Container(
width: 15.0,
height: 15.0,
decoration: BoxDecoration(
color: Colors.purple,
shape: BoxShape.circle,
border: Border.all(width: 1.0, color: Colors.black)),
)));
pointsToMeasureLabel.add(PolyWidget(
center: LatLng(wgsCoord.y + 0.0000075, wgsCoord.x + 0.0000075),
widthInMeters: 3,
heightInMeters: 3,
// constraints: const BoxConstraints(
// minWidth: 250,
// maxWidth: 350,
// ),
child: FittedBox(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
' $id ',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.yellow,
fontSize: 12.0),
),
),
)));
pointsToMeasureDropDownMenuItem.add(DropdownMenuItem<int>(
value: i,
child: Text('$id'),
));
}
}
}
pointsToMeasureSelectedValue.value = 0;
print('Converted points number -> ${pointsToMeasure.length}');
}
void pointsToMeasureSelectedValueChanged(int value) {
pointsToMeasureSelectedValue.value = value;
print('Selected point -> ${pointsToMeasureSelectedValue.value}');
}
double calculateDistance(LatLng start, LatLng end) {
const double earthRadius = 6371.0; // Radius of the Earth in kilometers
// Convert coordinates to radians
final double lat1 = start.latitude * (pi / 180.0);
final double lon1 = start.longitude * (pi / 180.0);
final double lat2 = end.latitude * (pi / 180.0);
final double lon2 = end.longitude * (pi / 180.0);
// Calculate the differences between the coordinates
final double dLat = lat2 - lat1;
final double dLon = lon2 - lon1;
// Apply the Haversine formula
final double a = sin(dLat / 2) * sin(dLat / 2) +
cos(lat1) * cos(lat2) * sin(dLon / 2) * sin(dLon / 2);
final double c = 2 * atan2(sqrt(a), sqrt(1 - a));
final double distance = earthRadius * c;
return distance; // Distance in kilometers, add "*1000" to get meters
}
void addMeasuredPoint() {
_measuredPoints.add({"id": 4001, "latitude": 46.3455, "longitude": 19.652});
}
void showAddPointDialog() {
onBottomNavigationBarTap(0);
}
void saveGpsAddress(String address) {
prefs.setString('gpsAddress', address);
}
void saveGpsName(String name) {
prefs.setString('gpsName', name);
}
void saveNtripUserName(String username) {
prefs.setString('ntripUserName', username);
}
void saveNtripPassword(String password) {
prefs.setString('ntripPassword', password);
}
void updatePointStatus(int pointId) {}
void toggleShowPassword() {
isShowPassword.value = !isShowPassword.value;
if (passwordFieldFocusNode.hasPrimaryFocus) return;
passwordFieldFocusNode.canRequestFocus = false;
}
void showMeasuredPointsTableDialog() {
Get.to(() => MeasuredPointsTableDialog(), transition: Transition.fadeIn);
}
Future<List> readMeasuredPoints() async {
var response = await Supabase.instance.client
.from('TerepiSeged_MeasuredPoints')
.select()
.eq('projectId', 2)
.order('created_at');
print(response);
return response;
}
void SaveMeasuredPointsToFile() async {
// var pointsDirectory = await getExternalStorageDirectory();
var pointsDirectory = await getApplicationDocumentsDirectory();
print(directory!.path);
// String newPath = '';
// List<String> folders = directory!.path.split("/");
// for (int i = 1; i < folders.length; i++) {
// String folder = folders[i];
// if (folder != "Android") {
// newPath += "/" + folder;
// } else {
// break;
// }
// }
// newPath = newPath + "/TerepisSegedApp";
// directory = Directory(newPath);
if (!await pointsDirectory!.exists()) {
await pointsDirectory.create(recursive: true);
}
var oldMeasuredPointsFile = File("${directory!.path}/measuredsPoints.csv");
if (await oldMeasuredPointsFile.exists()) {
await oldMeasuredPointsFile.delete();
}
var measuredPointsFile =
await File("${directory!.path}/measuredsPoints.csv").create();
if (await pointsDirectory.exists()) {
if (await measuredPointsFile.exists()) {
await measuredPointsFile.writeAsString(
"Id;DateTime;Description;EovX;EovY;Altitude;Hor.Err;Vert.Err\r\n");
}
}
var data = await readMeasuredPoints();
data.forEach((d) {
measuredPointsFile.writeAsStringSync(
"${d['id']};${d['created_at']};${d['description']};${formatEov.format(d['eovY'])};${formatEov.format(d['eovX'])};${formatEovZ.format(d['altitude'] - d['poleHeight'])};${formatAltitudeError.format(d['horizontalError'])};${formatAltitudeError.format(d['verticalError'])}\r\n",
flush: true,
mode: FileMode.append,
encoding: utf8);
});
print('Number of data: ${data.length}');
final params = ShareParams(
text: "Mérési eredmények",
// files: [XFile('$measuredPointsFile')],
files: [XFile("${directory!.path}/measuredsPoints.csv")],
subject: 'Mérési eredmények',
title: 'Mérési eredmények');
final result = await SharePlus.instance.share(params);
}
}