|
@@ -1,12 +1,19 @@
|
|
|
// ignore_for_file: non_constant_identifier_names
|
|
|
|
|
|
+import 'package:fis_measure/configs/patient.dart';
|
|
|
+import 'package:fis_measure/interfaces/process/calculators/values.dart';
|
|
|
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/unit_formulas/base/utils.dart';
|
|
|
+import 'package:fis_measure/process/calcuators/unit_formulas/index.dart';
|
|
|
+import 'package:fis_measure/process/items/item_feature.dart';
|
|
|
+import 'package:fis_measure/process/items/top_item.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 'calculator.dart';
|
|
|
import 'formulas/cardiac.dart';
|
|
|
import 'lv_study.dart';
|
|
|
import 'dart:math' as math;
|
|
@@ -402,3 +409,342 @@ abstract class _SimpsonFormulas {
|
|
|
return value;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+class LvSimpsonCalNew extends LvSimpsonCalBase<LvStudySimpson> {
|
|
|
+ LvSimpsonCalNew(super.ref) {
|
|
|
+ //
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void calculate() {
|
|
|
+ super.calculate();
|
|
|
+
|
|
|
+ if (ref.feature == null) return;
|
|
|
+
|
|
|
+ final feature = ref.feature!;
|
|
|
+
|
|
|
+ feature.updateStringValue(
|
|
|
+ ItemOutputMeta(
|
|
|
+ ref.meta.description, ref.meta.description, VidUsUnit.None),
|
|
|
+ "",
|
|
|
+ );
|
|
|
+
|
|
|
+ for (var childItem in ref.childItems) {
|
|
|
+ clacChildItem(childItem as MultiSimpsonPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ calcCouple();
|
|
|
+ calcA2c(ref.a2cLvedv, ref.a2cLvesv);
|
|
|
+ calcA2c(ref.a4cLvedv, ref.a4cLvesv);
|
|
|
+
|
|
|
+ doOutput();
|
|
|
+ }
|
|
|
+
|
|
|
+ void calcCouple() {
|
|
|
+ final featureA2cD = findChildFeature(ref.a2cLvedv);
|
|
|
+ final featureA2cS = findChildFeature(ref.a2cLvesv);
|
|
|
+ final featureA4cD = findChildFeature(ref.a4cLvedv);
|
|
|
+ final featureA4cS = findChildFeature(ref.a4cLvesv);
|
|
|
+
|
|
|
+ UnitFloatValue? edv;
|
|
|
+ UnitFloatValue? esv;
|
|
|
+
|
|
|
+ if (featureA2cD != null && featureA4cD != null) {
|
|
|
+ edv = coupleLVEDV(
|
|
|
+ featureA4cD as SimpsonPathFeature,
|
|
|
+ featureA2cD as SimpsonPathFeature,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (featureA2cS != null && featureA4cS != null) {
|
|
|
+ esv = coupleLVEDV(
|
|
|
+ featureA4cS as SimpsonPathFeature,
|
|
|
+ featureA2cS as SimpsonPathFeature,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ v.coupleEDV = edv;
|
|
|
+ v.coupleESV = esv;
|
|
|
+ if (edv != null && esv != null) {
|
|
|
+ v.coupleSV = calcSv(edv, esv);
|
|
|
+ v.coupleEF = calcEf(edv, esv);
|
|
|
+ v.coupleCO = calcCo(edv, esv);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class LvSingleSimpsonCalNew extends LvSimpsonCalBase<LvStudySingleSimpson> {
|
|
|
+ LvSingleSimpsonCalNew(super.ref) {
|
|
|
+ //
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void calculate() {
|
|
|
+ super.calculate();
|
|
|
+
|
|
|
+ if (ref.feature == null) return;
|
|
|
+
|
|
|
+ final feature = ref.feature!;
|
|
|
+
|
|
|
+ feature.updateStringValue(
|
|
|
+ ItemOutputMeta(
|
|
|
+ ref.meta.description, ref.meta.description, VidUsUnit.None),
|
|
|
+ "",
|
|
|
+ );
|
|
|
+
|
|
|
+ for (var childItem in ref.childItems) {
|
|
|
+ clacChildItem(childItem as MultiSimpsonPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ref.meta.description.toLowerCase().contains("a2c")) {
|
|
|
+ calcA2c(ref.lvedv, ref.lvesv);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ref.meta.description.toLowerCase().contains("a4c")) {
|
|
|
+ calcA4c(ref.lvedv, ref.lvesv);
|
|
|
+ }
|
|
|
+
|
|
|
+ doOutput();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+abstract class LvSimpsonCalBase<T extends TopMeasureItem>
|
|
|
+ extends Calculator<T, double> {
|
|
|
+ LvSimpsonCalBase(super.ref);
|
|
|
+
|
|
|
+ _SimpsonValues v = _SimpsonValues();
|
|
|
+
|
|
|
+ @override
|
|
|
+ void calculate() {
|
|
|
+ v = _SimpsonValues();
|
|
|
+ }
|
|
|
+
|
|
|
+ void doOutput() {
|
|
|
+ final feature = ref.feature!;
|
|
|
+
|
|
|
+ for (var output in ref.meta.outputs) {
|
|
|
+ switch (output.name) {
|
|
|
+ // Couple
|
|
|
+ case MeasureTerms.LVEDV:
|
|
|
+ _outputVal(feature, output, v.coupleEDV);
|
|
|
+ break;
|
|
|
+ case MeasureTerms.LVESV:
|
|
|
+ _outputVal(feature, output, v.coupleESV);
|
|
|
+ break;
|
|
|
+ case MeasureTerms.SV:
|
|
|
+ _outputVal(feature, output, v.coupleSV);
|
|
|
+ break;
|
|
|
+ case MeasureTerms.EF:
|
|
|
+ _outputVal(feature, output, v.coupleEF);
|
|
|
+ break;
|
|
|
+ case MeasureTerms.CO:
|
|
|
+ _outputVal(feature, output, v.coupleCO);
|
|
|
+ break;
|
|
|
+ // A2C
|
|
|
+ case "A2C LVEDV":
|
|
|
+ _outputVal(feature, output, v.a2cEDV);
|
|
|
+ break;
|
|
|
+ case "A2C LVESV":
|
|
|
+ _outputVal(feature, output, v.a2cESV);
|
|
|
+ break;
|
|
|
+ case "A2C SV":
|
|
|
+ _outputVal(feature, output, v.a2cSV);
|
|
|
+ break;
|
|
|
+ case "A2C EF":
|
|
|
+ _outputVal(feature, output, v.a2cEF);
|
|
|
+ break;
|
|
|
+ case "A2C CO":
|
|
|
+ _outputVal(feature, output, v.a2cCO);
|
|
|
+ break;
|
|
|
+ // A4C
|
|
|
+ case "A4C LVEDV":
|
|
|
+ _outputVal(feature, output, v.a4cEDV);
|
|
|
+ break;
|
|
|
+ case "A4C LVESV":
|
|
|
+ _outputVal(feature, output, v.a4cESV);
|
|
|
+ break;
|
|
|
+ case "A4C SV":
|
|
|
+ _outputVal(feature, output, v.a4cSV);
|
|
|
+ break;
|
|
|
+ case "A4C EF":
|
|
|
+ _outputVal(feature, output, v.a4cEF);
|
|
|
+ break;
|
|
|
+ case "A4C CO":
|
|
|
+ _outputVal(feature, output, v.a4cCO);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void _outputVal(
|
|
|
+ MeasureItemFeature feature,
|
|
|
+ ItemOutputMeta output,
|
|
|
+ UnitFloatValue? val,
|
|
|
+ ) {
|
|
|
+ if (val != null) {
|
|
|
+ feature.updateFloatValue(output, val.value, val.unit);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void calcA2c(MultiSimpsonPath itemD, MultiSimpsonPath itemS) {
|
|
|
+ final featureD = findChildFeature(itemD);
|
|
|
+ final featureS = findChildFeature(itemS);
|
|
|
+ UnitFloatValue? edv;
|
|
|
+ UnitFloatValue? esv;
|
|
|
+ if (featureD != null) {
|
|
|
+ edv = singleLVEDV(featureD as SimpsonPathFeature);
|
|
|
+ }
|
|
|
+ if (featureS != null) {
|
|
|
+ esv = singleLVEDV(featureS as SimpsonPathFeature);
|
|
|
+ }
|
|
|
+ v.a2cEDV = edv;
|
|
|
+ v.a2cESV = esv;
|
|
|
+ if (edv != null && esv != null) {
|
|
|
+ v.a2cSV = calcSv(edv, esv);
|
|
|
+ v.a2cEF = calcEf(edv, esv);
|
|
|
+ v.a2cCO = calcCo(edv, esv);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void calcA4c(MultiSimpsonPath itemD, MultiSimpsonPath itemS) {
|
|
|
+ final featureD = findChildFeature(itemD);
|
|
|
+ final featureS = findChildFeature(itemS);
|
|
|
+ UnitFloatValue? edv;
|
|
|
+ UnitFloatValue? esv;
|
|
|
+ if (featureD != null) {
|
|
|
+ edv = singleLVEDV(featureD as SimpsonPathFeature);
|
|
|
+ }
|
|
|
+ if (featureS != null) {
|
|
|
+ esv = singleLVEDV(featureS as SimpsonPathFeature);
|
|
|
+ }
|
|
|
+ v.a4cEDV = edv;
|
|
|
+ v.a4cESV = esv;
|
|
|
+ if (edv != null && esv != null) {
|
|
|
+ v.a4cSV = calcSv(edv, esv);
|
|
|
+ v.a4cEF = calcEf(edv, esv);
|
|
|
+ v.a4cCO = calcCo(edv, esv);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ UnitFloatValue? coupleLVEDV(
|
|
|
+ SimpsonPathFeature featureA,
|
|
|
+ SimpsonPathFeature featureB,
|
|
|
+ ) {
|
|
|
+ // max([A4C LVEDV Simpson|L"cm;2D"],[A2C LVEDV Simpson|L"cm;2D"]) *3.1415926/(4*20) * Sum(2D1*4D1 + 2D2*4D2 + ... + 2D20*4D20)
|
|
|
+ double lA = roundDouble(featureA.centerLineLength);
|
|
|
+ double lB = roundDouble(featureB.centerLineLength);
|
|
|
+ double lMax = math.max(lA, lB);
|
|
|
+
|
|
|
+ final splitterALengths = featureA.horizontalSplitterLegths.values.toList();
|
|
|
+ final splitterBLengths = featureB.horizontalSplitterLegths.values.toList();
|
|
|
+
|
|
|
+ if (splitterALengths.length < SimpsonPath.splitterCount ||
|
|
|
+ splitterBLengths.length < SimpsonPath.splitterCount) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ double sum = 0;
|
|
|
+ for (var i = 0; i < SimpsonPath.splitterCount; i++) {
|
|
|
+ final dA = roundDouble(splitterALengths[i]);
|
|
|
+ final dB = roundDouble(splitterBLengths[i]);
|
|
|
+ sum += dA * dB;
|
|
|
+ }
|
|
|
+
|
|
|
+ var value = lMax * 3.1415926 / (4 * 20) * sum;
|
|
|
+ value = value * 4;
|
|
|
+ return UnitFloatValue(value, VidUsUnit.ml);
|
|
|
+ }
|
|
|
+
|
|
|
+ UnitFloatValue? singleLVEDV(SimpsonPathFeature feature) {
|
|
|
+ // [A2C LVEDV Simpson|L"cm;2D"]*3.1415926/(4*20)* Sum(pow(D1,2),pow(D2,2),...,pow(D20,2))
|
|
|
+ double l = roundDouble(feature.centerLineLength);
|
|
|
+
|
|
|
+ final splitterLengths = feature.horizontalSplitterLegths.values.toList();
|
|
|
+
|
|
|
+ if (splitterLengths.length < SimpsonPath.splitterCount) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ double sum = 0;
|
|
|
+ for (var i = 0; i < SimpsonPath.splitterCount; i++) {
|
|
|
+ final d = math.pow(splitterLengths[i], 2).toDouble();
|
|
|
+ sum += roundDouble(d);
|
|
|
+ }
|
|
|
+ var value = l * 3.1415926 / (4 * 20) * sum;
|
|
|
+ return UnitFloatValue(value, VidUsUnit.ml);
|
|
|
+ }
|
|
|
+
|
|
|
+ UnitFloatValue calcSv(UnitFloatValue lvedv, UnitFloatValue lvesv) {
|
|
|
+ // [LVEDV(A2C Simp)"ml;"]-[LVESV(A2C Simp)"ml;"]
|
|
|
+ final value = lvedv.convert(VidUsUnit.ml) - lvesv.convert(VidUsUnit.ml);
|
|
|
+ return UnitFloatValue(value, VidUsUnit.ml);
|
|
|
+ }
|
|
|
+
|
|
|
+ UnitFloatValue calcEf(UnitFloatValue lvedv, UnitFloatValue lvesv) {
|
|
|
+ // ([LVEDV(A2C Simp)"ml;"]-[LVESV(A2C Simp)"ml;"])/[LVEDV(A2C Simp)"ml;"]*100
|
|
|
+ final value = UnitFormulas.cardiac.ef(lvedv, lvesv);
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ UnitFloatValue? calcCo(UnitFloatValue lvedv, UnitFloatValue lvesv) {
|
|
|
+ // ([LVEDV(A2C Simp)"ml;"]-[LVESV(A2C Simp)"ml;"])*{[HR|HR"HR;M"]}/1000
|
|
|
+ // ([LVEDV(A2C Simp)"ml;"]-[LVESV(A2C Simp)"ml;"])*{[HR|HR"HR;M"],[HR"HR;PatientInfo"]}/1000
|
|
|
+ final hr = GlobalPatientConfig.hr;
|
|
|
+ if (hr == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ final edv = lvedv.convert(VidUsUnit.ml);
|
|
|
+ final esv = lvesv.convert(VidUsUnit.ml);
|
|
|
+ final value = (edv - esv) * hr / 1000;
|
|
|
+ return UnitFloatValue(value, VidUsUnit.Lmin);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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.name.split(' ').first;
|
|
|
+ final isD = itemName.toLowerCase().contains("edv");
|
|
|
+ final sideTag = isD ? "d" : "s";
|
|
|
+ final outputs = [
|
|
|
+ ItemOutputMeta("Area", "$itemName LVA$sideTag", VidUsUnit.mm2),
|
|
|
+ ItemOutputMeta("L", "$itemName LVL$sideTag", 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:
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _SimpsonValues {
|
|
|
+ UnitFloatValue? a2cEDV;
|
|
|
+ UnitFloatValue? a2cESV;
|
|
|
+ UnitFloatValue? a2cSV;
|
|
|
+ UnitFloatValue? a2cEF;
|
|
|
+ UnitFloatValue? a2cCO;
|
|
|
+
|
|
|
+ UnitFloatValue? a4cEDV;
|
|
|
+ UnitFloatValue? a4cESV;
|
|
|
+ UnitFloatValue? a4cSV;
|
|
|
+ UnitFloatValue? a4cEF;
|
|
|
+ UnitFloatValue? a4cCO;
|
|
|
+
|
|
|
+ UnitFloatValue? coupleEDV;
|
|
|
+ UnitFloatValue? coupleESV;
|
|
|
+ UnitFloatValue? coupleSV;
|
|
|
+ UnitFloatValue? coupleEF;
|
|
|
+ UnitFloatValue? coupleCO;
|
|
|
+}
|