| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- import 'dart:async';
- import 'dart:math';
- import 'dart:typed_data';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- import 'package:trackoffical_app/logger.dart';
- import 'package:trackoffical_app/model/game_map.dart';
- import 'package:trackoffical_app/service/app.dart';
- import 'package:trackoffical_app/service/game/game_model.dart';
- import 'package:vibration/vibration.dart';
- import '../../model/map_mode.dart';
- import '../../widget/matrix_gesture_detector.dart';
- import 'package:vector_math/vector_math_64.dart' as vec;
- class MapStatus {
- var canVibrate = false;
- var mapImageData = Uint8List(0).obs;
- var gameMapData = GameMap();
- final GameModel _model = Get.find();
- Rx<Matrix4> get matrix => _model.mapTransformMatrix;
- Rx<MapMode> get mapMode => _model.mapMode;
- double get compassAngle => _model.compassRadiansFused.value;
- var lastCompassRadians = 0.0;
- var vibrateAccumulation = 0.0;
- var isTouching = false;
- double picFirstScale = 1;
- var isSetBeginMatrix = false;
- final isShowMapScale = false.obs;
- Timer? _showMapScaleTimer;
- double _mapLenMeter=1;
- // 比例尺 屏幕尺寸/米 实时
- final mapScale = 0.0.obs;
- // 比例尺 屏幕尺寸/米 原始
- var mapScaleSrc = 0.0;
- double get rotateRadian {
- final ogRm = matrix.value.clone();
- double radian = MatrixGestureDetector.decomposeToValues(ogRm).rotation;
- return radian;
- }
- double get compassPlantRadian =>_model.compassPlantRadian;
- final _translationUpdater = _ValueUpdater<Offset>(
- onUpdate: (oldVal, newVal) => newVal - (oldVal ?? Offset.zero),
- );
- final _rotationUpdater = _ValueUpdater<double>(
- onUpdate: (oldVal, newVal) => newVal - (oldVal ?? 0),
- );
- final _scaleUpdater = _ValueUpdater<double>(
- onUpdate: (oldVal, newVal) => newVal / (oldVal ?? 1),
- );
- Future<void> resetMatrix() async{
- matrix.value = Matrix4.identity();
- lastCompassRadians = 0.0;
- _rotationUpdater.value = 0;
- _translationUpdater.value = Offset.zero;
- _scaleUpdater.value = 1;
- isSetBeginMatrix=false;
- matrix.value = _doScale(4, matrix.value);
- const p0Src = Offset(0, 0);
- final p1Src = Offset(gameMapData.width, 0);
- final mapTopLeftLocation = await gameMapData.pixelToWorld(p0Src);
- final mapTopRightLocation = await gameMapData.pixelToWorld(p1Src);
- final disKm = mapTopLeftLocation.distance(mapTopRightLocation);
- _mapLenMeter = disKm.km;
- final screenLen = App.to.screenSize.width;
- mapScaleSrc = screenLen / _mapLenMeter;
- calculateMapScale();
- }
- Offset picOffsetToScreen(Offset offset){
- var thisOffset = Offset(offset.dx * picFirstScale, offset.dy * picFirstScale);
- final mr= matrix.value.applyToVector3Array([thisOffset.dx, thisOffset.dy, 0]);
- return Offset(mr[0], mr[1]);
- }
- void movePicPointTo(Offset src, Offset dst){
- final pOnScreen = picOffsetToScreen(src);
- final dis = dst - pOnScreen;
- final tranM = Matrix4.translationValues(dis.dx, dis.dy, 0);
- matrix.value = tranM * matrix.value;
- }
- Matrix4? _getRotationMatrix(
- double radiansDelta,
- Offset focalPoint,
- {bool willVibrate=false}) {
- if (_rotationUpdater.value == null || _rotationUpdater.value!.isNaN) {
- _rotationUpdater.value = radiansDelta;
- } else {
- final rotationDelta = _rotationUpdater.update(radiansDelta);
- var c = cos(rotationDelta);
- var s = sin(rotationDelta);
- var dx = (1 - c) * focalPoint.dx + s * focalPoint.dy;
- var dy = (1 - c) * focalPoint.dy - s * focalPoint.dx;
- final rotationDeltaMatrix = Matrix4(
- c, s, 0, 0,
- -s, c, 0, 0,
- 0, 0, 1, 0,
- dx, dy, 0, 1);
- if(willVibrate){
- vibrateAccumulation += vec.degrees(rotationDelta);
- if (vibrateAccumulation.abs() >= 5) {
- vibrateAccumulation = 0;
- if (canVibrate) {
- Vibration.vibrate(duration: 20, repeat: 1);
- }
- }
- }
- return rotationDeltaMatrix;
- }
- return null;
- }
- void setRotate(double radians) {
- final focalPoint = _model.mapRotateCenter;
- if(focalPoint != null){
- final rotate = _getRotationMatrix(radians, focalPoint);
- if(rotate!= null){
- var matrix = this.matrix.value;
- this.matrix.value = rotate * matrix;
- }
- }
- }
- void mapModeSwitch() {
- resetMatrix();
- switch (mapMode.value) {
- case MapMode.original:
- mapMode.value = MapMode.compass;
- break;
- case MapMode.compass:
- mapMode.value = MapMode.original;
- break;
- }
- }
- void onMapTouchScaleStart(ScaleStartDetails details) {
- isTouching=true;
- _translationUpdater.value = details.focalPoint;
- _rotationUpdater.value = double.nan;
- _scaleUpdater.value = 1.0;
- }
- Matrix4 _doScale(double scaleDelta, Matrix4 matrix){
- final focalPoint = _model.mapRotateCenter!;
- var dx = (1 - scaleDelta) * focalPoint.dx;
- var dy = (1 - scaleDelta) * focalPoint.dy;
- final scaleDeltaMatrix = Matrix4(
- scaleDelta, 0, 0, 0,
- 0, scaleDelta, 0, 0,
- 0, 0, 1, 0,
- dx, dy, 0, 1);
- return scaleDeltaMatrix * matrix;
- }
- void onMapTouchScaleUpdate(ScaleUpdateDetails details, Size screen) {
- final focalPoint = _model.mapRotateCenter!;
- var matrix = this.matrix.value;
- // 平移
- if(!_model.isLockScreenCenterToMyPositionSystem){
- final translationDelta = _translationUpdater.update(details.focalPoint);
- final translationDeltaMatrix =
- Matrix4.translationValues(translationDelta.dx, translationDelta.dy, 0);
- matrix = translationDeltaMatrix * matrix;
- }
- // 缩放
- final scale = matrix[0].abs();
- if (details.scale != 1.0) {
- final zoomOutLimit = scale > 0.5 || details.scale > 1;
- // final zoomInLimit = scale < 8 || details.scale < 1;
- final zoomInLimit = mapScale < 1.7 || details.scale < 1;
- if(zoomOutLimit && zoomInLimit){
- final scaleDelta = _scaleUpdater.update(details.scale);
- matrix = _doScale(scaleDelta, matrix);
- }
- }
- // 旋转
- var rotationDelta = 0.0;
- var willVibrate = false;
- switch (mapMode.value) {
- case MapMode.original:
- rotationDelta = details.rotation;
- willVibrate = true;
- break;
- case MapMode.compass:
- break;
- }
- if(rotationDelta != 0){
- final rotationDeltaMatrix = _getRotationMatrix(
- rotationDelta, focalPoint, willVibrate: willVibrate);
- if(rotationDeltaMatrix!= null){
- matrix = rotationDeltaMatrix * matrix;
- }
- }
- this.matrix.value = matrix;
- calculateMapScale();
- }
- calculateMapScale(){
- const p0Src = Offset(0, 0);
- final p1Src = Offset(gameMapData.width, 0);
- final p0Dst = picOffsetToScreen(p0Src);
- final p1Dst = picOffsetToScreen(p1Src);
- final disPx = sqrt((p1Dst.dx - p0Dst.dx)* (p1Dst.dx - p0Dst.dx)
- + (p1Dst.dy - p0Dst.dy) * (p1Dst.dy - p0Dst.dy));
- final scale = disPx / _mapLenMeter;
- mapScale.value = scale;
- isShowMapScale.value = true;
- _showMapScaleTimer?.cancel();
- _showMapScaleTimer = Timer(3.seconds, () {
- isShowMapScale.value = false;
- });
- }
- }
- typedef _OnUpdate<T> = T Function(T? oldValue, T newValue);
- class _ValueUpdater<T> {
- final _OnUpdate<T> onUpdate;
- T? value;
- _ValueUpdater({required this.onUpdate});
- T update(T newValue) {
- T updated = onUpdate(value, newValue);
- value = newValue;
- return updated;
- }
- }
|