Browse Source

add(measure): 新增测量项 角度 Angle

gavin.chen 2 years ago
parent
commit
2d2e89cd39

+ 1 - 0
lib/measure_page_test.dart

@@ -338,6 +338,7 @@ class _MeasureLeftBoardState extends State<_MeasureLeftBoard> {
     MeasureTypes.Distance,
     MeasureTypes.Perimeter,
     MeasureTypes.Area,
+    MeasureTypes.Angle,
     MeasureTypes.Depth,
     MeasureTypes.Volume,
     MeasureTypes.AreaPerimeterEllipse,

+ 5 - 0
lib/process/items/factory.dart

@@ -7,6 +7,7 @@ import 'package:fis_measure/process/primitives/combos/two_area.dart';
 import 'package:fis_measure/process/primitives/combos/two_straightline.dart';
 import 'package:fis_measure/process/primitives/ellipse.dart';
 import 'package:fis_measure/process/primitives/polyline.dart';
+import 'package:fis_measure/process/primitives/polyline_angle.dart';
 import 'package:fis_measure/process/primitives/spline.dart';
 import 'package:fis_measure/process/primitives/straightline.dart';
 
@@ -78,6 +79,10 @@ class MeasureItemFactory {
     _singleton._register(MeasureTypes.ABRatio, TwoArea.crateABRatio, "TwoArea");
     _singleton._register(MeasureTypes.ResidualUrine, TwoStraightLine.createRUV,
         "TwoStraightLine");
+    _singleton._register(
+      MeasureTypes.Angle,
+      PolylineAngle.createPolyAngle,
+    );
 
     //Ellipse
     _singleton._register(

+ 143 - 0
lib/process/primitives/polyline_angle.dart

@@ -0,0 +1,143 @@
+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<PolylineAngleFeature> {
+  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;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    // TODO: implement onExecuteTouch
+    throw UnimplementedError();
+  }
+
+  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;
+  }
+}
+
+class PolylineAngleFeature extends MeasureItemFeature {
+  PolylineAngleFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
+    innerPoints.add(point.clone());
+    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, paintPan);
+    }
+  }
+}
+
+class _AngleCalc extends Calculator<PolylineAngle, double> {
+  _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;
+  }
+}

+ 16 - 0
lib/process/workspace/application.dart

@@ -21,6 +21,7 @@ import 'package:fis_measure/process/items/factory.dart';
 import 'package:fis_measure/process/primitives/carotid_imt.dart';
 import 'package:fis_measure/process/primitives/detection.dart';
 import 'package:fis_measure/process/primitives/location.dart';
+import 'package:fis_measure/process/primitives/polyline_angle.dart';
 import 'package:fis_measure/process/primitives/straightline.dart';
 import 'package:fis_measure/process/visual/tissue_area.dart';
 import 'package:flutter/foundation.dart';
@@ -348,6 +349,21 @@ class Application implements IApplication {
       );
       return;
     }
+    if (name == MeasureTypes.Angle) {
+      activeMeasureItem = PolylineAngle.createPolyAngle(
+        ItemMeta(
+          MeasureTypes.Angle,
+          measureType: MeasureTypes.Angle,
+          description: MeasureTypes.Angle,
+          briefAnnotation: MeasureTypes.Angle,
+          outputs: [
+            ItemOutputMeta(MeasureTypes.Angle, "Angle", VidUsUnit.degree),
+          ],
+        ),
+        null,
+      );
+      return;
+    }
     if (name == MeasureTypes.Depth) {
       final isProbeConvex = (currentVisualArea as TissueArea).isConvex;
       final Location Function(ItemMeta, [IMeasureItem?]) fn = isProbeConvex