Melon 10 luni în urmă
părinte
comite
3bf554c2c5

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

@@ -51,6 +51,13 @@ class CardiacFormulas {
           [int num = 20]) =>
       _singleton.lvSimsonVolume(l, a, b, num);
 
+  static double mrEROA(double mrRadius, double mrAlsVel, double mrVmax) =>
+      _singleton.mrEROA(mrRadius, mrAlsVel, mrVmax);
+  static double mrRV(double mrEROA, double mrVti) =>
+      _singleton.mrRV(mrEROA, mrVti);
+  static double mrFlowRate(double mrRadius, double mrAlsVel) =>
+      _singleton.mrFlowRate(mrRadius, mrAlsVel);
+
   // CardiacFormulas._internal(); // 私有构造函数
 }
 
@@ -78,6 +85,10 @@ abstract class ICardiacFormulaStrategy {
   double lvevi(double lvev, double bsa);
   double lvSimsonVolume(double l, List<double>? a, List<double>? b,
       [int num = 20]);
+
+  double mrEROA(double mrRadius, double mrAlsVel, double mrVmax);
+  double mrRV(double mrEROA, double mrVti);
+  double mrFlowRate(double mrRadius, double mrAlsVel);
 }
 
 /// 基础公式
@@ -343,6 +354,26 @@ class BaseCardiacFormulas implements ICardiacFormulaStrategy {
 
     return volume;
   }
+
+  @override
+  double mrEROA(double mrRadius, double mrAlsVel, double mrVmax) {
+    double mrEROA = double.nan;
+    if (!GeneralFormulas.doubleAlmostEquals(mrVmax, 0)) {
+      mrEROA = 2 * math.pi * math.pow(mrRadius, 2) * mrAlsVel / (mrVmax).abs();
+    }
+    return mrEROA;
+  }
+
+  @override
+  double mrRV(double mrEROA, double mrVti) {
+    return mrEROA * mrVti;
+  }
+
+  @override
+  double mrFlowRate(double mrRadius, double mrAlsVel) {
+    double flowRate = 2 * math.pi * math.pow(mrRadius, 2) * mrAlsVel;
+    return flowRate;
+  }
 }
 
 /// 实验室小鼠

+ 81 - 1
lib/process/calcuators/pisa.dart

@@ -1,16 +1,96 @@
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'package:fis_measure/interfaces/process/items/terms.dart';
+import 'package:fis_measure/process/calcuators/formulas/cardiac.dart';
 import 'package:fis_measure/process/primitives/combos/pisa.dart';
+import 'package:vid/us/vid_us_unit.dart';
 
 import 'calculator.dart';
+import 'trace.dart';
 
 class PisaCal extends Calculator<Pisa, double> {
   PisaCal(super.ref);
 
+  static const String vMaxKey = "Vmax";
+  static const String rvKey = "RV";
+  static const String eroaKey = "EROA";
+  static const String flowRateKey = "Flow Rate";
+
   @override
   void calculate() {
     if (ref.feature == null) return;
 
     final feature = ref.feature!;
 
-    //
+    feature.values.clear();
+
+    feature.updateStringValue(
+      ItemOutputMeta(ref.displayName, ref.description, VidUsUnit.None),
+      '',
+    );
+
+    // final yUnit= ref.application.currentViewPort.yUnit;
+
+    double mrRadius = double.nan;
+    double vti = double.nan;
+    double mrVmax = double.nan;
+
+    final radiusFeature = findChildFeature(ref.radius);
+    if (radiusFeature != null) {
+      mrRadius = pickChildFloatValue(ref.radius)!;
+      final output = ref.radius.meta.outputs.first;
+      feature.updateFloatValue(output, mrRadius, VidUsUnit.cm);
+    }
+    final vtiFeature = findChildFeature(ref.trace);
+    if (vtiFeature != null) {
+      final countVTIResult = TraceCal.getCountVTI(vtiFeature);
+      var outputVTI = countVTIResult[0];
+      var outputVelocityMax = countVTIResult[3];
+
+      vti = outputVTI;
+      mrVmax = outputVelocityMax;
+
+      final outputs = ref.radius.meta.outputs;
+      for (var output in outputs) {
+        if (output.name == MeasureTerms.Placeholder) {
+          feature.updateStringValue(output, "");
+        } else if (output.name == MeasureTerms.VTI) {
+          feature.updateFloatValue(output, vti, VidUsUnit.cm);
+        } else if (output.name == MeasureTerms.VelocityMax) {
+          feature.updateFloatValue(output, mrVmax, VidUsUnit.cms);
+        }
+      }
+    }
+
+    double mrAlsVel = ref.alsVel;
+
+    double mrRV = double.nan;
+    double mrEROA = double.nan;
+    double mrFlowRate = double.nan;
+
+    if (!mrRadius.isNaN && !vti.isNaN && !mrVmax.isNaN && !mrAlsVel.isNaN) {
+      mrEROA = CardiacFormulas.mrEROA(mrRadius, mrAlsVel, mrVmax);
+      mrRV = CardiacFormulas.mrRV(mrEROA, vti);
+      mrFlowRate = CardiacFormulas.mrFlowRate(mrRadius, mrAlsVel);
+    }
+
+    for (var output in ref.meta.outputs) {
+      if (output.name == rvKey) {
+        if (!mrRV.isNaN) {
+          feature.updateFloatValue(output, mrVmax, VidUsUnit.ml);
+        }
+      } else if (output.name == eroaKey) {
+        if (!mrEROA.isNaN) {
+          feature.updateFloatValue(output, mrEROA, VidUsUnit.cm2);
+        }
+      } else if (output.name == flowRateKey) {
+        if (!mrFlowRate.isNaN) {
+          feature.updateFloatValue(output, mrFlowRate, VidUsUnit.mls);
+        }
+      } else if (output.name == MeasureTerms.AlsVel) {
+        if (!mrAlsVel.isNaN) {
+          feature.updateFloatValue(output, mrAlsVel, VidUsUnit.cms);
+        }
+      }
+    }
   }
 }

+ 2 - 1
lib/process/primitives/combos/pisa.dart

@@ -10,6 +10,7 @@ import '../straightline.dart';
 class Pisa extends TopMeasureItem<PisaFeature> {
   late final StraightLine radius;
   late final MultiTrace trace;
+  double alsVel = 65.9; // TODO: 可手动设置 cm/s
 
   Pisa(super.meta) {
     final metaRadius = meta.childItems[0];
@@ -19,7 +20,7 @@ class Pisa extends TopMeasureItem<PisaFeature> {
     childItems.add(radius);
     childItems.add(trace);
     isCrossAreaMode = true;
-    // canChildOutputSelf = false;
+    canChildOutputSelf = false;
   }
 
   @override