import 'dart:ui'; import 'package:fis_measure/interfaces/date_types/point.dart'; import 'package:fis_measure/interfaces/enums/items.dart'; import 'package:fis_measure/interfaces/process/items/item.dart'; import 'package:fis_measure/interfaces/process/items/item_metas.dart'; import 'package:fis_measure/interfaces/process/workspace/point_info.dart'; import 'package:fis_measure/process/calcuators/trace.dart'; import 'package:fis_measure/process/items/item.dart'; import 'package:fis_measure/process/items/item_feature.dart'; import 'package:fis_measure/utils/canvas.dart'; import 'package:fis_measure/view/gesture/positioned_touch_cursor.dart'; import 'package:get/get.dart'; /// 手势轨迹图形 class MultiTrace extends TraceItemAbstract { MultiTrace(ItemMeta meta, IMeasureItem? parent) : super(meta, parent); late final touchState = Get.find(); @override bool onExecuteMouse(PointInfo args) { if (state == ItemStates.finished) { if (args.pointType == PointInfoType.mouseDown) { state = ItemStates.waiting; } } if (state == ItemStates.waiting) { if (args.pointType == PointInfoType.mouseDown) { handleMouseDownWhileWaiting(args); } } else if (state == ItemStates.running) { if (args.pointType == PointInfoType.mouseUp) return false; feature?.adopt(args); doCalculate(); if (args.pointType == PointInfoType.mouseDown) { doFeatureFinish(); } } return true; } @override void doFeatureFinish() { super.doFeatureFinish(); } void handleMouseDownWhileWaiting(PointInfo args) { // TODO: 判断是否当前area // 转换为Area逻辑位置 feature = MultiTraceFeature(this); if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } final point = args.toAreaLogicPoint(); feature!.adopt(point); state = ItemStates.running; } void handleTouchDownWhileWaiting(PointInfo args) { // TODO: 判断是否当前area // 转换为Area逻辑位置 feature = MultiTraceFeature(this); if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } final point = args.toAreaLogicPoint(); feature!.adopt(point); // state = ItemStates.running; } PointInfo? startPoint; DPoint touchStartPosition = DPoint(0, 0); // 相对位移起始触摸点 bool isFirstPointMove = false; @override bool onExecuteTouch(PointInfo args) { if (state == ItemStates.finished) { if (args.pointType == PointInfoType.touchDown) { state = ItemStates.waiting; } } if (state == ItemStates.waiting) { if (isFirstPointMove) { args.addOffset(0, -0.2); } switch (args.pointType) { case PointInfoType.touchDown: isFirstPointMove = false; startPoint = args; // 设置线段起点 handleTouchDownWhileWaiting(startPoint!); // 通过设置的起点开始一个绘制事件 break; case PointInfoType.touchUp: startPoint = args; // 设置线段起点 state = ItemStates.running; touchState.touchOffset = Offset.zero; break; // 按下立即抬起无事发生 case PointInfoType.touchMove: isFirstPointMove = true; final pixelSize = application.displaySize; touchState.touchOffset = DPoint(0, -0.2).scale2Size(pixelSize).toOffset(); feature?.innerPoints.first = args; break; default: break; } } else if (state == ItemStates.running) { if (args.pointType == PointInfoType.touchDown) { touchStartPosition = args; final pixelSize = application.displaySize; touchState.touchOffset = startPoint!.scale2Size(pixelSize).toOffset() - args.scale2Size(pixelSize).toOffset(); } if (args.pointType == PointInfoType.touchUp) { touchState.touchOffset = Offset.zero; doFeatureFinish(); } if (args.pointType == PointInfoType.touchMove) { PointInfo newPoint = PointInfo.fromOffset( startPoint!.clone().addVector(args - touchStartPosition).toOffset(), startPoint!.pointType); feature?.adopt(newPoint); doCalculate(); } } return true; } static MultiTrace createTrace( ItemMeta meta, [ IMeasureItem? parent, ]) { MultiTrace trace = MultiTrace(meta, parent); trace.calculator = TraceCal(trace); return trace; } } class MultiTraceFeature extends TraceItemFeatureAbstract { MultiTraceFeature(TraceItemAbstract refItem) : super(refItem); final greenPen = Paint() ..color = const Color.fromARGB(255, 0, 255, 0) ..isAntiAlias = true ..strokeWidth = 1 ..style = PaintingStyle.stroke; final dashLinePan = Paint() ..color = const Color.fromARGB(255, 255, 255, 0) ..isAntiAlias = false ..strokeWidth = 1 ..style = PaintingStyle.stroke; DPoint furthestPoint = DPoint(0, 0); @override void paint(Canvas canvas, Size size) { final double areaTop = hostVisualArea!.displayRegion.top * size.height; final double areaBottom = hostVisualArea!.displayRegion.bottom * size.height; if (innerPoints.isEmpty) return; if (innerPoints.length == 1) { drawVertex(canvas, convert2ViewPoint(size, innerPoints[0]).toOffset()); drawId(canvas, size); return; } double maxDistance = 0; drawId(canvas, size); final points = innerPoints.map((e) => convert2ViewPoint(size, e)).toList(); final startOffset = convert2ViewPoint(size, startPoint); final endOffset = convert2ViewPoint(size, endPoint); canvas.drawDashLine(Offset(startOffset.x, areaTop), Offset(startOffset.x, areaBottom), 3, 3, dashLinePan); canvas.drawDashLine(Offset(endOffset.x, areaTop), Offset(endOffset.x, areaBottom), 3, 3, dashLinePan); if (points.length > 1) { final Path path = Path(); path.moveTo(startOffset.x, startOffset.y); for (var i = 1; i < points.length; i++) { final point = points[i]; path.lineTo(point.x, point.y); final distance = (point.y - startOffset.y).abs(); if (distance > maxDistance) { maxDistance = distance; furthestPoint = point; } } drawCrossVertex(canvas, furthestPoint.toOffset()); canvas.drawPath( path, greenPen, ); } } } abstract class TraceItemFeatureAbstract extends MeasureItemFeature { TraceItemFeatureAbstract(TraceItemAbstract refItem) : super(refItem); @override TraceItemAbstract get refItem => super.refItem as TraceItemAbstract; DPoint get startPoint => innerPoints.first; DPoint get endPoint => innerPoints.last; bool ifRightSide = true; /// 接收新坐标 void adopt(DPoint point) { if (innerPoints.isEmpty) { innerPoints.add(point); } if (point.x > startPoint.x) { handleChangeSide(point); if (point.x < innerPoints.last.x) { clearRight(point.x); } else if (point.x > innerPoints.last.x) { innerPoints.add(point); } } else { handleChangeSide(point); if (point.x > innerPoints.last.x) { clearLeft(point.x); } else if (point.x < innerPoints.last.x) { innerPoints.add(point); } } } void clearRight(double X) { if (innerPoints.isEmpty) return; for (var i = innerPoints.length - 1; i >= 0; i--) { if (innerPoints[i].x >= X) { innerPoints.removeAt(i); } } } void clearLeft(double X) { if (innerPoints.isEmpty) return; for (var i = innerPoints.length - 1; i >= 0; i--) { if (innerPoints[i].x <= X) { innerPoints.removeAt(i); } } } void handleChangeSide(point) { if (ifRightSide) { if (point.x < startPoint.x) { ifRightSide = false; innerPoints.clear(); innerPoints.add(point); } } else { if (point.x > startPoint.x) { ifRightSide = true; innerPoints.clear(); innerPoints.add(point); } } } } abstract class TraceItemAbstract extends MeasureItem { TraceItemAbstract(ItemMeta meta, IMeasureItem? parent) : super(meta, parent); }