Files
flutterApp/lib/features/home/presentation/widgets/common/tracepoint.dart
2026-02-26 14:08:02 +08:00

344 lines
8.3 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, // 定位模式:仅绘制当前点
TRACK, // 轨迹模式:实时绘制历史轨迹
}
/// 导航模式下的操作动作枚举
enum TPAction {
UPDATE, // 更新当前点
ADD, // 添加完成点
}
// ======================== 尝试锁实现 ========================
class TryLock {
bool _locked = false;
/// 尝试获取锁
/// return: true-获取成功,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, // 默认1MB
}) : buffer = List<T?>.filled(capacity, null);
/// 清空队列
void clear() {
head = tail;
isFull = false;
currentMemoryBytes = 0;
}
/// 判断队列是否为空
bool isEmpty() {
return head == tail && !isFull;
}
/// 判断队列是否已满
bool isFullFn() {
return isFull;
}
/// 估算对象大小(JSON序列化后的字节长度)
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 = [];
_completePointIndex = 0;
_lock.release();
}
/// 设置工作模式
void setMode(TPMode mode) {
reset();
_mode = mode;
}
/// 添加/更新轨迹点
void upsert(T point, [TPAction act = TPAction.UPDATE]) {
switch (_mode) {
case TPMode.NAVIGATION:
act == TPAction.UPDATE
? _updateCurrentPoint(point)
: _addCompletePoint(point);
break;
case TPMode.LOCATION:
_updateCurrentPoint(point);
break;
case TPMode.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;
}
}
/// 更新当前点(私有方法)
void _updateCurrentPoint(T point) {
if (point == null) {
print('updateCurrentPoint: point is NULL');
return;
}
if (_lock.tryLock()) {
try {
switch (_mode) {
case TPMode.NAVIGATION:
if (_tracePoint.isEmpty) {
print(
'updateCurrentPoint: tracePoint is empty , wait first completed point, discard current point: $point',
);
} else {
_tracePoint = _tracePoint.sublist(0, _completePointIndex);
_tracePoint.add(point);
// 触发公开的回调(无下划线)
onCurrentPointUpdated?.call(point);
}
break;
case TPMode.LOCATION:
if (_tracePoint.isEmpty) {
_tracePoint.add(point);
} else {
_tracePoint[0] = point;
}
// 触发公开的回调(无下划线)
onCurrentPointUpdated?.call(point);
break;
default:
break;
}
} finally {
_lock.release();
}
} else {
print('updateCurrentPoint: lock!!!, discard current point: $point');
}
}
/// 添加完成点(私有方法)
void _addCompletePoint(T point) {
if (point == null) {
print('addCompletePoint: point is NULL');
return;
}
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 {
_queue.enter(point);
print('addCompletePoint: lock!!!, enter queue, wait disposing: $point');
}
}
/// 内部添加点逻辑(私有方法)
void _addPoint(T point) {
if (point == null) {
print('point NULL:');
return;
}
final hasCurrentPoint =
_tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length;
if (hasCurrentPoint) {
_tracePoint = _tracePoint.sublist(0, _completePointIndex);
_tracePoint.insert(_completePointIndex, point);
} else {
_tracePoint.add(point);
}
_completePointIndex++;
}
}