Procházet zdrojové kódy

暂存部分Simpson代码

Melon před 10 měsíci
rodič
revize
06cb165b4f

+ 5 - 0
lib/interfaces/process/items/terms.dart

@@ -268,6 +268,11 @@ class MeasureTerms {
   static const LvStudy = "LV Study";
   static const LvStudySimple = "LV Study(Simple)";
 
+  // 辛普森
+  static const ModifiedSimpsonDisc = "Modified Simpson Disc";
+  static const A2CEnterSimpsonDisc = "A2C-Enter Simpson Disc";
+  static const A4CEnterSimpsonDisc = "A4C-Enter Simpson Disc";
+
   /// Body Surface Area
   /// 体表面积
   static const BSA = "BSA";

+ 3 - 0
lib/interfaces/process/items/types.dart

@@ -9,6 +9,9 @@ class MeasureTypes {
   static const LvStudyByLineGroupTissue = 'LvStudyByLineGroupTissue';
   static const LvSimpleTissue = "LvSimpleTissue";
   static const LvSimpleTissueTm = "LvSimpleTissueTm";
+  static const LvSingleSimpson = "LvSingleSimpson";
+  static const LvSimpson = "LvSimpson";
+  static const SimpsonPath = "SimpsonPath";
 
   /// 空类型,用于结束测量
   static const Empty = 'Empty';

+ 27 - 0
lib/process/calcuators/simpson.dart

@@ -0,0 +1,27 @@
+import 'package:fis_measure/process/primitives/combos/simpson.dart';
+
+import 'lv_study.dart';
+
+class LvSimpsonCal extends LvStudyCalculatorBase<LvStudySimpson> {
+  LvSimpsonCal(super.ref) {
+    //
+  }
+
+  @override
+  void calculate() {
+    // TODO: implement calculate
+    super.calculate();
+  }
+}
+
+class LvSingleSimpsonCal extends LvStudyCalculatorBase<LvStudySingleSimpson> {
+  LvSingleSimpsonCal(super.ref) {
+    //
+  }
+
+  @override
+  void calculate() {
+    // TODO: implement calculate
+    super.calculate();
+  }
+}

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

@@ -10,6 +10,7 @@ import 'package:fis_measure/process/primitives/combos/flow_area_vti.dart';
 import 'package:fis_measure/process/primitives/combos/lv_mass.dart';
 import 'package:fis_measure/process/primitives/combos/lwh_straightline.dart';
 import 'package:fis_measure/process/primitives/combos/lv_study.dart';
+import 'package:fis_measure/process/primitives/combos/simpson.dart';
 import 'package:fis_measure/process/primitives/combos/sv.dart';
 import 'package:fis_measure/process/primitives/combos/three_ray.dart';
 import 'package:fis_measure/process/primitives/combos/two_area.dart';
@@ -96,6 +97,9 @@ class MeasureItemFactory {
 
     _singleton._register(MeasureTypes.LVdMass, LVMass.createLVdMass);
     _singleton._register(MeasureTypes.RVSP, Rvsp.createRvsp);
+    _singleton._register(MeasureTypes.LvSimpson, LvStudySimpson.create);
+    _singleton._register(
+        MeasureTypes.LvSingleSimpson, LvStudySingleSimpson.create);
 
     // SV
     _singleton._register(MeasureTypes.SV, Sv.createSV);

+ 70 - 0
lib/process/primitives/combos/simpson.dart

@@ -0,0 +1,70 @@
+import 'package:fis_measure/interfaces/process/items/item.dart';
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'package:fis_measure/process/calcuators/simpson.dart';
+import 'package:fis_measure/process/items/item_feature.dart';
+import 'package:fis_measure/process/items/item.dart';
+import 'package:fis_measure/process/items/top_item.dart';
+import 'package:fis_measure/process/items/top_item_feature.dart';
+
+import '../multi_method/multi_simpson_path.dart';
+
+class LvStudySimpson extends TopMeasureItem<LvStudySimpsonFeature> {
+  static const String _lvedvKey = "LVEDV";
+  static const String _lvesvKey = "LVESV";
+
+  // late final Trace epi;
+  // late final Trace endo;
+  // late final StraightLine l;
+
+  LvStudySimpson(super.meta) {
+    //
+  }
+
+  @override
+  LvStudySimpsonFeature buildFeature() => LvStudySimpsonFeature(this);
+
+  static LvStudySimpson create(ItemMeta meta, [IMeasureItem? parent]) {
+    final simpson = LvStudySimpson(meta);
+    simpson.calculator = LvSimpsonCal(simpson);
+    return simpson;
+  }
+}
+
+class LvStudySingleSimpson extends TopMeasureItem<LvStudySingleSimpsonFeature> {
+  static const String _lvedvKey = "LVEDV";
+  static const String _lvesvKey = "LVESV";
+
+  late final MultiSimpsonPath lvedv;
+  late final MultiSimpsonPath lvesv;
+
+  LvStudySingleSimpson(super.meta) {
+    final lvedvMeta = meta.getChildByName(_lvedvKey)!;
+    final lvesvMeta = meta.getChildByName(_lvesvKey)!;
+    lvedv = MultiSimpsonPath.create(lvedvMeta, this);
+    lvesv = MultiSimpsonPath.create(lvesvMeta, this);
+    childItems.add(lvedv);
+    childItems.add(lvesv);
+  }
+
+  @override
+  LvStudySingleSimpsonFeature buildFeature() =>
+      LvStudySingleSimpsonFeature(this);
+
+  static LvStudySingleSimpson create(ItemMeta meta, [IMeasureItem? parent]) {
+    final simpson = LvStudySingleSimpson(meta);
+    simpson.calculator = LvSingleSimpsonCal(simpson);
+    return simpson;
+  }
+}
+
+class LvStudySimpsonFeature extends TopMeasureItemFeature {
+  LvStudySimpsonFeature(
+    ITopMeasureItem refItem,
+  ) : super(refItem);
+}
+
+class LvStudySingleSimpsonFeature extends TopMeasureItemFeature {
+  LvStudySingleSimpsonFeature(
+    ITopMeasureItem refItem,
+  ) : super(refItem);
+}

+ 84 - 0
lib/process/primitives/multi_method/multi_simpson_path.dart

@@ -0,0 +1,84 @@
+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/items/item_metas.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+import 'package:fis_measure/process/items/item.dart';
+import 'package:fis_measure/process/items/item_feature.dart';
+import 'package:fis_measure/process/primitives/polyline.dart';
+import 'package:fis_measure/process/primitives/area_abstract.dart';
+import 'package:fis_measure/process/primitives/utils/auto_snap.dart';
+import 'package:fis_measure/utils/canvas.dart';
+import 'package:path_drawing/path_drawing.dart';
+
+import '../simpson_path.dart';
+
+class MultiSimpsonPath extends SimpsonPath {
+  MultiSimpsonPath(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    final rst = super.onExecuteMouse(args);
+    return rst;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    // TODO: implement onExecuteTouch
+    throw UnimplementedError();
+  }
+
+  static MultiSimpsonPath create(ItemMeta meta, [IMeasureItem? parent]) {
+    final path = MultiSimpsonPath(meta, parent);
+    return path;
+  }
+}
+
+class MultiSimpsonPathFeature extends SimpsonPathFeature {
+  MultiSimpsonPathFeature(super.refItem);
+
+  @override
+  MultiSimpsonPath get refItem => super.refItem as MultiSimpsonPath;
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    // TODO: implement paint
+    super.paint(canvas, size);
+  }
+}
+
+
+// class MultiSimpsonPath extends MeasureItem<MultiSimpsonPathFeature> {
+//   MultiSimpsonPath(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
+
+//   @override
+//   bool onExecuteMouse(PointInfo args) {
+//     // TODO: implement onExecuteMouse
+//     throw UnimplementedError();
+//   }
+
+//   @override
+//   bool onExecuteTouch(PointInfo args) {
+//     // TODO: implement onExecuteTouch
+//     throw UnimplementedError();
+//   }
+
+//   static MultiSimpsonPath create(ItemMeta meta, [IMeasureItem? parent]) {
+//     final path = MultiSimpsonPath(meta, parent);
+//     return path;
+//   }
+// }
+
+// class MultiSimpsonPathFeature extends MeasureItemFeature {
+//   MultiSimpsonPathFeature(super.refItem);
+
+//   @override
+//   MultiSimpsonPath get refItem => super.refItem as MultiSimpsonPath;
+
+//   @override
+//   void paint(Canvas canvas, Size size) {
+//     // TODO: implement paint
+//   }
+// }

+ 457 - 0
lib/process/primitives/simpson_path.dart

@@ -0,0 +1,457 @@
+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/items/item_metas.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/formulas/general.dart';
+import 'package:fis_measure/process/items/item.dart';
+import 'package:fis_measure/process/items/item_feature.dart';
+import 'package:fis_measure/process/primitives/polyline.dart';
+import 'package:fis_measure/process/primitives/area_abstract.dart';
+import 'package:fis_measure/process/primitives/utils/auto_snap.dart';
+import 'package:fis_measure/utils/canvas.dart';
+import 'package:flutter/foundation.dart';
+import 'package:path_drawing/path_drawing.dart';
+
+enum LvSimpsonStep {
+  none,
+  splineBeginEdit,
+  splineEditing,
+  splineEndEdit,
+  splineCompleted,
+  done,
+}
+
+class SimpsonPath extends AreaItemAbstract with AutoSnapMixin {
+  static const int SplitterCount = 20;
+  static const double MaxPointsCount = 10000;
+
+  SimpsonPath(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
+
+  PointInfo? firstPoint;
+
+  @protected
+  LvSimpsonStep lvSimpsonStep = LvSimpsonStep.none;
+
+  @override
+  SimpsonPathFeature? get feature => super.feature as SimpsonPathFeature;
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    if (state == ItemStates.finished) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        state = ItemStates.waiting;
+        lvSimpsonStep = LvSimpsonStep.none;
+      }
+    }
+
+    if (state == ItemStates.waiting) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        handleMouseDownWhileWaiting(args);
+      }
+    } else if (state == ItemStates.running) {
+      switch (args.pointType) {
+        case PointInfoType.mouseUp:
+          return false;
+        case PointInfoType.mouseDown:
+          if (lvSimpsonStep == LvSimpsonStep.splineCompleted) {
+            feature!.adjustEndPoint(args.toAreaLogicPoint());
+            lvSimpsonStep = LvSimpsonStep.done;
+            // CaliperExtension.ShowCaliper();
+          } else {
+            final lineLen = (args - firstPoint!).length;
+            if ((feature!.innerPoints.length > 3 &&
+                    GeneralFormulas.doubleAlmostEquals(lineLen, 0)) ||
+                feature!.innerPoints.length >= MaxPointsCount) {
+              lvSimpsonStep = LvSimpsonStep.splineCompleted;
+              feature!.fixedSpline();
+            } else {
+              feature!.adopt(args.toAreaLogicPoint());
+            }
+          }
+          break;
+        case PointInfoType.mouseMove:
+          if (lvSimpsonStep == LvSimpsonStep.splineCompleted) {
+            feature!.adjustEndPoint(args.toAreaLogicPoint());
+          } else {
+            if (!snapState) {
+              checkAutoSnap(args, false);
+            }
+            if (!snapState) {
+              feature!.updateActivePoint(args.toAreaLogicPoint());
+            }
+          }
+          break;
+        default:
+          break;
+      }
+    }
+
+    doCalculate();
+    if (args.pointType == PointInfoType.mouseDown) {
+      // doFeatureFinish();
+      if (state == ItemStates.waiting || state == ItemStates.finished) {
+        state = ItemStates.running;
+      }
+      if (state == ItemStates.running) {
+        updateStatus();
+      }
+    }
+
+    if (args.pointType == PointInfoType.mouseMove) {
+      updateStatus();
+    }
+    return true;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    // TODO: implement onExecuteTouch
+    throw UnimplementedError();
+  }
+
+  void handleMouseDownWhileWaiting(PointInfo args) {
+    // TODO: 判断是否当前area
+    // 转换为Area逻辑位置
+    feature = SimpsonPathFeature(this);
+    if (args.hostVisualArea != null) {
+      feature!.hostVisualArea = args.hostVisualArea;
+    }
+    final point = args.toAreaLogicPoint();
+    feature!.adopt(point);
+    feature!.adopt(point);
+    state = ItemStates.running;
+    firstPoint = args;
+  }
+
+  void updateStatus() {
+    switch (lvSimpsonStep) {
+      case LvSimpsonStep.splineCompleted:
+        firstPoint = null;
+        if (feature != null) {
+          feature!.activeIndex = feature!.innerPoints.length;
+        }
+        break;
+      case LvSimpsonStep.done:
+        state = ItemStates.finished;
+        if (feature != null) {
+          feature!.activeIndex = -1;
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  static SimpsonPath create(ItemMeta meta, [IMeasureItem? parent]) {
+    final path = SimpsonPath(meta, parent);
+    return path;
+  }
+}
+
+class SimpsonPathFeature extends AreaItemFeatureAbstract {
+  Map<int, double> horizontalSplitterLegths = {};
+  IPathGeometry? _pathGeometry;
+  List<DPoint>? _splinePoints;
+  IPathGeometry? _spline;
+  late DPoint _centerLineFixedPoint;
+  late DPoint _centerLineMovablePoint;
+  late DPoint _leftPoint;
+  late DPoint _rightPoint;
+  late DPoint _apexPoint;
+
+  SimpsonPathFeature(AreaItemAbstract refItem) : super(refItem) {
+    // _splinePoints = [];
+    _centerLineFixedPoint = DPointExt.empty;
+    _centerLineMovablePoint = DPointExt.empty;
+    _leftPoint = DPointExt.empty;
+    _rightPoint = DPointExt.empty;
+    _apexPoint = DPointExt.empty;
+  }
+
+  @override
+  SimpsonPath get refItem => super.refItem as SimpsonPath;
+
+  DPoint get centerLineMovablePoint => _centerLineMovablePoint;
+  set centerLineMovablePoint(DPoint val) {
+    if (val != _centerLineMovablePoint) {
+      _centerLineMovablePoint = val;
+
+      updateSplitters();
+      // OnVertexPointChanged();
+    }
+  }
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    if (innerPoints.isEmpty) return;
+
+    drawId(canvas, size);
+
+    final points = innerPoints.map((e) => convert2ViewPoint(size, e)).toList();
+    final startPoint = points.first;
+    drawVertex(canvas, startPoint.toOffset(), 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);
+    //   }
+    //   if (isClosed) {
+    //     path.lineTo(startPoint.x, startPoint.y);
+    //   }
+    //   canvas.drawPath(
+    //     path,
+    //     paintLinePan,
+    //   );
+    // }
+
+    drawVertex(canvas, points.last.toOffset(), isActive);
+  }
+
+  @override
+  void adopt(DPoint point) {
+    super.adopt(point);
+    recreateSpline(false);
+  }
+
+  void updateActivePoint(DPoint point) {
+    if (activeIndex > 0 && activeIndex <= innerPoints.length) {
+      // ActivePoint = point;
+      recreateSpline(false);
+    }
+  }
+
+  void fixedSpline() {
+    return;
+    if (innerPoints.isEmpty) {
+      return;
+    }
+    // _centerLineFixedPoint =
+    DPoint((innerPoints.last.x + innerPoints.first.x) * 0.5,
+        (innerPoints.last.y + innerPoints.first.y) * 0.5);
+
+    var movablePoint = DPoint(0, double.infinity);
+
+    // if (BaseType == MeasureTypes.SimpsonAutoTrace)
+    // {
+    //     movablePoint = InnerPoints[InnerPoints.Count >> 1];
+    // }
+    // else
+    // {
+    // var isFindMin = innerPoints[innerPoints.length >> 1].y - innerPoints[0].y < 0;
+    // if (AutoGetApexPoint)
+    // {
+    //     movablePoint = isFindMin ? movablePoint :  DPoint(0, double.negativeInfinity);
+    // }
+
+    // foreach (DPoint point in InnerPoints)
+    // {
+    //     if (AutoGetApexPoint && innerPoints.Count > 0)
+    //     {
+    //         if (isFindMin)
+    //         {
+    //             if (point.Y < movablePoint.Y)
+    //             {
+    //                 movablePoint = point;
+    //             }
+    //         }
+    //         else
+    //         {
+    //             if (point.Y > movablePoint.Y)
+    //             {
+    //                 movablePoint = point;
+    //             }
+    //         }
+    //     }
+    //     else
+    //     {
+    //         if (point.Y < movablePoint.Y)
+    //         {
+    //             movablePoint = point;
+    //         }
+    //     }
+    // }
+    // }
+
+    // if (_centerLineMovablePoint != movablePoint)
+    // {
+    //     _centerLineMovablePoint = movablePoint;
+    //     if (!DPointExtension.IsEmpty(_centerLineMovablePoint) && (BaseType != MeasureTypes.SimpsonAutoTrace))
+    //     {
+    //         _centerLineMovablePoint.SynchToMainMonitorScreen(HostArea);
+    //     }
+    // }
+    // UpdateSplitters();
+    // OnVertexPointChanged();
+  }
+
+  void adjustEndPoint(DPoint point) {
+    if (innerPoints.isEmpty) {
+      return;
+    }
+    var endPoint = point;
+    double minDistance = double.infinity;
+    if (_splinePoints != null) {
+      for (DPoint splinePoint in _splinePoints!) {
+        double distance = (point - splinePoint).length;
+        if (distance < minDistance) {
+          minDistance = distance;
+          endPoint = splinePoint;
+        }
+      }
+    }
+
+    centerLineMovablePoint = endPoint;
+  }
+
+  void recreateSpline(bool isClosed) {
+    // if (_breaker.Paused) {
+    //   return;
+    // }
+    final generator = SimpsonGeometryGenerator();
+    _pathGeometry ??= generator.createPathGeometry();
+
+    double tempCircumference = 0;
+    _spline = generator.createSpline(
+      innerPoints,
+      0.5,
+      null,
+      isClosed,
+      false,
+      0.005,
+      tempCircumference,
+      _splinePoints,
+    );
+
+    if (_spline != null && _splinePoints != null) {
+      _pathGeometry!.addGeometry(_spline!);
+    }
+  }
+
+  void updateSplitters() {
+    recreateSpline(true);
+
+    if (_spline != null && !_centerLineMovablePoint.isEmpty) {
+      var generator = SimpsonGeometryGenerator();
+      _pathGeometry!.clear();
+
+      if (innerPoints.isNotEmpty) {
+        _pathGeometry!.addGeometry(_spline!);
+
+        horizontalSplitterLegths = {};
+        generator.createSplitters(
+          _pathGeometry!,
+          _spline!,
+          _centerLineFixedPoint,
+          _centerLineMovablePoint,
+          horizontalSplitterLegths,
+        );
+
+        _pathGeometry!.addLineGeometry(
+          _centerLineFixedPoint,
+          _centerLineMovablePoint,
+        );
+      }
+    }
+  }
+}
+
+class SimpsonGeometryGenerator {
+  static const int splitterCount = 20;
+
+  void createSplitters(
+    IPathGeometry pathGeometry,
+    IPathGeometry spline,
+    DPoint centerLineFixedPoint,
+    DPoint centerLineMovablePoint,
+    Map<int, double> horizontalSplitterLegths,
+  ) {
+    // TODO: 辛普森绘制核心
+  }
+
+  IPathGeometry? createSpline(
+    List<DPoint> sourcePoints,
+    double tension,
+    List<double>? tensions,
+    bool isClosed,
+    bool isFilled,
+    double tolerance,
+    double length,
+    List<DPoint>? splinePoints,
+  ) {
+    length = 0;
+    if (sourcePoints.isEmpty) {
+      return null;
+    }
+    List<DPoint> samplePoints = [];
+    // var points = Spline.Create(sourcePoints, tension, tensions, isClosed, tolerance, true, out length, samplePoints,true);
+    var points = <DPoint>[];
+    // var myPoints = GeomTools.ToWindowPoints(points.ToArray());
+    // var polyLineSegment = new PolyLineSegment { Points = new PointCollection(myPoints) };
+    // var pathFigure = new PathFigure { IsClosed = isClosed, IsFilled = true, StartPoint = sourcePoints[0].ToWindowPoint() };
+    // pathFigure.Segments.Add(polyLineSegment);
+    var pathGeometry = Path();
+    // pathGeometry.Figures.Add(pathFigure);
+
+    splinePoints = points;
+    return PathGeometryContainer(pathGeometry);
+  }
+
+  IPathGeometry createPathGeometry() {
+    return PathGeometryContainer(Path());
+  }
+}
+
+class PathGeometryContainer implements IPathGeometry {
+  final pathList = <Path>[];
+  late final Path control;
+
+  PathGeometryContainer(Path geometry) {
+    control = geometry;
+  }
+
+  @override
+  void addGeometry(IPathGeometry geometry) {
+    // TODO:
+    // pathList.addAll(geometry.pathList);
+  }
+
+  void addPath(Path path) {
+    pathList.add(path);
+  }
+
+  @override
+  void clear() {
+    pathList.clear();
+  }
+
+  @override
+  void addLineGeometry(
+      DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {
+    final linePath = Path()
+      ..moveTo(centerLineFixedPoint.x, centerLineFixedPoint.y)
+      ..lineTo(centerLineMovablePoint.x, centerLineMovablePoint.y);
+    addPath(linePath);
+  }
+}
+
+abstract class IPathGeometry {
+  void clear();
+  void addGeometry(IPathGeometry spline);
+  void addLineGeometry(
+      DPoint centerLineFixedPoint, DPoint centerLineMovablePoint);
+}
+
+extension DPointExt on DPoint {
+  static final empty = DPoint(double.minPositive, double.minPositive);
+
+  bool get isEmpty {
+    return this == empty;
+  }
+}

+ 5 - 3
lib/process/primitives/utils/auto_snap.dart

@@ -37,7 +37,7 @@ mixin AutoSnapMixin<T extends MeasureItemFeature> on MeasureItem<T> {
   }
 
   /// 自动结束检测
-  bool checkAutoSnap(PointInfo current) {
+  bool checkAutoSnap(PointInfo current, [bool autoFinishFeature = true]) {
     if (feature == null || feature!.innerPoints.length < 3) {
       isSmartMove = false;
       return _syncState(false);
@@ -61,8 +61,10 @@ mixin AutoSnapMixin<T extends MeasureItemFeature> on MeasureItem<T> {
       // feature!.innerPoints.removeLast();
 
       HapticFeedback.heavyImpact();
-      doCalculate();
-      doFeatureFinish();
+      if (autoFinishFeature) {
+        doCalculate();
+        doFeatureFinish();
+      }
       isSmartMove = false;
       return _syncState(true);
     } else {