Browse Source

fix 19024: 【图像测量】【小动物】LV Study / LV Study(simple) / 辛普森 测量项测量结果中单位(cm³,kg)需调整为与超声机一致ml g

Melon 9 months ago
parent
commit
c4d97f9064

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

@@ -510,8 +510,7 @@ class LvStudyCalculatorBase<T extends TopMeasureItem>
     ref.measuredFeatures;
     final feature = ref.feature!;
     final outputMeta = ref.meta.outputs.firstWhere((x) => x.name == name);
-    outputMeta.unit = updateUnitBySpeciesType(unit ?? outputMeta.unit, name);
-    feature.updateFloatValue(outputMeta, value, outputMeta.unit);
+    feature.updateFloatValue(outputMeta, value, unit ?? outputMeta.unit);
   }
 
   VidUsUnit updateUnitBySpeciesType(VidUsUnit unit, String name) {

+ 213 - 17
lib/process/calcuators/simpson.dart

@@ -1,3 +1,5 @@
+// ignore_for_file: non_constant_identifier_names
+
 import 'package:fis_measure/interfaces/process/items/item_metas.dart';
 import 'package:fis_measure/interfaces/process/items/terms.dart';
 import 'package:fis_measure/process/primitives/combos/simpson.dart';
@@ -7,6 +9,7 @@ import 'package:vid/us/vid_us_unit.dart';
 
 import 'formulas/cardiac.dart';
 import 'lv_study.dart';
+import 'dart:math' as math;
 
 class LvSimpsonCal extends LvStudyCalculatorBase<LvStudySimpson> {
   LvSimpsonCal(super.ref) {
@@ -27,6 +30,10 @@ class LvSimpsonCal extends LvStudyCalculatorBase<LvStudySimpson> {
       "",
     );
 
+    for (var childItem in ref.childItems) {
+      _clacChildItem(childItem as MultiSimpsonPath);
+    }
+
     for (var output in ref.meta.outputs) {
       switch (output.name) {
         case MeasureTerms.LVEDV:
@@ -55,11 +62,14 @@ class LvSimpsonCal extends LvStudyCalculatorBase<LvStudySimpson> {
           break;
       }
     }
+
+    // _updateA2cGroup();
+    // _updateA4cGroup();
   }
 
   @override
   void updateLVEDV() {
-    final value = _clacLvedv(ref.a2cLvedv, ref.a4cLvedv);
+    final value = _clacLvedvNew(ref.a2cLvedv, ref.a4cLvedv);
     if (value != null) {
       updateFloatValueByName(MeasureTerms.LVEDV, value, unit: VidUsUnit.cm3);
       v.lvedv = value;
@@ -68,42 +78,160 @@ class LvSimpsonCal extends LvStudyCalculatorBase<LvStudySimpson> {
 
   @override
   void updateLVESV() {
-    final value = _clacLvedv(ref.a2cLvesv, ref.a4cLvesv);
+    final value = _clacLvedvNew(ref.a2cLvesv, ref.a4cLvesv);
     if (value != null) {
       updateFloatValueByName(MeasureTerms.LVESV, value, unit: VidUsUnit.cm3);
       v.lvesv = value;
     }
   }
 
-  double? _clacLvedv(MultiSimpsonPath a2c, MultiSimpsonPath a4c) {
-    final a2cFeature = findChildFeature(a2c);
-    final a4cFeature = findChildFeature(a4c);
-    if (a2cFeature == null || a4cFeature == null) {
+  double? _clacLvedv(MultiSimpsonPath path1, MultiSimpsonPath path2) {
+    final feature1 = findChildFeature(path1);
+    final feature2 = findChildFeature(path2);
+    if (feature1 == null || feature2 == null) {
       return null;
     }
-    a2cFeature as SimpsonPathFeature;
-    a4cFeature as SimpsonPathFeature;
-    double a2cL = a2cFeature.centerLineLength;
-    double a4cL = a4cFeature.centerLineLength;
+    feature1 as SimpsonPathFeature;
+    feature2 as SimpsonPathFeature;
+    final distance1 = feature1.centerLineLength;
+    final distance2 = feature2.centerLineLength;
+
+    int index = 0;
 
     List<double> aDiameters =
         List.generate(SimpsonPath.splitterCount, (index) => 0);
-    int index = 0;
-    a4cFeature.horizontalSplitterLegths.forEach((key, value) {
+    index = 0;
+    feature1.horizontalSplitterLegths.forEach((key, value) {
       aDiameters[index++] = value;
     });
 
     List<double> bDiameters =
         List.generate(SimpsonPath.splitterCount, (index) => 0);
     index = 0;
-    a2cFeature.horizontalSplitterLegths.forEach((key, value) {
+    feature2.horizontalSplitterLegths.forEach((key, value) {
       bDiameters[index++] = value;
     });
-    final longDiameter = (a2cL + a4cL) / 2.0;
+
+    final longDiameter = (distance1 + distance2) / 2.0;
     final lvesv = CardiacFormulas.lvSimsonVolume(
-        longDiameter, aDiameters, bDiameters, SimpsonPath.splitterCount);
+      longDiameter,
+      aDiameters,
+      bDiameters,
+      SimpsonPath.splitterCount,
+    );
     return lvesv;
   }
+
+  double? _clacLvedvNew(MultiSimpsonPath path1, MultiSimpsonPath path2) {
+    final feature1 = findChildFeature(path1);
+    final feature2 = findChildFeature(path2);
+    if (feature1 == null || feature2 == null) {
+      return null;
+    }
+    feature1 as SimpsonPathFeature;
+    feature2 as SimpsonPathFeature;
+    final distance1 = feature1.centerLineLength;
+    final distance2 = feature2.centerLineLength;
+
+    int index = 0;
+
+    List<double> aDiameters =
+        List.generate(SimpsonPath.splitterCount, (index) => 0);
+    index = 0;
+    feature1.horizontalSplitterLegths.forEach((key, value) {
+      aDiameters[index++] = value;
+    });
+
+    List<double> bDiameters =
+        List.generate(SimpsonPath.splitterCount, (index) => 0);
+    index = 0;
+    feature2.horizontalSplitterLegths.forEach((key, value) {
+      bDiameters[index++] = value;
+    });
+
+    double sum = 0;
+    for (var i = 0; i < SimpsonPath.splitterCount; i++) {
+      sum += aDiameters[i] * bDiameters[i];
+    }
+    final maxL = math.max(distance1, distance2);
+    final value = maxL * 3.1415926 / (4 * 20) * sum;
+    return value;
+  }
+
+  void _clacChildItem(MultiSimpsonPath childItem) {
+    final feature = findChildFeature(childItem);
+    if (feature == null) {
+      return;
+    }
+    feature as SimpsonPathFeature;
+
+    // final outputs = childItem.meta.outputs;
+    // TODO:
+    final itemName = childItem.meta.description.split(' ').first;
+    final outputs = [
+      ItemOutputMeta("Area", "$itemName LVAs", VidUsUnit.mm2),
+      ItemOutputMeta("L", "$itemName LVLs", VidUsUnit.mm),
+    ];
+    for (var output in outputs) {
+      switch (output.name) {
+        case "Area":
+          feature.updateFloatValue(output, feature.area, VidUsUnit.cm2);
+          break;
+        case "L":
+          feature.updateFloatValue(
+              output, feature.centerLineLength, VidUsUnit.cm);
+          break;
+        default:
+      }
+    }
+  }
+
+  void _updateA2cGroup() {
+    _updateLVEDV_A2C();
+    _updateLVESV_A2C();
+  }
+
+  void _updateA4cGroup() {
+    _updateLVEDV_A2C();
+    _updateLVESV_A2C();
+  }
+
+  void _updateLVEDV_A2C() {
+    final feature = findChildFeature(ref.a2cLvedv);
+    if (feature == null) {
+      return;
+    }
+    feature as SimpsonPathFeature;
+    final value = _SimpsonFormulas.lvedv(
+      feature.area,
+      feature.centerLineLength,
+    );
+    ref.feature!.updateFloatValue(
+      ItemOutputMeta("LVEDV(A2C Simp)", "LVEDV(A2C Simp)", VidUsUnit.ml),
+      value,
+      VidUsUnit.ml,
+    );
+  }
+
+  void _updateLVESV_A2C() {
+    final feature = findChildFeature(ref.a2cLvesv);
+    if (feature == null) {
+      return;
+    }
+    feature as SimpsonPathFeature;
+    final value = _SimpsonFormulas.lvedv(
+      feature.area,
+      feature.centerLineLength,
+    );
+    ref.feature!.updateFloatValue(
+      ItemOutputMeta("LVESV(A2C Simp)", "LVESV(A2C Simp)", VidUsUnit.ml),
+      value,
+      VidUsUnit.ml,
+    );
+  }
+
+  void _updateLVEDV_A4C() {}
+  void _updateLVESV_A4C() {}
 }
 
 class LvSingleSimpsonCal extends LvStudyCalculatorBase<LvStudySingleSimpson> {
@@ -125,6 +253,8 @@ class LvSingleSimpsonCal extends LvStudyCalculatorBase<LvStudySingleSimpson> {
       "",
     );
 
+    _clacChildItem(ref.lvedv);
+
     for (var output in ref.meta.outputs) {
       switch (output.name) {
         case MeasureTerms.LVEDV:
@@ -167,7 +297,7 @@ class LvSingleSimpsonCal extends LvStudyCalculatorBase<LvStudySingleSimpson> {
 
   @override
   void updateLVEDV() {
-    final value = _calcLvedv(ref.lvedv);
+    final value = _calcLvedvNew(ref.lvedv);
     if (value != null) {
       updateFloatValueByName(MeasureTerms.LVEDV, value, unit: VidUsUnit.cm3);
       v.lvedv = value;
@@ -176,7 +306,7 @@ class LvSingleSimpsonCal extends LvStudyCalculatorBase<LvStudySingleSimpson> {
 
   @override
   void updateLVESV() {
-    final value = _calcLvedv(ref.lvesv);
+    final value = _calcLvedvNew(ref.lvesv);
     if (value != null) {
       updateFloatValueByName(MeasureTerms.LVESV, value, unit: VidUsUnit.cm3);
       v.lvesv = value;
@@ -205,4 +335,70 @@ class LvSingleSimpsonCal extends LvStudyCalculatorBase<LvStudySingleSimpson> {
       SimpsonPath.splitterCount,
     );
   }
+
+  double? _calcLvedvNew(MultiSimpsonPath item) {
+    final feature = findChildFeature(item);
+    if (feature == null) {
+      return null;
+    }
+
+    feature as SimpsonPathFeature;
+
+    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;
+    });
+
+    double sum = 0;
+    for (var i = 0; i < SimpsonPath.splitterCount; i++) {
+      sum += math.pow(bDiameters[i], 2).toDouble();
+    }
+    var value = longDiameter * 3.1415926 / (4 * 20) * sum;
+    return value;
+
+    return CardiacFormulas.lvSimsonVolume(
+      longDiameter,
+      bDiameters,
+      bDiameters,
+      SimpsonPath.splitterCount,
+    );
+  }
+
+  void _clacChildItem(MultiSimpsonPath childItem) {
+    final feature = findChildFeature(childItem);
+    if (feature == null) {
+      return;
+    }
+    feature as SimpsonPathFeature;
+
+    // final outputs = childItem.meta.outputs;
+    // TODO:
+    final itemName = childItem.meta.description.split(' ').first;
+    final outputs = [
+      ItemOutputMeta("Area", "$itemName LVAs", VidUsUnit.mm2),
+      ItemOutputMeta("L", "$itemName LVLs", VidUsUnit.mm),
+    ];
+    for (var output in outputs) {
+      switch (output.name) {
+        case "Area":
+          feature.updateFloatValue(output, feature.area, VidUsUnit.cm2);
+          break;
+        case "L":
+          feature.updateFloatValue(
+              output, feature.centerLineLength, VidUsUnit.cm);
+          break;
+        default:
+      }
+    }
+  }
+}
+
+abstract class _SimpsonFormulas {
+  static double lvedv(double area, double distance) {
+    final value = 0.85 * math.pow(area, 2) / distance;
+    return value;
+  }
 }

+ 16 - 7
lib/process/primitives/simpson_path.dart

@@ -4,6 +4,7 @@ import 'dart:math' as math;
 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/calculators/values.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';
@@ -16,12 +17,14 @@ 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/process/unit/convert/convert.dart';
 import 'package:fis_measure/utils/canvas.dart';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
 import 'package:get/get.dart';
 import 'package:path_drawing/path_drawing.dart';
+import 'package:vid/us/vid_us_unit.dart';
 
 import 'spline.dart';
 import 'utils/line.dart';
@@ -258,20 +261,26 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
   }
 
   double get centerLineLength {
-    final viewport = hostVisualArea!.viewport!;
-    final p1 = viewport.convert(_centerLineFixedPoint);
-    final p2 = viewport.convert(_centerLineMovablePoint);
-    final value = (p2 - p1).length.abs();
+    final p1 = convert2CmPoint(_centerLineFixedPoint);
+    final p2 = convert2CmPoint(_centerLineMovablePoint);
+    double 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);
+    final points = innerPoints.map((e) => convert2CmPoint(e)).toList();
+    double value = AreaPerimeterCal.calcArea(points);
     return value;
   }
 
+  DPoint convert2CmPoint(DPoint logicPoint) {
+    final viewport = hostVisualArea!.viewport!;
+    final p = viewport.convert(logicPoint);
+    p.x = UnitValueConverter.convert(viewport.xUnit, VidUsUnit.cm, p.x);
+    p.y = UnitValueConverter.convert(viewport.yUnit, VidUsUnit.cm, p.y);
+    return p;
+  }
+
   bool isClosed = false; // TODO
 
   @override

+ 1 - 1
lib/view/measure/measure_view_controller.dart

@@ -148,7 +148,7 @@ class MeasureMetaController extends GetxController {
                     !MeasureUnsupportedTerms.items.contains(element.name))
                 .map((element) {
                   try {
-                    if (element.name == 'Qp/Qs') {
+                    if (element.name == 'LV Study') {
                       print(element);
                     }
                     return ItemMetaConverter(element).output();

+ 70 - 14
lib/view/result/converter.dart

@@ -18,6 +18,9 @@ class FeatureValueDescConverter {
   String idPlaceStr = ' ';
   String idStr = ' ';
 
+  String kidIdPlaceStr = ' ';
+  String kidIdStr = ' ';
+
   List<ResultLine> generate(int idLength) {
     idPlaceStr = ' '.padRight(idLength, ' ');
     idStr = feature.id.toString().padRight(idLength, ' ');
@@ -28,25 +31,32 @@ class FeatureValueDescConverter {
 
     final ref = feature.refItem;
     if (ref is ITopMeasureItem && ref.canChildOutputSelf) {
-      for (var child in ref.childItems) {
-        for (var feature in child.measuredFeatures) {
-          final str = _findChildLine(feature);
-          if (str != null && str.isNotEmpty) {
-            arr.add(str);
-          }
-        }
-        if (child.feature != null) {
-          final str = _findChildLine(child.feature!);
-          if (str != null && str.isNotEmpty) {
-            arr.add(str);
-          }
-        }
-      }
+      _buildChildOutputs(arr, ref.childItems);
     }
 
     return arr;
   }
 
+  void _buildChildOutputs(List<ResultLine> arr, List<IMeasureItem> childItems) {
+    for (var i = 0; i < childItems.length; i++) {
+      kidIdPlaceStr = '   '.padRight(2, ' ');
+      kidIdStr = "  ${i + 1}".padRight(2, ' ');
+
+      final child = childItems[i];
+      for (final feature in child.measuredFeatures) {
+        arr.addAll(_pickFeatureLines(feature));
+      }
+      if (child.feature != null) {
+        arr.addAll(_pickFeatureLines(child.feature!));
+      }
+    }
+  }
+
+  List<ResultLine> _pickFeatureLines(IMeasureItemFeature feature) {
+    final lines = _findKidFeatureLines(feature);
+    return lines;
+  }
+
   ResultLine? _findChildLine(IMeasureItemFeature feature) {
     if (feature.value == null) return null;
 
@@ -58,6 +68,30 @@ class FeatureValueDescConverter {
     return ResultLine(label: ' $idPlaceStr $name', value: valueStr);
   }
 
+  List<ResultLine> _findKidFeatureLines(IMeasureItemFeature feature) {
+    final count = feature.values.length;
+    final itemName = _findMetaDisplayName(feature.refItem.meta, true);
+    if (count == 0) {
+      return [];
+    }
+
+    List<ResultLine> arr = [];
+    for (var i = 0; i < count; i++) {
+      final val = feature.values[i];
+      final meta = val.meta;
+      final valueStr = _pickValueStr(val);
+
+      if (i == 0) {
+        arr.add(ResultLine(label: "$kidIdStr $itemName", value: valueStr));
+      } else {
+        final name = _findOutputMetaDisplayName(
+            meta, feature.featureStyle.showBriefAnnotation);
+        arr.add(ResultLine(label: "$kidIdPlaceStr $name", value: valueStr));
+      }
+    }
+    return arr;
+  }
+
   List<ResultLine> _findFeatureLines(IMeasureItemFeature feature) {
     final count = feature.values.length;
     final itemName = _findMetaDisplayName(
@@ -182,5 +216,27 @@ class FeatureValueDescConverter {
   static final List<VidUsUnit> timeUnits = [
     VidUsUnit.msec,
     VidUsUnit.s,
+    VidUsUnit.hour,
+    VidUsUnit.minute,
+  ];
+
+  static final List<VidUsUnit> volumeUnits = [
+    VidUsUnit.cm3,
+    VidUsUnit.ml,
+    VidUsUnit.mm3,
+    VidUsUnit.L,
+  ];
+
+  static final List<VidUsUnit> weightUnits = [
+    VidUsUnit.kg,
+    VidUsUnit.g,
+    VidUsUnit.mg,
+  ];
+
+  static final List<VidUsUnit> pressureUnits = [
+    VidUsUnit.cm3s,
+    VidUsUnit.mls,
+    VidUsUnit.mlmin,
+    VidUsUnit.Lmin,
   ];
 }