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/workspace/point_info.dart'; import 'package:fis_measure/utils/canvas.dart'; import 'package:path_drawing/path_drawing.dart'; import '../calcuators/area.dart'; import '../calcuators/perimeter.dart'; import '../items/item.dart'; import '../items/item_feature.dart'; class PolyLine extends MeasureItem { final bool _initialClosed = false; PointInfo? _firstPoint; PolyLine(ItemMeta meta, IMeasureItem? parent) : super(meta, parent); @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(); } else { _checkAutoFinish(args); } } return true; } void _doFinish() { doFeatureFinish(); _firstPoint = null; } void _checkAutoFinish(PointInfo current) { if (feature == null || feature!.innerPoints.length < 3) return; double autoSnapDistance = 0.01; //TODO: from config double autoSnapThreshold = 0.05; bool isAutoSnap = true; //TODO: from config if (isAutoSnap == false) return; // final viewport = feature!.hostVisualArea!.viewport!; var length = (feature!.firstPoint - current).length; if (length > autoSnapThreshold * 2.0 && !feature!.isSmartMove) { feature!.isSmartMove = true; } if (length < autoSnapThreshold && feature!.isSmartMove) { _doFinish(); } // final logicStart = feature!.innerPoints.first; // final logicEnd = feature!.innerPoints.last; // // isSmartMove // if (logicEnd.almostEquals(logicStart, 0.01)) { // feature!.innerPoints.add(feature!.innerPoints.first); // 强制闭合 // doFeatureFinish(); // } } void handleMouseDownWhileWaiting(PointInfo args) { // TODO: 判断是否当前area // 转换为Area逻辑位置 feature = PolyLineFeature(this); feature!.isClosed = _initialClosed; if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } final point = args.toAreaLogicPoint(); feature!.adopt(point); _firstPoint = args; state = ItemStates.running; } @override bool onExecuteTouch(PointInfo args) { return true; } /// 创建面积测量 static PolyLine createArea( ItemMeta meta, [ IMeasureItem? parent, ]) { PolyLine poyline = PolyLine(meta, parent); poyline.calculator = PolyLineAreaCal(poyline); return poyline; } /// 创建周长测量 static PolyLine createPerimeter( ItemMeta meta, [ IMeasureItem? parent, ]) { PolyLine poyline = PolyLine(meta, parent); poyline.calculator = PolyLinePerimeterCal(poyline); return poyline; } } class PolyLineFeature extends MeasureItemFeature { bool _isClosed = false; bool _isSmartMove = false; PolyLineFeature(IMeasureItem refItem) : super(refItem); /// 是否闭合?抄自超声机 bool get isClosed => _isClosed; set isClosed(bool value) { if (value != _isClosed) { _isClosed = value; } } /// 是否启动智能定位 bool get isSmartMove => _isSmartMove; set isSmartMove(bool value) { if (value != _isSmartMove) { _isSmartMove = value; } } /// 首节点 DPoint get firstPoint => innerPoints.first; /// 接收新坐标 void adopt(DPoint point) { innerPoints.add(point); } @override void paint(Canvas canvas, Size size) { if (innerPoints.isEmpty) return; // TODO: from style config const double vertexSize = 10; final points = innerPoints.map((e) => convert2ViewPoint(size, e)).toList(); final startPoint = points.first; canvas.drawVertex( startPoint.toOffset(), vertexSize, active: points.length == 1, ); if (points.length > 1) { final Path path = Path(); path.moveTo(startPoint.x, startPoint.y); for (var i = 1; i < points.length; i++) { final point = points[i]; path.lineTo(point.x, point.y); } path.lineTo(startPoint.x, startPoint.y); canvas.drawPath( dashPath(path, dashArray: CircularIntervalList([2.0, 10.0])), paintPan, ); } canvas.drawVertex(points.last.toOffset(), vertexSize, active: isActive); } }