Files
flutterApp/lib/features/home/presentation/widgets/common/tracepoint.dart
2026-04-15 16:38:54 +08:00

312 lines
7.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'dart:async';
// ======================== 枚举定义 ========================
/// 轨迹模式枚举
enum TPMode {
NAVIGATION, // 导航模式:绘制规划已完成路径和当前路径
LOCATION, // 定位模式:仅绘制当前点(永远只有1个)
TRACK, // 轨迹模式:实时绘制历史轨迹
}
/// 导航模式下的操作动作枚举
enum TPAction {
UPDATE, // 更新当前点
ADD, // 添加完成点
}
// ======================== 尝试锁实现 ========================
class TryLock {
bool _locked = false;
bool tryLock() {
if (_locked) return false;
_locked = true;
return true;
}
void release() {
_locked = false;
}
bool get isLocked => _locked;
}
// ======================== 环形队列实现 ========================
class CircQueue<T> {
final int capacity;
final List<T?> buffer;
int head = 0;
int tail = 0;
bool isFull = false;
final bool deepCopy;
final int maxMemoryBytes;
int currentMemoryBytes = 0;
CircQueue(this.capacity, {this.deepCopy = true, this.maxMemoryBytes = 1024 * 1024}) : buffer = List<T?>.filled(capacity, null);
void clear() {
head = tail;
isFull = false;
currentMemoryBytes = 0;
}
bool isEmpty() {
return head == tail && !isFull;
}
bool isFullFn() {
return isFull;
}
int _estimateSize(T item) {
try {
return utf8.encode(jsonEncode(item)).length;
} catch (e) {
return 0;
}
}
T? _deepClone(T? item) {
if (!deepCopy || item == null) return item;
try {
return jsonDecode(jsonEncode(item)) as T;
} catch (e) {
return item;
}
}
bool enter(T item) {
final itemSize = _estimateSize(item);
if (isFullFn() || (currentMemoryBytes + itemSize > maxMemoryBytes)) {
return false;
}
final clone = _deepClone(item);
buffer[tail] = clone;
tail = (tail + 1) % capacity;
currentMemoryBytes += itemSize;
if (tail == head) isFull = true;
return true;
}
T? out() {
if (isEmpty()) return null;
final item = buffer[head];
if (item != null) {
currentMemoryBytes -= _estimateSize(item);
}
head = (head + 1) % capacity;
isFull = false;
return _deepClone(item);
}
bool discard(int len) {
for (int i = 0; i < len; i++) {
if (isEmpty()) return false;
final index = (tail - 1 + capacity) % capacity;
final item = buffer[index];
if (item != null) {
currentMemoryBytes -= _estimateSize(item);
}
tail = index;
isFull = false;
}
return true;
}
int getDepth() {
return isFull ? capacity : (tail + capacity - head) % capacity;
}
Future<bool> send(T item, {int timeoutMs = 0}) async {
final start = DateTime.now().millisecondsSinceEpoch;
while (!enter(item)) {
if (timeoutMs > 0 && DateTime.now().millisecondsSinceEpoch - start >= timeoutMs) {
return false;
}
await Future.delayed(const Duration(milliseconds: 1));
}
return true;
}
Future<T?> recv({int timeoutMs = 0}) async {
final start = DateTime.now().millisecondsSinceEpoch;
while (true) {
final item = out();
if (item != null) return item;
if (timeoutMs > 0 && DateTime.now().millisecondsSinceEpoch - start >= timeoutMs) {
return null;
}
await Future.delayed(const Duration(milliseconds: 1));
}
}
List<T?> toList() {
final result = <T?>[];
int i = head;
int count = getDepth();
while (count-- > 0) {
result.add(_deepClone(buffer[i]));
i = (i + 1) % capacity;
}
return result;
}
}
class TracePoint<T> {
late final CircQueue<T> _queue;
List<T> _tracePoint = [];
int _completePointIndex = 0;
late final TryLock _lock;
TPMode _mode = TPMode.LOCATION;
void Function(T)? onCurrentPointUpdated;
void Function(T)? onCompletePointAdded;
bool tryLock() => _lock.tryLock();
void release() => _lock.release();
TracePoint({int queueCapacity = 5, int maxMemoryBytes = 1024 * 1024}) {
_queue = CircQueue<T>(queueCapacity, deepCopy: true, maxMemoryBytes: maxMemoryBytes);
_lock = TryLock();
reset();
}
/// 复位所有状态
void reset() {
_queue.clear();
_tracePoint.clear();
_completePointIndex = 0;
_lock.release();
}
/// 设置模式
void setMode(TPMode mode) {
reset();
_mode = mode;
}
TPMode getMode() {
return _mode;
}
/// 添加/更新轨迹点
void upsert(T point, [TPAction act = TPAction.UPDATE]) {
// 严格按模式分发
switch (_mode) {
case TPMode.NAVIGATION:
if (act == TPAction.UPDATE) {
_updateCurrentPoint(point);
} else {
_addCompletePoint(point);
}
break;
case TPMode.LOCATION:
// LOCATION 永远只保留最新一个点
_updateCurrentPoint(point);
break;
case TPMode.TRACK:
// TRACK 每个点都直接添加,不进队列
_addCompletePoint(point);
break;
}
}
/// 获取轨迹列表
List<T>? getTracePoint() {
if (_lock.tryLock()) {
final trace = List<T>.from(_tracePoint);
_lock.release();
return trace;
} else {
print('getTracePoint: lock!!!');
return null;
}
}
/// 更新当前点(LOCATION 永远只有1个)
void _updateCurrentPoint(T point) {
if (_lock.tryLock()) {
try {
switch (_mode) {
case TPMode.NAVIGATION:
if (_tracePoint.isNotEmpty) {
_tracePoint = _tracePoint.sublist(0, _completePointIndex);
_tracePoint.add(point);
onCurrentPointUpdated?.call(point);
}
break;
case TPMode.LOCATION:
// 核心:永远清空,只保留最新一个
_tracePoint.clear();
_tracePoint.add(point);
onCurrentPointUpdated?.call(point);
break;
default:
break;
}
} finally {
_lock.release();
}
}
}
/// 添加完成点
void _addCompletePoint(T point) {
if (_lock.tryLock()) {
try {
// 先消费队列
while (!_queue.isEmpty()) {
final queuedPoint = _queue.out();
if (queuedPoint != null) {
_addPoint(queuedPoint);
}
}
// 添加当前点
_addPoint(point);
onCompletePointAdded?.call(point);
} catch (e) {
print('addCompletePoint failure: $e');
} finally {
_lock.release();
}
} else {
if (_mode != TPMode.TRACK) {
// TRACK 模式不加队列,直接丢弃旧的保证流畅
_queue.enter(point);
}
print('addCompletePoint: lock!!!');
}
}
/// 内部添加点
void _addPoint(T point) {
if (_mode == TPMode.LOCATION) {
// LOCATION 强制只保留1个
_tracePoint.clear();
_tracePoint.add(point);
_completePointIndex = 1;
return;
}
final hasCurrent = _tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length;
if (hasCurrent) {
_tracePoint = _tracePoint.sublist(0, _completePointIndex);
_tracePoint.add(point);
} else {
_tracePoint.add(point);
}
_completePointIndex++;
}
}