Browse Source

temp save

Melon 10 months ago
parent
commit
8c60ca5b7e

+ 18 - 0
lib/process/calcuators/formulas/cardiac.dart

@@ -218,4 +218,22 @@ class CardiacFormulas {
     }
     return index;
   }
+
+  /// <summary>
+  /// Formular : V= π/4×∑_(i=1)^20▒〖(a_i×b_i)〗×L/20
+  /// </summary>
+  /// <returns></returns>
+  static double lvSimsonVolume(double l, List<double>? a, List<double>? b,
+      [int num = 20]) {
+    double volume = double.nan;
+    if (a != null && b != null) {
+      double sum = 0;
+      for (int i = 0; i < num; i++) {
+        sum += a[i] * b[i] * l / num;
+      }
+      volume = math.pi / 4 * sum;
+    }
+
+    return volume;
+  }
 }

+ 5 - 1
lib/process/calcuators/lv_study.dart

@@ -29,7 +29,7 @@ class LvStudySimpleCal extends LvStudyCalculatorBase<LvStudy> {
 
     final feature = ref.feature!;
 
-    v = _ValTemp();
+    restoreVals();
     v.lvidd = pickChildFloatValue(kidLVIDd);
     v.lvids = pickChildFloatValue(kidLVIDs);
 
@@ -144,6 +144,10 @@ class LvStudyCalculatorBase<T extends TopMeasureItem>
     // TODO: implement calculate
   }
 
+  void restoreVals() {
+    v = _ValTemp();
+  }
+
   @protected
   void updateLVEDV() {
     if (v.lvidd == null) {

+ 75 - 2
lib/process/calcuators/simpson.dart

@@ -1,5 +1,10 @@
+import 'package:fis_measure/interfaces/process/items/terms.dart';
 import 'package:fis_measure/process/primitives/combos/simpson.dart';
+import 'package:fis_measure/process/primitives/multi_method/multi_simpson_path.dart';
+import 'package:fis_measure/process/primitives/simpson_path.dart';
+import 'package:vid/us/vid_us_unit.dart';
 
+import 'formulas/cardiac.dart';
 import 'lv_study.dart';
 
 class LvSimpsonCal extends LvStudyCalculatorBase<LvStudySimpson> {
@@ -21,7 +26,75 @@ class LvSingleSimpsonCal extends LvStudyCalculatorBase<LvStudySingleSimpson> {
 
   @override
   void calculate() {
-    // TODO: implement calculate
-    super.calculate();
+    if (ref.feature == null) return;
+
+    final feature = ref.feature!;
+
+    restoreVals();
+
+    for (var output in ref.meta.outputs) {
+      switch (output.name) {
+        // TODO: xxx
+        case MeasureTerms.LvStudySimple:
+          feature.updateStringValue(output, "");
+          break;
+        case MeasureTerms.LVEDV:
+          updateLVEDV();
+          break;
+        case MeasureTerms.LVESV:
+          updateLVESV();
+          break;
+        case MeasureTerms.SV:
+          updateSV();
+          break;
+        case MeasureTerms.EF:
+          updateEF();
+          break;
+        case MeasureTerms.FS:
+          updatePercentFS();
+          break;
+      }
+    }
+  }
+
+  @override
+  void updateLVEDV() {
+    final value = _calcLvedv(ref.lvedv);
+    if (value != null) {
+      updateFloatValueByName(MeasureTerms.LVEDV, value, unit: VidUsUnit.cm3);
+      v.lvedv = value;
+    }
+  }
+
+  @override
+  void updateLVESV() {
+    final value = _calcLvedv(ref.lvesv);
+    if (value != null) {
+      updateFloatValueByName(MeasureTerms.LVESV, value, unit: VidUsUnit.cm3);
+      v.lvesv = value;
+    }
+  }
+
+  double? _calcLvedv(MultiSimpsonPath item) {
+    if (item.feature == null) {
+      return null;
+    }
+
+    final feature = item.feature!;
+
+    double longDiameter = roundDouble(feature.centerLineLength);
+    int index = 0;
+    List<double> bDiameters =
+        List.generate(SimpsonPath.SplitterCount, (index) => 0);
+    feature.horizontalSplitterLegths.forEach((key, value) {
+      bDiameters[index++] = value;
+    });
+
+    return CardiacFormulas.lvSimsonVolume(
+      longDiameter,
+      bDiameters,
+      bDiameters,
+      SimpsonPath.SplitterCount,
+    );
   }
 }

+ 181 - 60
lib/process/primitives/simpson_path.dart

@@ -1,11 +1,13 @@
 import 'dart:ui';
 
 import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/date_types/vector.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/curve.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';
@@ -14,8 +16,11 @@ 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:flutter/rendering.dart';
 import 'package:path_drawing/path_drawing.dart';
 
+import 'spline.dart';
+
 enum LvSimpsonStep {
   none,
   splineBeginEdit,
@@ -153,23 +158,34 @@ class SimpsonPath extends AreaItemAbstract with AutoSnapMixin {
 }
 
 class SimpsonPathFeature extends AreaItemFeatureAbstract {
-  Map<int, double> horizontalSplitterLegths = {};
+  static const autoGetApexPoint = false; // TODO
+
+  late Map<int, double> horizontalSplitterLegths;
+  late DPoint moveBasedPoint;
+
   IPathGeometry? _pathGeometry;
   List<DPoint>? _splinePoints;
   IPathGeometry? _spline;
   late DPoint _centerLineFixedPoint;
   late DPoint _centerLineMovablePoint;
+
+  late MovablePointsInfo _movablePtsInfo;
   late DPoint _leftPoint;
   late DPoint _rightPoint;
   late DPoint _apexPoint;
 
   SimpsonPathFeature(AreaItemAbstract refItem) : super(refItem) {
-    // _splinePoints = [];
+    _splinePoints = [];
     _centerLineFixedPoint = DPointExt.empty;
     _centerLineMovablePoint = DPointExt.empty;
+
+    _movablePtsInfo = MovablePointsInfo.empty();
     _leftPoint = DPointExt.empty;
     _rightPoint = DPointExt.empty;
     _apexPoint = DPointExt.empty;
+
+    moveBasedPoint = DPointExt.empty;
+    horizontalSplitterLegths = {};
   }
 
   @override
@@ -181,10 +197,61 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
       _centerLineMovablePoint = val;
 
       updateSplitters();
-      // OnVertexPointChanged();
+      _onVertexPointChanged();
     }
   }
 
+  DPoint get centerLineFixedPoint => _centerLineFixedPoint;
+
+  MovablePointsInfo get movablePtsInfo => _movablePtsInfo;
+  set movablePtsInfo(MovablePointsInfo val) {
+    if (val != _movablePtsInfo) {
+      _movablePtsInfo = val;
+      _onSplineMovablePointsInfoChanged();
+    }
+  }
+
+  DPoint get leftPoint => _leftPoint;
+  set leftPoint(DPoint val) {
+    if (val != _leftPoint) {
+      _leftPoint = val;
+      _onVertexPointChanged();
+    }
+  }
+
+  DPoint get rightPoint => _rightPoint;
+  set rightPoint(DPoint val) {
+    if (val != _rightPoint) {
+      _rightPoint = val;
+      _onVertexPointChanged();
+    }
+  }
+
+  DPoint get apexPoint => _apexPoint;
+  set apexPoint(DPoint val) {
+    if (val != _apexPoint) {
+      _apexPoint = val;
+      _onVertexPointChanged();
+    }
+  }
+
+  double get centerLineLength {
+    final viewport = hostVisualArea!.viewport!;
+    final p1 = viewport.convert(_centerLineFixedPoint);
+    final p2 = viewport.convert(_centerLineMovablePoint);
+    final value = (p2 - p1).length.abs();
+    return value;
+  }
+
+  double get area {
+    final viewport = hostVisualArea!.viewport!;
+    final points = innerPoints.map((e) => viewport.convert(e)).toList();
+    final value = AreaPerimeterCal.calcArea(points);
+    return value;
+  }
+
+  bool isClosed = false; // TODO
+
   @override
   void paint(Canvas canvas, Size size) {
     if (innerPoints.isEmpty) return;
@@ -222,73 +289,70 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
 
   void updateActivePoint(DPoint point) {
     if (activeIndex > 0 && activeIndex <= innerPoints.length) {
-      // ActivePoint = point;
+      activePoint = point;
       recreateSpline(false);
     }
   }
 
+  DPoint get activePoint {
+    if (activeIndex < 0 || activeIndex >= innerPoints.length) {
+      throw IndexError.withLength(activeIndex, innerPoints.length);
+    }
+    return innerPoints[activeIndex];
+  }
+
+  set activePoint(DPoint val) {
+    if (activeIndex < 0 || activeIndex >= innerPoints.length) {
+      throw IndexError.withLength(activeIndex, innerPoints.length);
+    }
+    innerPoints[activeIndex] = val;
+  }
+
   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);
+    _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);
-    // }
+    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;
-    //         }
-    //     }
-    // }
-    // }
+    for (DPoint point in innerPoints) {
+      if (autoGetApexPoint && innerPoints.isNotEmpty) {
+        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();
+    if (_centerLineMovablePoint != movablePoint) {
+      _centerLineMovablePoint = movablePoint;
+      if (!_centerLineMovablePoint.isEmpty) {
+        // TODO 重设光标位置,暂不支持
+        // _centerLineMovablePoint.SynchToMainMonitorScreen(HostArea);
+      }
+    }
+    updateSplitters();
+    _onVertexPointChanged();
   }
 
   void adjustEndPoint(DPoint point) {
@@ -360,6 +424,9 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
       }
     }
   }
+
+  void _onVertexPointChanged() {}
+  void _onSplineMovablePointsInfoChanged() {}
 }
 
 class SimpsonGeometryGenerator {
@@ -372,7 +439,49 @@ class SimpsonGeometryGenerator {
     DPoint centerLineMovablePoint,
     Map<int, double> horizontalSplitterLegths,
   ) {
+    if (centerLineFixedPoint.isEmpty || centerLineMovablePoint.isEmpty) {
+      return;
+    }
+
     // TODO: 辛普森绘制核心
+
+    // Center line
+    DVector centerLine = centerLineMovablePoint - centerLineFixedPoint;
+    var horizontalStart = DPoint(-50, centerLineFixedPoint.y);
+    // horizonta line
+    DVector horizontalLine = horizontalStart - centerLineFixedPoint;
+    // Get angle between horizontal and center line
+    double angle = DVector.angleBetween(horizontalLine, centerLine);
+    double angleToVertical = 90.0 - angle;
+
+    double cellHeight = centerLine.length / splitterCount;
+
+    //Create a 20 splitters path geometry
+    PathGeometryContainer temSplittersGeometry = PathGeometryContainer(Path());
+    for (int i = 1; i <= splitterCount; i++) {
+      double midPointY =
+          centerLineFixedPoint.y - cellHeight * (i - 1) - cellHeight / 2;
+      //horizontal splitter line
+      final tempLinePath = Path();
+      tempLinePath.moveTo(-50, midPointY);
+      tempLinePath.lineTo(50, midPointY);
+
+      var matrix = Matrix4.identity();
+      matrix.rotateZ(angleToVertical * 0.0174533); // Convert degrees to radians
+      // matrix.translate(centerLineFixedPoint.dx, centerLineFixedPoint.dy);
+      matrix.scale(1, 1, 1); // Adjust scale if needed
+      matrix.translate(
+          -50, -midPointY); // Adjust translation to center the line
+      // tempLinePath.transform(matrix)
+      // LineGeometry templineGeometry =
+      //     new LineGeometry(Point(-50, midPointY), Point(50, midPointY));
+      // templineGeometry.Transform = new RotateTransform(
+      //     -angleToVertical, centerLineFixedPoint.x, centerLineFixedPoint.y);
+      // temSplittersGeometry.addGeometry(templineGeometry);
+    }
+
+    List<DPoint> leftPoints = [];
+    List<DPoint> rightPoints = [];
   }
 
   IPathGeometry? createSpline(
@@ -390,7 +499,7 @@ class SimpsonGeometryGenerator {
       return null;
     }
     List<DPoint> samplePoints = [];
-    // var points = Spline.Create(sourcePoints, tension, tensions, isClosed, tolerance, true, out length, samplePoints,true);
+    // 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) };
@@ -410,6 +519,7 @@ class SimpsonGeometryGenerator {
 
 class PathGeometryContainer implements IPathGeometry {
   final pathList = <Path>[];
+  final geometries = <IPathGeometry>[];
   late final Path control;
 
   PathGeometryContainer(Path geometry) {
@@ -418,8 +528,7 @@ class PathGeometryContainer implements IPathGeometry {
 
   @override
   void addGeometry(IPathGeometry geometry) {
-    // TODO:
-    // pathList.addAll(geometry.pathList);
+    geometries.add(geometry);
   }
 
   void addPath(Path path) {
@@ -455,3 +564,15 @@ extension DPointExt on DPoint {
     return this == empty;
   }
 }
+
+class MovablePointsInfo {
+  int index;
+  int start;
+  int end;
+
+  MovablePointsInfo(this.index, this.start, this.end);
+
+  factory MovablePointsInfo.empty() {
+    return MovablePointsInfo(-1, -1, -1);
+  }
+}