import 'dart:developer' as dev; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:scence_map/controllers/controller.dart'; import 'package:scence_map/controllers/plum_controller.dart'; import 'package:scence_map/record_entity.dart'; import 'package:get/get.dart'; import '../../../../main.dart'; import '../../../../service/pile/device_type.dart'; import '../../../../service/pile/input.dart'; import '../../../../service/pile/public_widget.dart'; import '../../model.dart'; import '../../task_page.dart'; import '../../taskcontroller.dart'; import '../pileGenerateCard/pile_point_table.dart'; import 'draw_pile.dart'; final TaskController taskcontroller = Get.find(); final ScenceMapController mapController = Get.find(); class TaskView extends StatefulWidget { const TaskView({super.key}); @override State createState() => _TaskViewState(); } class _TaskViewState extends State { final controller = Get.find(); @override void dispose() { super.dispose(); } bool isInit = false; @override void initState() { super.initState(); mapController.update(); isInit = true; } @override Widget build(BuildContext context) { ever(controller.showList, (bool val) { if (val) { taskcontroller.currentask.update((task) { double centerPointX = controller.centerXY.value.dx; double centerPointY = controller.centerXY.value.dy; task?.list.length = 0; var dx = (controller.canvasSize.width) / 2; var dy = (controller.canvasSize.height) / 2; var rotation = mapController.rotation.value; List currentPoints = []; for (int i = 0; i < controller.plumList.length; i++) { Offset item = controller.plumList[i]; var dx1 = ((item.dx - dx) * cos(rotation) + (item.dy - dy) * sin(rotation)); var dy1 = -(item.dx - dx) * sin(rotation) + (item.dy - dy) * cos(rotation); // Offset xy = mapController.screenCenter2xy(dx1, dy1); Offset xy = Offset(dx1, dy1); PilePoint pilePoint = PilePoint( x: (xy.dx * 1000).roundToDouble() / 1000, y: (xy.dy * 1000).roundToDouble() / 1000, times: 0, id: i + 1, radius: 0.3); currentPoints.add(pilePoint); } task?.list = currentPoints; task?.centerPileInfo = CenterPileInfo( x: (centerPointX * 1000).round() / 1000, y: (centerPointY * 1000).round() / 1000, // direction: controller.direction.value, space: controller.space.value, pileWidth: controller.pileWidth.value, ); }); } }); final size = MediaQuery.of(context).size; final isDarkMode = Theme.of(context).brightness == Brightness.dark; double diagonal = mapController.diagonal; double mapWidth = mapController.width; double mapHeight = mapController.height; Offset scOffset = Offset(mapWidth / 2 - diagonal / 2, mapHeight / 2 - diagonal / 2); onTapDown(TapDownDetails details) { isInit = false; if (controller.checkValue.value == "checkPile") { Offset sc2xy = mapController.screen2xy0(details.localPosition); controller.centerXY.value = sc2xy; RecordEntity? checkPoint = mapController.pointInfo(controller.centerXY.value); if (checkPoint != null) { controller.isPileId.value = true; // controller.checkName.value = checkPoint.tpId.toString(); } else { controller.isPileId.value = false; controller.checkName.value = "未找到"; } controller.linePointOffset.value = Offset.zero; } else {} } onScaleStart(ScaleStartDetails details) { if (controller.checkValue.value != "checkPile") { controller.linePointOffset.value = details.localFocalPoint; controller.updateDistances(0.0); } // controller.shouldPaint.value = true; } onScaleUpdate(ScaleUpdateDetails details) { controller.isUp.value = false; // controller.shouldPaint.value = true; if (controller.checkValue.value != "checkPile") { Offset offset = details.localFocalPoint; controller.linePointOffset.value = offset; controller.linePointXY.value = mapController.screen2xy0(offset); double distance = (controller.centerOffset.value - controller.linePointOffset.value) .distance; controller.distanceOfCenter[controller.currentDir.value.index] = (distance * 100).round() / 100; controller.updateDistances(controller.direction.value); controller.updateCount++; } controller.isUp.value = true; double deg = (atan2( controller.linePointOffset.value.dy - controller.centerOffset.value.dy, controller.linePointOffset.value.dx - controller.centerOffset.value.dx) * 180 / pi) .roundToDouble(); controller.direction.value = deg + 90; controller.angle.value = ((controller.direction.value * pi / 180) * 100).round() / 100; } onScaleEnd(ScaleEndDetails details) { controller.isUp.value = true; controller.updateCount++; } // 中间 var center = Obx(() { controller.updateCount; // 桩点生成 if (!controller.isGenerate.value) { return const Text(""); } return Positioned( width: mapController.diagonal, height: mapController.diagonal, top: scOffset.dy, left: scOffset.dx, child: GestureDetector( onTapDown: (TapDownDetails details) => onTapDown(details), onScaleStart: (ScaleStartDetails details) => onScaleStart(details), onScaleUpdate: (ScaleUpdateDetails details) => onScaleUpdate(details), onScaleEnd: (ScaleEndDetails details) => onScaleEnd(details), child: Container( clipBehavior: Clip.hardEdge, decoration: BoxDecoration( boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Obx(() { controller.updateCount; List buttons = controller.distancesOffset; buttons[controller.currentDir.value.index] = controller.linePointOffset.value - controller.transOff; if (controller.checkValue.value == "checkPile") { buttons = [ Offset.zero, Offset.zero, Offset.zero, Offset.zero ]; } List buttonsList = []; for (int b = 0; b < buttons.length; b++) { buttonsList .add(buildPositionedButton(buttons[b], -3.14 / 2, () { controller.currentDir.value = dirList[b]; // controller.direction.value += dirList[b].angle + 3.14 / 2; })); } return Stack( children: [ CustomPaint( // size: Size(scenceMapController.diagonal, // scenceMapController.diagonal), foregroundPainter: DrawDirection( controller, scOffset, isDarkMode, isInit), // child: ), ...buttonsList ], ); }), ), )); }); // 桩点生成时返回按钮 var back = Obx(() { // bug :有时候点击的位置不准确 8寸屏的是正常的 controller.centerOffset.value = mapController.xy2Screen( controller.centerXY.value.dx, controller.centerXY.value.dy); if (isInit) { controller.centerOffset.value = mapController.xy2Screen( controller.centerXY.value.dx, controller.centerXY.value.dy) - scOffset; } // controller.linePointOffset.value = controller.centerOffset.value; dev.log( "中心${controller.centerOffset.value},${controller.centerXY.value},${mapController.centerXY},$scOffset,$isInit"); // dev.log(scenceMapController.xy2Screen( // controller.centerXY.value.dx, controller.centerXY.value.dy)); return Positioned( left: controller.isGenerate.value ? controller.centerOffset.value.dx - 25 + (mapWidth / 2 - diagonal / 2) : -50, top: controller.isGenerate.value ? controller.centerOffset.value.dy - 20 + (mapHeight / 2 - diagonal / 2) // 20 为高一半 : -50, width: 50, height: 40, child: ClipOval( child: ElevatedButton( style: ElevatedButton.styleFrom( padding: EdgeInsets.zero, shape: const CircleBorder(), ), child: const Icon(Icons.keyboard_return), onPressed: () { controller.isGenerate.value = false; controller.updateDistances(controller.angle.value); if (controller.checkValue.value == "checkPile") { centerPointDialog(context, controller); } else { controller.showList.value = true; } controller.checkValue.value = ""; }, ), )); }); return Scaffold( appBar: AppBar( title: const Text('任务页面'), actions: [ ElevatedButton( child: const Text("桩点坐标"), onPressed: () => { controller.checkValue.value = "checkPile", }), const SizedBox( width: 10, ), ElevatedButton( child: const Text("生成"), onPressed: () => { controller.checkValue.value = "checkDirection", }), UnconstrainedBox( child: IconButton( onPressed: () { int index = controller.currentDir.value.index; // controller.distancesOffset[index] = // controller.linePointOffset.value - controller.transOff; if (index + 1 == dirList.length) { index = -1; } controller.currentDir.value = dirList[index + 1]; // controller.direction.value += // controller.currentDir.value.angle + 3.14 / 2; controller.updateDistances(controller.direction.value); controller.linePointOffset.value = controller.distancesOffset[index + 1]; controller.updateCount++; }, icon: Obx(() { int index = controller.currentDir.value.index; return Transform.rotate( angle: dirList[index].angle, child: const Icon(Icons.arrow_back), ); }), ), ), UnconstrainedBox( child: SizedBox( height: 30, child: Builder( builder: (context) => Obx( () => InkWell( child: Icon( Icons.list, size: 35, color: appcontroller.isDarkMode.value ? Colors.white70 : const Color.fromARGB(200, 29, 28, 28), ), onTap: () { controller.showList.value = !controller.showList.value; }), ), ), ), ), ], ), body: Stack( children: [ Obx(() { controller.isGenerate.value; return AbsorbPointer( absorbing: controller.isGenerate.value ? true : false, //设置CenterLayout 内的GestureDetector 不生效 child: const TaskPage(), // 任务页面 ); }), center, back, Obx(() { if (controller.showList.value) { return Positioned( right: 0, top: 0, width: size.width * 0.4, height: size.height, child: PilePointTable( pilePoints: taskcontroller.currentask.value.list, onUpdate: (updatedPilePoints) => updatePoints(updatedPilePoints), ), ); } else { return const Text(""); } }) // const PileGenerateCard1() ], )); } Widget buildPositionedButton( Offset position, double rotationAngle, VoidCallback press) { Color color = Colors.black; return Positioned( left: position.dx, top: position.dy, child: IconButton( onPressed: press, icon: Transform.rotate( angle: rotationAngle, child: Icon( Icons.arrow_back, color: color, ), ), ), ); } } centerPointDialog(context, PlumDataController controller) { double titleTextWidth = 90; double inputLength = 120; FocusNode xFocus = FocusNode(); FocusNode yFocus = FocusNode(); FocusNode directionFocus = FocusNode(); FocusNode pileSpaceFocus = FocusNode(); // FocusNode pileWidthFocus = FocusNode(); DeviceType deviceType = getDeviceType(context); double fontSize = 16; if (deviceType == DeviceType.mobile) { fontSize = 16; } else { fontSize = 20; } showDialog( context: context, builder: (context) { final size = MediaQuery.of(context).size; double centerPointX = controller.centerXY.value.dx; double centerPointY = controller.centerXY.value.dy; return AlertDialog( title: const Text("设置"), contentPadding: const EdgeInsets.symmetric(horizontal: 3), actionsPadding: const EdgeInsets.only(bottom: 5), actions: [ TextButton( child: const Text('取消'), onPressed: () { controller.isGenerate.value = false; controller.isSave.value = false; Navigator.of(context).pop(); // 执行取消的逻辑 }, ), TextButton( child: const Text('确定'), onPressed: () { // 执行确定的逻辑 controller.isGenerate.value = false; controller.isSave.value = true; controller.centerXY.value = Offset(centerPointX, centerPointY); Navigator.of(context).pop(); }, ), ], content: SizedBox( height: size.height * 0.45, width: size.width * 0.5, child: SingleChildScrollView( child: AlignWrapWidget( children: [ Row(children: [ FixedWidthTextWidget(width: titleTextWidth, text: "X:"), inputText( inputLength: inputLength, value: centerPointX.toString(), fontsize: fontSize, focusNode: yFocus, onChanged: (value) => value.isNotEmpty ? centerPointY = (double.parse(value) * 1000).round() / 1000 : '') ]), Row(children: [ FixedWidthTextWidget(width: titleTextWidth, text: "Y:"), inputText( inputLength: inputLength, value: centerPointY.toString(), fontsize: fontSize, focusNode: xFocus, onChanged: (value) => value.isNotEmpty ? centerPointX = (double.parse(value) * 1000).round() / 1000 : '') ]), Row(children: [ FixedWidthTextWidget(width: titleTextWidth, text: "方向(°):"), inputText( inputLength: inputLength, value: controller.direction.toString(), fontsize: fontSize, focusNode: directionFocus, keyboardType: 0, onChanged: (value) { if (value.isNotEmpty) { controller.direction.value = double.parse(value); // bug 值修改后 绘制没有变化 controller.angle.value = controller.direction.value * pi / 180; } }) ]), Row( children: [ FixedWidthTextWidget( width: titleTextWidth + 10, text: "夯点间距(m):"), inputText( inputLength: inputLength - 10, fontsize: fontSize, value: controller.space.toString(), focusNode: pileSpaceFocus, onChanged: (value) => { value.isNotEmpty ? controller.space.value = double.parse(value) : '', }) ], ), Row(children: [ FixedWidthTextWidget( width: titleTextWidth + 10, text: "是否为梅花桩:"), Obx(() { bool c = controller.isPlum.value; return Switch( onChanged: (val) { controller.isPlum.value = val; }, value: c, ); }) ]), // Row(children: [ // FixedWidthTextWidget( // width: titleTextWidth + 10, text: "宽度(m):"), // inputText( // inputLength: inputLength - 10, // fontsize: fontSize, // value: controller.pileWidth.toString(), // focusNode: pileWidthFocus, // onChanged: (value) => { // value.isNotEmpty // ? controller.pileWidth.value = // double.parse(value) // : '', // }) // ]), Row(children: [ const Icon( Icons.tips_and_updates_outlined, color: Colors.red, ), Text( controller.isPileId.value ? '选中桩点:${controller.checkName.value}' : ' 未选中桩点', style: TextStyle( color: !controller.isPileId.value ? Colors.red : Colors.black), ) ]), ], )), ), ); }); } updatePoints(List updatedPilePoints) { taskcontroller.currentask.update((task) { task?.list = updatedPilePoints; }); // 这里可以处理更新后的桩点列表 // dev.log("生成桩点${updatedPilePoints.length},"); // for (var updatedPilePoint in updatedPilePoints) { // // 查找 recordList 中对应的 RecordEntity // RecordEntity? recordEntity = // mapController.recordList.firstWhere( // (record) => record.id == updatedPilePoint.id, // orElse: () => RecordEntity( // id: -1, // 使用一个无效的 id 表示未找到 // tid: 0, // startTime: DateTime.now(), // endTime: DateTime.now(), // pileId: 0, // name: '', // times: 0, // lat: 0.0, // lng: 0.0, // x: 0.0, // y: 0.0, // h: 0.0, // totalFlow: 0.0, // titlXavg: 0.0, // titlYavg: 0.0, // current1Avg: 0.0, // current2Avg: 0.0, // quality: 0, // reason: '', // remark: '', // depth: 0, // speed: 0.0, // ), // ); // if (recordEntity.id != -1) { // // 更新 RecordEntity 的属性 // recordEntity.x = updatedPilePoint.x; // recordEntity.y = updatedPilePoint.y; // // 其他属性的更新 // } else { // // 如果找不到对应的 RecordEntity,则添加新的 // recordEntity = RecordEntity( // id: updatedPilePoint.id, // tid: 0, // startTime: DateTime.now(), // endTime: DateTime.now(), // pileId: 0, // name: '', // times: 0, // lat: 0.0, // lng: 0.0, // x: updatedPilePoint.x, // y: updatedPilePoint.y, // h: 0.0, // totalFlow: 0.0, // titlXavg: 0.0, // titlYavg: 0.0, // current1Avg: 0.0, // current2Avg: 0.0, // quality: 0, // reason: '', // remark: '', // depth: 0, // speed: 0.0, // ); // mapController.recordList.add(recordEntity); // } // } }