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_metas.dart'; import 'package:fis_measure/interfaces/process/items/item.dart'; import 'package:fis_measure/interfaces/process/workspace/point_info.dart'; import 'package:fis_measure/process/calcuators/curve.dart'; import 'package:fis_measure/process/primitives/utils/auto_snap.dart'; import 'package:fis_measure/utils/canvas.dart'; import 'area_abstract.dart'; /// 折线多边形 class Polyline extends AreaItemAbstract with AutoSnapMixin { Polyline(ItemMeta meta, IMeasureItem? parent) : super(meta, parent); static Polyline createAreaPerimeter(ItemMeta meta, [IMeasureItem? parent]) { Polyline polygon = Polyline(meta, parent); polygon.calculator = AreaPerimeterCal(polygon); return polygon; } static Polyline createCurveLength(ItemMeta meta, [IMeasureItem? parent]) { Polyline polygon = Polyline(meta, parent); polygon.calculator = CurveLengthCal(polygon); polygon.isClosed = false; return polygon; } @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 (feature == null) return false; if (args.pointType == PointInfoType.mouseUp) return false; final f = feature!; if (args.pointType == PointInfoType.mouseDown) { f.innerPoints.add(args); } else { f.innerPoints.last = args; } doCalculate(); checkAutoSnap(args); // if (f.startPoint.almostEquals(f.endPoint)) { // doFeatureFinish(); // } } return true; } DPoint lastStartPoint = DPoint(0, 0); // 上一个起点 bool isFirstPointNeedOffset = false; // 第一个点是否需要施加偏移 DPoint splineTouchStartPoint = DPoint(0, 0); // 轨迹触摸起始点 bool isOtherPointNeedOffset = false; // 其他点是否需要施加偏移 @override bool onExecuteTouch(PointInfo args) { if (state == ItemStates.finished) { if (args.pointType == PointInfoType.touchDown) { state = ItemStates.waiting; } } if (state == ItemStates.waiting) { if (isFirstPointNeedOffset) args.addOffset(0, -0.2); switch (args.pointType) { case PointInfoType.touchDown: handleTouchDownWhileWaiting(args); isFirstPointNeedOffset = false; break; case PointInfoType.touchUp: lastStartPoint = args; // 设置线段起点 state = ItemStates.running; feature?.innerPoints.first = args; break; // 按下立即抬起无事发生 case PointInfoType.touchMove: if (isMoveTargetOutOfRange(args)) return true; isFirstPointNeedOffset = true; feature?.innerPoints.first = args; break; default: break; } } else if (state == ItemStates.running) { if (feature == null) return false; PointInfo newPoint = PointInfo.fromOffset( lastStartPoint .clone() .addVector(args - splineTouchStartPoint) .toOffset(), args.pointType); newPoint.hostVisualArea = args.hostVisualArea; final f = feature!; if (args.pointType == PointInfoType.touchUp) { if (!isOtherPointNeedOffset) { f.innerPoints.last = args; lastStartPoint = args; doCalculate(); } else { lastStartPoint = newPoint; } } if (args.pointType == PointInfoType.touchDown) { isOtherPointNeedOffset = false; splineTouchStartPoint = args; f.innerPoints.add(lastStartPoint); } if (args.pointType == PointInfoType.touchMove) { if (isMoveTargetOutOfRange(newPoint)) return true; isOtherPointNeedOffset = true; f.innerPoints.last = newPoint; } doCalculate(); PointInfo newPointInfo = isOtherPointNeedOffset ? PointInfo.fromOffset(newPoint.toOffset(), args.pointType) : args; checkAutoSnap(newPointInfo); } return true; } void handleMouseDownWhileWaiting(PointInfo args) { // TODO: 判断是否当前area // 转换为Area逻辑位置 final point = args.toAreaLogicPoint(); feature = PolylineFeature(this, point); if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } state = ItemStates.running; } void handleTouchDownWhileWaiting(PointInfo args) { // TODO: 判断是否当前area final point = args.toAreaLogicPoint(); feature = PolylineFeature.withOneStartPoint(this, point); if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } } } class PolylineFeature extends AreaItemFeatureAbstract { PolylineFeature(AreaItemAbstract refItem, DPoint point) : super(refItem) { innerPoints.add(point.clone()); innerPoints.add(point.clone()); } PolylineFeature.withOneStartPoint(AreaItemAbstract refItem, DPoint point) : super(refItem) { innerPoints.add(point.clone()); } @override void paint(Canvas canvas, Size size) { if (innerPoints.isEmpty) return; drawId(canvas, size); final startOffset = convert2ViewPoint(size, startPoint).toOffset(); if (innerPoints.length == 1) { drawVertex(canvas, startOffset, true); return; } else { drawVertex(canvas, startOffset); } final len = innerPoints.length; for (var i = 1; i < len; i++) { final a = innerPoints[i - 1]; final b = innerPoints[i]; final offsetA = convert2ViewPoint(size, a).toOffset(); final offsetB = convert2ViewPoint(size, b).toOffset(); canvas.drawDashLine(offsetA, offsetB, 1, 10, paintPan); final isLast = len - i == 1; if (isLast) { drawVertex(canvas, offsetB, isActive); if (isClosed) { canvas.drawDashLine(offsetB, startOffset, 1, 10, paintLinePan); } } else { drawVertex(canvas, offsetB, false); } } } }