修复障碍物打点
This commit is contained in:
@@ -593,21 +593,23 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
setState(() {
|
||||
// 1. 作业区域模式
|
||||
if (_currentAreaMode == AreaMode.work) {
|
||||
if (_currentRobotMode == RobotMode.robot && _robotModeWgsPoints.isNotEmpty && _markedPoints.isNotEmpty) {
|
||||
// Robot模式撤回
|
||||
if (_markedPoints.isNotEmpty) {
|
||||
_robotModeWgsPoints.removeLast();
|
||||
_markedPoints.removeLast();
|
||||
// 作业点撤回后,若路径已生成,重新生成路径(保持同步)
|
||||
if (_isWorkAreaCompleted && _markedPoints.length >= 3) {
|
||||
_generatePath(showTips: false);
|
||||
}
|
||||
ToastUtils.showInfo(context, '已撤回Robot模式最后一个点,剩余${_robotModeWgsPoints.length}个点');
|
||||
ToastUtils.showInfo(context, '已撤回作业区域最后一个点,剩余${_markedPoints.length}个点');
|
||||
//ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已撤回作业区域最后一个点,剩余${_markedPoints.length}个点')));
|
||||
} else {
|
||||
ToastUtils.showInfo(context, '暂无作业区域点可撤回');
|
||||
//ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无作业区域点可撤回')));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 障碍物模式(逻辑不变,Robot模式下障碍物打点和Point模式一致)
|
||||
// 2. 空洞模式(完成后优先撤回已完成的空洞)
|
||||
if (_currentAreaMode == AreaMode.obstacle) {
|
||||
if (_currentObstaclePoints.isNotEmpty) {
|
||||
_currentObstaclePoints.removeLast();
|
||||
@@ -615,20 +617,28 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
if (_currentObstaclePoints.isEmpty) {
|
||||
_isObstacleEditing = false;
|
||||
}
|
||||
ToastUtils.showInfo(context, '已撤回当前障碍物最后一个点,剩余${_currentObstaclePoints.length}个点');
|
||||
return;
|
||||
ToastUtils.showInfo(context, '已撤回当前空洞最后一个点,剩余${_currentObstaclePoints.length}个点');
|
||||
|
||||
//ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已撤回当前空洞最后1个点,剩余${_currentObstaclePoints.length}个点')));
|
||||
return; // 撤完点就结束,不执行后面的逻辑
|
||||
}
|
||||
|
||||
// 第二步:当前空洞无点可撤 → 再撤回「上一个完整空洞」
|
||||
if (_obstacleHoles.isNotEmpty) {
|
||||
_obstacleHoles.removeLast();
|
||||
// 撤完空洞后重新生成路径(排除该空洞)
|
||||
if (_isWorkAreaCompleted) {
|
||||
_generatePath(showTips: false);
|
||||
}
|
||||
ToastUtils.showInfo(context, '已撤回上一个完整障碍物,剩余${_obstacleHoles.length}个障碍物');
|
||||
ToastUtils.showInfo(context, '已撤回上一个完整空洞,剩余${_obstacleHoles.length}个空洞');
|
||||
|
||||
//ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已撤回上一个完整空洞,剩余${_obstacleHoles.length}个空洞')));
|
||||
return;
|
||||
}
|
||||
|
||||
ToastUtils.showInfo(context, '暂无障碍物可撤回');
|
||||
// 第三步:无任何可撤内容
|
||||
ToastUtils.showInfo(context, '暂无空洞可撤回');
|
||||
//ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无空洞可撤回')));
|
||||
}
|
||||
});
|
||||
_saveDataToLocal();
|
||||
@@ -639,16 +649,11 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
setState(() {
|
||||
// 1. 作业区域模式:清空作业点 + 重置路径
|
||||
if (_currentAreaMode == AreaMode.work) {
|
||||
if (_currentRobotMode == RobotMode.robot) {
|
||||
_markedPoints.clear();
|
||||
ToastUtils.showSuccess(context, '已清空所有作业点');
|
||||
} else {
|
||||
// 原有Point模式清空
|
||||
if (_markedPoints.isEmpty) {
|
||||
ToastUtils.showInfo(context, '暂无作业区域点可删除');
|
||||
return;
|
||||
}
|
||||
_markedPoints.clear();
|
||||
if (_markedPoints.isEmpty) {
|
||||
ToastUtils.showInfo(context, '暂无作业区域点可删除');
|
||||
|
||||
//ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无作业区域点可删除')));
|
||||
return;
|
||||
}
|
||||
_markedPoints.clear();
|
||||
gcjPathPoints.clear();
|
||||
@@ -661,7 +666,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
|
||||
//ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有作业区域点和路径')));
|
||||
}
|
||||
// 2. 障碍物模式:清空所有障碍物 + 恢复UI + 重新生成路径
|
||||
// 2. 空洞模式:清空所有空洞 + 恢复UI + 重新生成路径
|
||||
else if (_currentAreaMode == AreaMode.obstacle) {
|
||||
if (_obstacleHoles.isEmpty && _currentObstaclePoints.isEmpty) {
|
||||
ToastUtils.showInfo(context, '暂无障碍物可删除');
|
||||
@@ -671,7 +676,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
_currentObstaclePoints.clear();
|
||||
_robotModeObsWgsPoints.clear();
|
||||
_isObstacleEditing = false;
|
||||
// 清空后重新生成路径(无障碍物)
|
||||
// 清空后重新生成路径(无空洞)
|
||||
if (_isWorkAreaCompleted) {
|
||||
_generatePath(showTips: false);
|
||||
}
|
||||
@@ -687,7 +692,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
|
||||
/// ===============================
|
||||
/// 企业级定位初始化(已修复坐标系)
|
||||
///
|
||||
Future<void> _initLocationEnterprise() async {
|
||||
// 1. 设置轨迹模式为 LOCATION(核心:确保模式正确)
|
||||
_traceManager.setMode(TPMode.LOCATION);
|
||||
@@ -800,7 +804,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
_mapController.move(_currentLatLng!, 17);
|
||||
}
|
||||
|
||||
// ========== 障碍物模式:完成当前障碍物绘制 ==========
|
||||
// ========== 障碍物模式:完成当前障碍物绘制 ==========
|
||||
void _completeObstacle() {
|
||||
if (_currentObstaclePoints.length < 3) {
|
||||
@@ -1149,12 +1152,12 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
children: [
|
||||
/// 高德瓦片(GCJ-02)
|
||||
TileLayer(
|
||||
urlTemplate:
|
||||
"https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=2&style=7&key=bbb1f0f20eed6bf679eddf2625630aba",
|
||||
// urlTemplate:
|
||||
// 'https://webrd02.is.autonavi.com/appmaptile'
|
||||
// '?style=8&x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1'
|
||||
// '&key=bbb1f0f20eed6bf679eddf2625630aba',
|
||||
//urlTemplate:
|
||||
// "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=2&style=7&key=bbb1f0f20eed6bf679eddf2625630aba",
|
||||
urlTemplate:
|
||||
'https://webrd02.is.autonavi.com/appmaptile'
|
||||
'?style=8&x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1'
|
||||
'&key=bbb1f0f20eed6bf679eddf2625630aba',
|
||||
// 🔥 修复:适配高DPI(替代pixelRatio)
|
||||
// tileSize: 512, // 高清瓦片尺寸(默认256,改为512适配scale=2)
|
||||
tileProvider: NetworkTileProvider(
|
||||
@@ -1266,7 +1269,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
//开始作业之后
|
||||
|
||||
// 2. 正在绘制的障碍物打点连线(红色虚线)
|
||||
if (_isObstacleEditing && _currentObstaclePoints.isNotEmpty && _currentRobotMode == RobotMode.point)
|
||||
if (_isObstacleEditing && _currentObstaclePoints.isNotEmpty)
|
||||
PolylineLayer(
|
||||
polylines: [
|
||||
// 已绘制的障碍物点连线
|
||||
@@ -1772,12 +1775,18 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
if (_currentRobotMode == RobotMode.robot && _robotModeWgsPoints.isNotEmpty) {
|
||||
// Robot模式:直接使用原始WGS84坐标(无需转换)
|
||||
firstPointWgs = _robotModeWgsPoints.first;
|
||||
} else {
|
||||
} else if (_currentRobotMode == RobotMode.point && _markedPoints.isNotEmpty) {
|
||||
// Point模式:先取十字准星的GCJ02坐标 → 转换为WGS84
|
||||
if (_markedPoints.isEmpty) return;
|
||||
LatLng firstPointGcj = _markedPoints.first;
|
||||
firstPointWgs = gcj02ToWgs84(firstPointGcj.latitude, firstPointGcj.longitude);
|
||||
} else {
|
||||
debugPrint('⚠️ 参考点坐标为空,无法生成路径');
|
||||
if (showTips) {
|
||||
ToastUtils.showError(context, '参考点坐标为空,请先添加作业区域打点!');
|
||||
}
|
||||
return; // 终止方法执行,避免后续错误
|
||||
}
|
||||
|
||||
// 参考点使用转换后的WGS84坐标
|
||||
final referencePoint = work_area_model.ReferencePoint(lat: firstPointWgs.latitude, lon: firstPointWgs.longitude);
|
||||
|
||||
@@ -1791,7 +1800,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
outerPositions = _robotModeWgsPoints.map((latLng) {
|
||||
return work_area_model.Position(lat: latLng.latitude, lon: latLng.longitude);
|
||||
}).toList();
|
||||
} else {
|
||||
} else if(_currentRobotMode == RobotMode.point && _markedPoints.isNotEmpty) {
|
||||
// Point模式:十字准星的GCJ02坐标 → 转换为WGS84
|
||||
outerPositions = _markedPoints.map((latLng) {
|
||||
final wgs84Point = gcj02ToWgs84(latLng.latitude, latLng.longitude);
|
||||
@@ -1807,9 +1816,10 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
|
||||
final outerBoundary = work_area_model.OuterBoundary(position: outerPositions, sideWidth: _workDistance);
|
||||
|
||||
// 2.4 障碍物处理(同样区分Robot/Point模式)
|
||||
work_area_model.HoleBoundary? holeBoundary;
|
||||
|
||||
if (_obstacleHoles.isNotEmpty) {
|
||||
// 1. 构造二维 Position 数组
|
||||
List<List<work_area_model.Position>> positionList = [];
|
||||
|
||||
if (_currentRobotMode == RobotMode.robot && _robotModeObsWgsPoints.isNotEmpty) {
|
||||
@@ -1821,43 +1831,46 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
}).toList();
|
||||
positionList.add(innerPositionList);
|
||||
}
|
||||
} else {
|
||||
for (var holePoints in _obstacleHoles) {
|
||||
} else if(_currentRobotMode == RobotMode.point && _obstacleHoles.isNotEmpty) {
|
||||
for (var holePoints in _obstacleHoles) {
|
||||
List<work_area_model.Position> innerPositionList = [];
|
||||
|
||||
// Point模式:GCJ02→WGS84转换
|
||||
innerPositionList = holePoints.map((latLng) {
|
||||
final wgs84Point = gcj02ToWgs84(latLng.latitude, latLng.longitude);
|
||||
return work_area_model.Position(lat: wgs84Point.latitude, lon: wgs84Point.longitude);
|
||||
}).toList();
|
||||
final wgs84Point = gcj02ToWgs84(latLng.latitude, latLng.longitude);
|
||||
return work_area_model.Position(lat: wgs84Point.latitude, lon: wgs84Point.longitude);
|
||||
}).toList();
|
||||
positionList.add(innerPositionList);
|
||||
}
|
||||
}
|
||||
|
||||
for (var holePoints in _obstacleHoles) {
|
||||
List<work_area_model.Position> innerPositionList = [];
|
||||
//for (var holePoints in _obstacleHoles) {
|
||||
// List<work_area_model.Position> innerPositionList = [];
|
||||
|
||||
if (_currentRobotMode == RobotMode.robot && _robotModeObsWgsPoints.isNotEmpty) {
|
||||
// Robot模式:使用障碍物原始WGS84坐标
|
||||
innerPositionList = holePoints.map((latLng) {
|
||||
return work_area_model.Position(lat: latLng.latitude, lon: latLng.longitude);
|
||||
}).toList();
|
||||
} else {
|
||||
// Point模式:GCJ02→WGS84转换
|
||||
innerPositionList = holePoints.map((latLng) {
|
||||
final wgs84Point = gcj02ToWgs84(latLng.latitude, latLng.longitude);
|
||||
return work_area_model.Position(lat: wgs84Point.latitude, lon: wgs84Point.longitude);
|
||||
}).toList();
|
||||
}
|
||||
positionList.add(innerPositionList);
|
||||
}
|
||||
// if (_currentRobotMode == RobotMode.robot && _robotModeObsWgsPoints.isNotEmpty) {
|
||||
// // Robot模式:使用障碍物原始WGS84坐标
|
||||
// innerPositionList = holePoints.map((latLng) {
|
||||
// return work_area_model.Position(lat: latLng.latitude, lon: latLng.longitude);
|
||||
// }).toList();
|
||||
// } else {
|
||||
// // Point模式:GCJ02→WGS84转换
|
||||
// innerPositionList = holePoints.map((latLng) {
|
||||
// final wgs84Point = gcj02ToWgs84(latLng.latitude, latLng.longitude);
|
||||
// return work_area_model.Position(lat: wgs84Point.latitude, lon: wgs84Point.longitude);
|
||||
// }).toList();
|
||||
// }
|
||||
// positionList.add(innerPositionList);
|
||||
//}
|
||||
|
||||
// 2. 创建 HoleBoundary 对象(无外层 Map)
|
||||
holeBoundary = work_area_model.HoleBoundary(position: positionList, sideWidth: 0.0);
|
||||
}
|
||||
|
||||
// 🔥 第二步:构造符合方法参数要求的 Map<String, HoleBoundary>
|
||||
// 用一个临时 Map 来满足类型要求,后续在 Cubit 中取值即可
|
||||
Map<String, work_area_model.HoleBoundary> holes = {};
|
||||
if (holeBoundary != null) {
|
||||
holes = {'tempKey': holeBoundary};
|
||||
holes = {'tempKey': holeBoundary}; // 键名任意,仅为满足类型要求
|
||||
}
|
||||
final workType = _currentWorkMode == WorkMode.bow ? 0 : 2;
|
||||
|
||||
@@ -1866,7 +1879,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
reference: referencePoint,
|
||||
heading: heading,
|
||||
outer: outerBoundary,
|
||||
holes: holes.isNotEmpty ? holes : {},
|
||||
holes: holes.isNotEmpty ? holes : {}, // 无障碍物时传空对象
|
||||
workType: workType,
|
||||
);
|
||||
|
||||
@@ -1877,6 +1890,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
if (cubitState.errorMessage != null) {
|
||||
if (showTips) {
|
||||
ToastUtils.showError(context, '路径生成失败:${cubitState.errorMessage}');
|
||||
//ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('路径生成失败:${cubitState.errorMessage}'), backgroundColor: Colors.red));
|
||||
}
|
||||
} else if (cubitState.generatedPath != null) {
|
||||
if (showTips) {
|
||||
@@ -1891,8 +1905,8 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
final pathList = cubitState.generatedPath as List;
|
||||
typedPathList = pathList.whereType<work_area_model.DeviceAddPathPointModel>().toList();
|
||||
debugPrint('✅ 过滤并转换后的路径点列表:typedPathList 长度=${typedPathList.length}');
|
||||
//打印
|
||||
|
||||
// 路径点转换为GCJ02(无论哪种模式,最终地图显示都需要GCJ02)
|
||||
gcjPathPoints = typedPathList.map((point) {
|
||||
double wgs84Lat = point.latitude;
|
||||
double wgs84Lon = point.longitude;
|
||||
@@ -1964,17 +1978,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
// 🔥 核心:用Transform.scale实现视觉放大1.5倍
|
||||
//Transform.scale(
|
||||
// scale: 1.5, // 放大倍数
|
||||
// // 对齐方式:以地图中心为缩放原点(避免偏移)
|
||||
// alignment: Alignment.center,
|
||||
// child: RepaintBoundary(
|
||||
// key: _mapRepaintKey,
|
||||
// // 你的地图构建方法
|
||||
// child: _buildMap(currentLat, currentLng, obfFlag, headingStatus, controlMode),
|
||||
// ),
|
||||
//),
|
||||
RepaintBoundary(key: _mapRepaintKey, child: _buildMap(currentLat, currentLng, obfFlag, headingStatus, controlMode)),
|
||||
|
||||
// 地图核心组件
|
||||
@@ -2030,22 +2033,22 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
|
||||
/// 核心:地图正中心固定定位标
|
||||
if (_currentRobotMode == RobotMode.point)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Center(
|
||||
// 自定义十字标(中心精准对齐地图中心)
|
||||
child: SizedBox(
|
||||
width: 16, // 十字整体宽度
|
||||
height: 16, // 十字整体高度
|
||||
child: CustomPaint(
|
||||
painter: CrosshairPainter(), // 自定义十字画笔
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Center(
|
||||
// 自定义十字标(中心精准对齐地图中心)
|
||||
child: SizedBox(
|
||||
width: 16, // 十字整体宽度
|
||||
height: 16, // 十字整体高度
|
||||
child: CustomPaint(
|
||||
painter: CrosshairPainter(), // 自定义十字画笔
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
//保存按钮
|
||||
if (_saveBoxOpen)
|
||||
|
||||
Reference in New Issue
Block a user