Browse Source

Temporary submission

melon.yin 2 years ago
parent
commit
e9645286e8

+ 23 - 0
lib/interfaces/enums/annotation.dart

@@ -0,0 +1,23 @@
+/// 注释类型
+enum AnnotationType {
+  /// 文本标签
+  label,
+
+  /// 输入框自定义
+  input,
+
+  /// 箭头
+  arrow,
+}
+
+/// 注释状态
+enum AnnotationStates {
+  /// 就绪
+  waiting,
+
+  /// 进行中
+  running,
+
+  /// 完成
+  finish,
+}

+ 35 - 0
lib/interfaces/process/annotations/annotation.dart

@@ -0,0 +1,35 @@
+import 'package:fis_common/event/event_type.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/enums/annotation.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+import 'package:flutter/painting.dart';
+
+/// 注释
+abstract class IAnnotationItem {
+  /// 类型
+  AnnotationType get type;
+
+  /// 状态
+  AnnotationStates get state;
+
+  /// 记录集合
+  List<IAnnotationFeature> get features;
+
+  /// 当前注释
+  IAnnotationFeature? get feature;
+
+  /// 处理手势
+  bool execute(PointInfo args);
+
+  /// Feature更新
+  late final FEventHandler<IAnnotationFeature?> featureUpdated;
+}
+
+/// 注释记录
+abstract class IAnnotationFeature {
+  /// 坐标
+  DPoint get position;
+
+  /// 绘制
+  void draw(Canvas canvas, Size size, Offset offset);
+}

+ 111 - 0
lib/process/annotations/annotation.dart

@@ -0,0 +1,111 @@
+import 'package:fis_common/event/event_type.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/enums/annotation.dart';
+import 'package:fis_measure/interfaces/process/annotations/annotation.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+import 'package:flutter/foundation.dart';
+
+abstract class AnnotationItem implements IAnnotationItem {
+  late AnnotationType _type;
+  late AnnotationStates _state;
+  final List<AnnotationFeature> _features = [];
+  AnnotationFeature? _feature;
+
+  @override
+  late final FEventHandler<IAnnotationFeature?> featureUpdated;
+
+  AnnotationItem(AnnotationType type) {
+    _type = AnnotationType.arrow;
+    _state = AnnotationStates.waiting;
+    featureUpdated = FEventHandler<IAnnotationFeature?>();
+  }
+
+  @override
+  AnnotationType get type => _type;
+
+  @override
+  AnnotationStates get state => _state;
+  set state(AnnotationStates value) {
+    if (value != _state) {
+      _state = value;
+    }
+  }
+
+  @override
+  AnnotationFeature? get feature => _feature;
+  set feature(AnnotationFeature? value) {
+    if (value != _feature) {
+      _feature = value;
+    }
+  }
+
+  @override
+  List<IAnnotationFeature> get features => _features;
+
+  @override
+  bool execute(PointInfo args) {
+    bool result = false;
+    switch (args.pointType) {
+      case PointInfoType.mouseUp:
+      case PointInfoType.mouseDown:
+      case PointInfoType.mouseMove:
+        result = onExecuteMouse(args);
+        break;
+      case PointInfoType.touchUp:
+      case PointInfoType.touchDown:
+      case PointInfoType.touchMove:
+        result = onExecuteTouch(args);
+        break;
+    }
+    if (result) {
+      doFeatureUpdate();
+    }
+    return result;
+  }
+
+  /// 处理鼠标手势
+  @protected
+  bool onExecuteMouse(PointInfo args);
+
+  /// 处理触摸手势
+  @protected
+  bool onExecuteTouch(PointInfo args);
+
+  @protected
+  void doFeatureFinish() {
+    if (feature != null) {
+      // feature!.isActive = false;
+      features.add(feature!);
+    }
+    feature = null;
+    state = AnnotationStates.finish;
+  }
+
+  @protected
+  void doFeatureUpdate() {
+    featureUpdated.emit(this, feature);
+  }
+}
+
+abstract class AnnotationFeature extends IAnnotationFeature {
+  late IAnnotationItem _ref;
+  final List<DPoint> _points = [];
+
+  AnnotationFeature(IAnnotationItem ref) {
+    _ref = ref;
+  }
+
+  IAnnotationItem get ref => _ref;
+
+  List<DPoint> get points => _points;
+
+  @override
+  DPoint get position => _points[0];
+  set position(DPoint value) {
+    if (_points.isEmpty) {
+      _points.add(value);
+    } else {
+      _points[0] = value;
+    }
+  }
+}

+ 153 - 0
lib/process/annotations/arrow_annotation.dart

@@ -0,0 +1,153 @@
+// ignore_for_file: constant_identifier_names
+
+import 'dart:math' as math;
+import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/enums/annotation.dart';
+import 'package:fis_measure/interfaces/process/annotations/annotation.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+import 'package:flutter/material.dart';
+
+import 'annotation.dart';
+
+/// 箭头注释
+class ArrowAnnotation extends AnnotationItem {
+  ArrowAnnotation() : super(AnnotationType.arrow);
+
+  @override
+  ArrowAnnotationFeature? get feature =>
+      super.feature as ArrowAnnotationFeature?;
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    if (state == AnnotationStates.finish) {
+      state = AnnotationStates.waiting;
+    }
+    if (state == AnnotationStates.waiting) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        feature = ArrowAnnotationFeature(this, args);
+        state = AnnotationStates.running;
+        return true;
+      } else {
+        return false;
+      }
+    } else {
+      if (args.pointType == PointInfoType.mouseUp) return false;
+
+      feature?.endPoint = args;
+      if (args.pointType == PointInfoType.mouseDown) {
+        doFeatureFinish();
+      }
+    }
+
+    return true;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    // TODO: implement onExecuteTouch
+    throw UnimplementedError();
+  }
+}
+
+class ArrowAnnotationFeature extends AnnotationFeature {
+  static const C_ARRPW_ANGLE = 90.0; // 箭头角度
+  static const C_ARROW_LENGTH = 20; // 中心线交叉点到终点的长度
+  final _paint = Paint()
+    ..color = Colors.red
+    ..strokeWidth = 2
+    ..style = PaintingStyle.stroke;
+
+  ArrowAnnotationFeature(ArrowAnnotation ref, DPoint offset) : super(ref) {
+    points.addAll([offset, offset]);
+  }
+
+  DPoint get endPoint => points[1];
+  set endPoint(DPoint value) => points[1] = value;
+
+  @override
+  void draw(Canvas canvas, Size size, Offset offset) {
+    final startPoint = points[0].toOffset();
+    final endPoint = points[1].toOffset();
+    canvas.drawLine(startPoint, endPoint, _paint);
+
+    _drawArrow(canvas, startPoint, endPoint);
+  }
+
+  /// 绘制箭头
+  void _drawArrow(Canvas canvas, Offset p1, Offset p2) {
+    final directionX = (p2.dx - p1.dx); // X轴向量方向
+    final directionY = (p2.dy - p1.dy); // Y轴向量方向
+    final center = _findArrowHeadCenter(p1, p2);
+
+    const cuspAngle = C_ARRPW_ANGLE / 2; // 边线和中心线的角度
+    const cuspRadians = cuspAngle * (math.pi / 180);
+    // 边角到中心交叉点的距离
+    final distanceCenter2Side = math.tan(cuspRadians) * C_ARROW_LENGTH;
+
+    final tan2AxisX = (p2.dy - p1.dy) / (p2.dx - p1.dx);
+    // 中心线到X轴的弧度
+    final radians2AxisX = math.atan(tan2AxisX).abs();
+
+    // 在画布正坐标计算边点
+    // 边点到X轴的距离
+    final distance2AxisX = math.sin(radians2AxisX) * distanceCenter2Side;
+    // 边点到Y轴的距离
+    final distance2AxisY = math.cos(radians2AxisX) * distanceCenter2Side;
+
+    double xRight = 0, yRight = 0;
+    double xLeft = 0, yLeft = 0;
+    if (directionX < 0) {
+      if (directionY > 0) {
+        // 右上->左下
+        xRight = center.dx - distance2AxisX;
+        yRight = center.dy - distance2AxisY;
+        xLeft = center.dx + distance2AxisX;
+        yLeft = center.dy + distance2AxisY;
+      } else {
+        // 右下->左上
+        xRight = center.dx + distance2AxisX;
+        yRight = center.dy - distance2AxisY;
+        xLeft = center.dx - distance2AxisX;
+        yLeft = center.dy + distance2AxisY;
+      }
+    } else {
+      if (directionY > 0) {
+        // 左上->右下
+        xRight = center.dx - distance2AxisX;
+        yRight = center.dy + distance2AxisY;
+        xLeft = center.dx + distance2AxisX;
+        yLeft = center.dy - distance2AxisY;
+      } else {
+        // 左下->右上
+        xRight = center.dx + distance2AxisX;
+        yRight = center.dy + distance2AxisY;
+        xLeft = center.dx - distance2AxisX;
+        yLeft = center.dy - distance2AxisY;
+      }
+    }
+
+    final leftSidePoint = Offset(xLeft, yLeft);
+    final rightSidePoint = Offset(xRight, yRight);
+    canvas.drawLine(p2, leftSidePoint, _paint);
+    canvas.drawLine(p2, rightSidePoint, _paint);
+  }
+
+  /// 找到箭头底部(两个边角的水平线)与直线的交叉点
+  Offset _findArrowHeadCenter(Offset p1, Offset p2) {
+    final x1 = p1.dx, x2 = p2.dx;
+    final y1 = p1.dy, y2 = p2.dy;
+    // - 假设交叉点: p3 = (x3,y3)
+    // ratio = distanc(p3-p2)/distance(p2-p1)
+    // - 同时
+    // ratio == (x3-x2)/(x1-x2)
+    // ratio == (y3-y2)/(y1-y2)
+    // - 可得
+    // x3 = (x1-x2)*ratio + x2
+    // y3 = (y1-y2)*ratio + y2
+    final lineLength = (p2 - p1).distance;
+    final ratio = C_ARROW_LENGTH / lineLength;
+    final dx = (ratio * (x1 - x2)) + x2;
+    final dy = (ratio * (y1 - y2)) + y2;
+    return Offset(dx, dy);
+  }
+}

+ 34 - 0
lib/process/annotations/input_annotation.dart

@@ -0,0 +1,34 @@
+import 'dart:ui';
+
+import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/enums/annotation.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+
+import 'annotation.dart';
+
+/// 自定义文本注释
+class InputAnnotation extends AnnotationItem {
+  InputAnnotation() : super(AnnotationType.input);
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    return true;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    // TODO: implement onExecuteTouch
+    throw UnimplementedError();
+  }
+}
+
+class InputAnnotationFeature extends AnnotationFeature {
+  InputAnnotationFeature(InputAnnotation ref, DPoint offset) : super(ref) {
+    points.add(offset);
+  }
+
+  @override
+  void draw(Canvas canvas, Size size, Offset offset) {
+    // TODO: implement draw
+  }
+}

+ 34 - 0
lib/process/annotations/text_annotation.dart

@@ -0,0 +1,34 @@
+import 'dart:ui';
+
+import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/enums/annotation.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+
+import 'annotation.dart';
+
+/// 文本标签注释
+class TextAnnotation extends AnnotationItem {
+  TextAnnotation() : super(AnnotationType.input);
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    return true;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    // TODO: implement onExecuteTouch
+    throw UnimplementedError();
+  }
+}
+
+class TextAnnotationFeature extends AnnotationFeature {
+  TextAnnotationFeature(TextAnnotation ref, DPoint offset) : super(ref) {
+    points.add(offset);
+  }
+
+  @override
+  void draw(Canvas canvas, Size size, Offset offset) {
+    // TODO: implement draw
+  }
+}