344 lines
8.3 KiB
Dart
344 lines
8.3 KiB
Dart
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++;
|
||
}
|
||
}
|