import 'dart:math'; 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/items/types.dart'; import 'package:fis_measure/interfaces/process/workspace/point_info.dart'; import 'package:fis_measure/process/calcuators/calculator.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'; /// 连续两个线段确定一个角度 class PolylineAngle extends MeasureItem { PolylineAngle(ItemMeta meta, IMeasureItem? parent) : super(meta, parent); static PolylineAngle createPolyAngle(ItemMeta meta, [IMeasureItem? parent]) { PolylineAngle polygon = PolylineAngle(meta, parent); polygon.calculator = _AngleCalc(polygon); 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); if (f.innerPoints.length == 4) { f.innerPoints.removeLast(); doFeatureFinish(); } } else { f.innerPoints.last = args; } doCalculate(); } 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; DPoint newPoint = lastStartPoint.clone().addVector(args - splineTouchStartPoint); final f = feature!; if (args.pointType == PointInfoType.touchUp) { if (!isOtherPointNeedOffset) { f.innerPoints.last = args; lastStartPoint = args; doCalculate(); } else { lastStartPoint = newPoint; } if (f.innerPoints.length == 3) { // f.innerPoints.removeLast(); doFeatureFinish(); } } if (args.pointType == PointInfoType.touchDown) { isOtherPointNeedOffset = false; splineTouchStartPoint = args; f.innerPoints.add(lastStartPoint); } if (args.pointType == PointInfoType.touchMove) { if (isMoveTargetOutOfRange(args)) return true; isOtherPointNeedOffset = true; f.innerPoints.last = newPoint; } doCalculate(); } return true; } void handleMouseDownWhileWaiting(PointInfo args) { // TODO: 判断是否当前area // 转换为Area逻辑位置 final point = args.toAreaLogicPoint(); feature = PolylineAngleFeature(this, point); if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } state = ItemStates.running; } void handleTouchDownWhileWaiting(PointInfo args) { // TODO: 判断是否当前area final point = args.toAreaLogicPoint(); feature = PolylineAngleFeature.withOneStartPoint(this, point); if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } } } class PolylineAngleFeature extends MeasureItemFeature { PolylineAngleFeature(IMeasureItem refItem, DPoint point) : super(refItem) { innerPoints.add(point.clone()); innerPoints.add(point.clone()); } PolylineAngleFeature.withOneStartPoint(IMeasureItem refItem, DPoint point) : super(refItem) { innerPoints.add(point.clone()); } @override void paint(Canvas canvas, Size size) { if (innerPoints.isEmpty) return; drawId(canvas, size); final innerOffsets = innerPoints.map((e) => convert2ViewPoint(size, e).toOffset()).toList(); for (var e in innerOffsets) { drawVertex(canvas, e); } final len = innerOffsets.length; for (var i = 1; i < len; i++) { final a = innerOffsets[i - 1]; final b = innerOffsets[i]; canvas.drawDashLine(a, b, 1, 10, paintLinePan); } } } class _AngleCalc extends Calculator { _AngleCalc(PolylineAngle ref) : super(ref); @override void calculate() { if (ref.feature == null) return; final feature = ref.feature!; final viewport = feature.hostVisualArea!.viewport!; final points = feature.innerPoints.map((e) => viewport.convert(e)).toList(); feature.values.clear(); double angle; if (points.length != 3) { angle = 0; } else { angle = calcAngle(points[1], points[0], points[2]); } for (var output in ref.meta.outputs) { if (output.name == MeasureTypes.Angle) { var value = roundDouble(angle, output.fractionalDigits); feature.updateFloatValue(output, value, output.unit); } } } /// 三个点计算角度,pointsA 为顶点 static double calcAngle(DPoint pointsA, DPoint pointsB, DPoint pointsC) { double angle = 0; double a = sqrt(pow(pointsB.x - pointsC.x, 2) + pow(pointsB.y - pointsC.y, 2)); double b = sqrt(pow(pointsA.x - pointsC.x, 2) + pow(pointsA.y - pointsC.y, 2)); double c = sqrt(pow(pointsA.x - pointsB.x, 2) + pow(pointsA.y - pointsB.y, 2)); if (a + b > c && a + c > b && b + c > a) { double cosA = (pow(b, 2) + pow(c, 2) - pow(a, 2)) / (2 * b * c); angle = acos(cosA) * 180 / pi; } return angle; } }