plug_location.dart 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import 'dart:async';
  2. import 'package:grpc/grpc.dart';
  3. import 'package:trackoffical_app/logger.dart';
  4. import 'package:trackoffical_app/service/api.dart';
  5. import 'package:trackoffical_app/service/app.dart';
  6. import 'package:trackoffical_app/service/game/game_model.dart';
  7. import 'package:trackoffical_app/utils.dart';
  8. import 'package:simple_kalman/simple_kalman.dart';
  9. import '../../model/game_map.dart';
  10. import '../../model/m_position.dart';
  11. import 'plug.dart';
  12. import 'package:get/get.dart';
  13. import 'package:trackoffical_app/pb.dart' as pb;
  14. class PlugLocation extends Plug {
  15. StreamSubscription<MPosition>? _locationSubscription;
  16. final GameModel _model = Get.find();
  17. final GameMap _gameMap;
  18. final kalmanLat = SimpleKalman(errorMeasure: 360, errorEstimate: 150, q: 0.9);
  19. final kalmanLon = SimpleKalman(errorMeasure: 360, errorEstimate: 150, q: 0.9);
  20. final _toUpload = <MPosition>[];
  21. PlugLocation({
  22. required GameMap gameMap,
  23. required List<pb.GameGpsInfo> lastInfo,
  24. }) : _gameMap = gameMap
  25. {
  26. if(lastInfo.isNotEmpty){
  27. for(var one in lastInfo){
  28. var p = MPosition();
  29. p.latitude = one.latitude;
  30. p.longitude = one.longitude;
  31. p.directionRadian = one.directionRadian;
  32. p.timestamp = one.gpsTime.toModel();
  33. _addOnePosition(p);
  34. }
  35. }
  36. }
  37. final ApiService _api = Get.find();
  38. var _lastPositionTime = DateTime(2000);
  39. final _app = App.to;
  40. @override
  41. Future<void> init() async {
  42. // await setLocationSettings(
  43. // askForGooglePlayServices: false,
  44. // askForPermission: true,
  45. // useGooglePlayServices: false,
  46. // accuracy: LocationAccuracy.high,
  47. // interval: 500,
  48. // askForGPS: true
  49. // );
  50. //
  51. // final locationStream = onLocationChanged();
  52. final locationStream = _app.locationStream;
  53. _app.locationStart(500.milliseconds, 0);
  54. _locationSubscription?.cancel();
  55. _locationSubscription = locationStream.listen((event) {
  56. onRcvPosition(event);
  57. // final lat = event.latitude;
  58. // final lon = event.longitude;
  59. // if (lat != null && lon != null) {
  60. // final p = MPosition(latitude: lat, longitude: lon);
  61. // p.timestamp = _app.now;
  62. // onRcvPosition(p);
  63. // }
  64. });
  65. final lastPosition = _model.myPosition.value;
  66. if (lastPosition != null) {
  67. _gameMap
  68. .worldToPixel(lastPosition)
  69. .then((value) => _model.myPositionOnMap.value = value);
  70. }
  71. loopUploadPosition();
  72. }
  73. void _addOnePosition(MPosition p){
  74. if (_model.myPositionHistory.isNotEmpty) {
  75. final lastP = _model.myPositionHistory.last;
  76. final dis = p.distance(lastP);
  77. _model.myPositionHistoryLen.value += dis;
  78. }
  79. _model.myPositionHistory.add(p);
  80. }
  81. void onRcvPosition(MPosition p) {
  82. p.directionRadian = -_model.compassRadiansFused.value;
  83. // // 卡尔曼
  84. // if(_isFirstP){
  85. // for(var i = 0; i<10; i++){
  86. // p.latitude = kalmanLat.filtered(p.latitude);
  87. // p.longitude = kalmanLon.filtered(p.longitude);
  88. // }
  89. // _isFirstP=false;
  90. // }
  91. //
  92. // p.latitude = kalmanLat.filtered(p.latitude);
  93. // p.longitude = kalmanLon.filtered(p.longitude);
  94. // info('${p.latitude} ${p.longitude}');
  95. _model.myPosition.value = p;
  96. _model.myPositionHistoryTmp.add(p);
  97. if(_model.myPositionHistoryTmp.length>=20){
  98. _model.myPositionHistoryTmp.removeAt(0);
  99. }
  100. _toUpload.add(p);
  101. _gameMap
  102. .worldToPixel(p)
  103. .then((value) => _model.myPositionOnMap.value = value);
  104. // final pTest = MPosition( latitude: 36.649713,
  105. // longitude:117.052860,);
  106. _gameMap.mapPackage?.isInHotZone(p).then((value) =>
  107. _model.zone.value=value
  108. );
  109. if (_model.isStarted && (!_model.isFinish)) {
  110. final now = DateTime.now();
  111. if (now.difference(_lastPositionTime) > 1.seconds) {
  112. _addOnePosition(p);
  113. _model.gameSrcState.value.pbGameSave.gameGpsInfos.add(p.toPb2());
  114. _lastPositionTime = now;
  115. }
  116. }
  117. }
  118. Future<void> loopUploadPosition() async {
  119. while (isActive) {
  120. await Future.delayed(1.seconds);
  121. await uploadPosition();
  122. }
  123. }
  124. Future<void> uploadPosition() async {
  125. final gameId = _model.gameSrcState.value.pbGameData.gameId;
  126. final data = <MPosition>[];
  127. final distanceMeter = _model.myPositionHistoryLen.value.m;
  128. final paceSecondKm = _model.paceSecondKm;
  129. if(_toUpload.isNotEmpty){
  130. data.addAll(_toUpload);
  131. try {
  132. await _api.gameGpsUpload(
  133. gameId, data, distanceMeter.round(), paceSecondKm.value.inSeconds);
  134. _toUpload.clear();
  135. } catch (e) {
  136. warn('GameId[$gameId]上传位置失败: $e');
  137. }
  138. }
  139. }
  140. Future<void> _makeSureUploadAll() async {
  141. while (true) {
  142. try {
  143. await uploadPosition();
  144. return;
  145. } on GrpcError catch (e) {
  146. if (e.code != StatusCode.unavailable) {
  147. return;
  148. }
  149. error(e);
  150. } catch (e) {
  151. error(e);
  152. return;
  153. }
  154. await Future.delayed(100.milliseconds);
  155. }
  156. }
  157. @override
  158. Future<void> close() async {
  159. await _makeSureUploadAll();
  160. super.close();
  161. _app.locationStop();
  162. _locationSubscription?.cancel();
  163. _locationSubscription = null;
  164. debug('[位置插件]已关闭');
  165. }
  166. }