123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- import 'dart:math' as math;
- import 'package:fis_measure/configs/cardiac.dart';
- import 'package:fis_measure/configs/patient.dart';
- import 'package:fis_measure/interfaces/enums/species.dart';
- import 'package:fis_measure/process/calcuators/formulas/general.dart';
- import 'package:fis_measure/utils/number.dart';
- class CardiacFormulas {
- static ICardiacFormulaStrategy _singleton = AnimalsCardiacFormulas();
- static void reinitialize() {
- if (GlobalPatientConfig.speciesType == SpeciesType.mouse) {
- GlobalCardiacConfigs.density = 1.05;
- _singleton = MouseCardiacFormulas();
- } else {
- GlobalCardiacConfigs.density = 1.04;
- _singleton = AnimalsCardiacFormulas();
- }
- }
- static double teiIndex(double co, double et) => _singleton.teiIndex(co, et);
- static double ef(double edv, double esv) => _singleton.ef(edv, esv);
- static double edvTeichholz(double lvidd) => _singleton.edvTeichholz(lvidd);
- static double edvCube(double lvidd) => _singleton.edvCube(lvidd);
- static double esvTeichholz(double lvids) => _singleton.esvTeichholz(lvids);
- static double esvCube(double lvids) => _singleton.esvCube(lvids);
- static double sv(double edv, double esv) => _singleton.sv(edv, esv);
- static double co(double sv, {required int hr}) => _singleton.co(sv, hr: hr);
- static double ci(double sv, {required int hr, required double bsa}) =>
- _singleton.ci(sv, hr: hr, bsa: bsa);
- static double lvdMass(double ivsd, double lvidd, double lvpwd) =>
- _singleton.lvdMass(ivsd, lvidd, lvpwd);
- static double lvdMassAL(
- double lvadSaxEpi, double lvadSaxEndo, double lvldApical) =>
- _singleton.lvdMassAL(lvadSaxEpi, lvadSaxEndo, lvldApical);
- static double lvdMassIndex(double lvdmass, double bsa) =>
- _singleton.lvdMassIndex(lvdmass, bsa);
- static double fsPercent(double lvidd, double lvids) =>
- _singleton.fsPercent(lvidd, lvids);
- static double ivsPercent(double ivss, double ivsd) =>
- _singleton.ivsPercent(ivss, ivsd);
- static double lvpwPercent(double lvpws, double lvpwd) =>
- _singleton.lvpwPercent(lvpws, lvpwd);
- static double mamPercent(double mapse, double lvidd, double lvids) =>
- _singleton.mamPercent(mapse, lvidd, lvids);
- static double si(double sv, double bsa) => _singleton.si(sv, bsa);
- static double flowAreaByVTI(double otDiam, double otvti, double vti) =>
- _singleton.flowAreaByVTI(otDiam, otvti, vti);
- static double dviByVTI(double otvti, double vti) =>
- _singleton.dviByVTI(otvti, vti);
- static double avaIndex(double avaByVTI, double bsa) =>
- _singleton.avaIndex(avaByVTI, bsa);
- static double lvevi(double lvev, double bsa) => _singleton.lvevi(lvev, bsa);
- static double lvSimsonVolume(double l, List<double>? a, List<double>? b,
- [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);
- static double lvidIndex(double lvid, double bsa) =>
- _singleton.lvidIndex(lvid, bsa);
- static double lvidN(double lvid, double weight) =>
- _singleton.lvidN(lvid, weight);
- // CardiacFormulas._internal(); // 私有构造函数
- static double bsa(double weight) {
- return 0.1 * math.pow(weight, 0.667);
- }
- }
- abstract class ICardiacFormulaStrategy {
- double teiIndex(double co, double et);
- double ef(double edv, double esv);
- double edvTeichholz(double lvidd);
- double edvCube(double lvidd);
- double esvTeichholz(double lvids);
- double esvCube(double lvids);
- double sv(double edv, double esv);
- double co(double sv, {required int hr});
- double ci(double sv, {required int hr, required double bsa});
- double lvdMass(double ivsd, double lvidd, double lvpwd);
- double lvdMassAL(double lvadSaxEpi, double lvadSaxEndo, double lvldApical);
- double lvdMassIndex(double lvdmass, double bsa);
- double fsPercent(double lvidd, double lvids);
- double ivsPercent(double ivss, double ivsd);
- double lvpwPercent(double lvpws, double lvpwd);
- double mamPercent(double mapse, double lvidd, double lvids);
- double si(double sv, double bsa);
- double flowAreaByVTI(double otDiam, double otvti, double vti);
- double dviByVTI(double otvti, double vti);
- double avaIndex(double avaByVTI, double bsa);
- 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);
- /// LVID Index
- ///
- /// [lvid] cm
- ///
- /// [bsa] m2
- double lvidIndex(double lvid, double bsa);
- /// LVID N
- ///
- /// [lvid] cm
- ///
- /// [weight] kg
- double lvidN(double lvid, double weight);
- }
- /// 基础公式
- class BaseCardiacFormulas implements ICardiacFormulaStrategy {
- /// IMP
- ///
- /// Formula: `(CO-ET)/ET`
- ///
- /// Result Unit: `None`
- @override
- double teiIndex(double co, double et) {
- double imp = 0.0;
- if (et != 0.0) {
- imp = (((co).abs() - (et).abs()) / et).abs();
- }
- return imp;
- }
- /// EF
- /// Formula: `(EDV - ESV )/EDV`
- ///
- /// [edv] Unit: `cm³`
- ///
- /// [esv] Unit: `cm³`
- ///
- /// Result Unit: `None`
- @override
- double ef(double edv, double esv) {
- // 这行判断暂时注释掉是为了使实际表现与旧版一致
- // if (edv < esv) {
- // return double.nan;
- // }
- return (edv - esv) / edv * 100;
- }
- /// EDV (Teichholz)
- ///
- /// Formula: `[7.0/(2.4 + LVIDd)] x LVIDd^3`
- ///
- /// [lvidd] Unit: `cm`
- ///
- /// Result Unit: `cm³`
- @override
- double edvTeichholz(double lvidd) {
- double edv = double.nan;
- if (!NumUtil.almostEquals(lvidd, 0)) {
- edv = 7.0 * math.pow(lvidd, 3) / (2.4 + lvidd);
- }
- return edv;
- }
- /// EDV (Cube)
- ///
- /// Formula: `LVIDd^3`
- ///
- /// [lvidd] Unit: `cm`
- ///
- /// Result Unit: `cm³`
- @override
- double edvCube(double lvidd) {
- double edv = double.nan;
- if (!NumUtil.almostEquals(lvidd, 0)) {
- edv = math.pow(lvidd, 3).toDouble();
- }
- return edv;
- }
- /// ESV (Teichholz)
- ///
- /// Formula: `[7.0/(2.4 + LVIDs)] x LVIDs^3`
- ///
- /// [lvids] Unit: `cm`
- ///
- /// Result Unit: `cm³`
- @override
- double esvTeichholz(double lvids) {
- // 计算公式相同,入参不同
- return edvTeichholz(lvids);
- }
- /// ESV (Cube)
- ///
- /// Formula: `LVIDs^3`
- ///
- /// [lvids] Unit: `cm`
- ///
- /// Result Unit: `cm³`
- @override
- double esvCube(double lvids) {
- // 计算公式相同,入参不同
- return edvCube(lvids);
- }
- /// SV
- @override
- double sv(double edv, double esv) {
- return edv - esv;
- }
- /// CO
- @override
- double co(
- double sv, {
- required int hr,
- }) {
- return (sv - hr) / 1000.0;
- }
- /// CI
- @override
- double ci(
- double sv, {
- required int hr,
- required double bsa,
- }) {
- return ((sv - hr) / 1000.0) / bsa;
- }
- /// <summary>
- /// LVEVI = LVEV / BSA
- /// </summary>
- /// <param name="lvev">Unit cm³</param>
- /// <param name="bsa">Unit m²</param>
- /// <returns>cm³/m²</returns>
- @override
- double lvevi(double lvev, double bsa) {
- return lvev / bsa;
- }
- /// LVdMass
- /// LVd Mass(2D)
- @override
- double lvdMass(double ivsd, double lvidd, double lvpwd) {
- final density = GlobalCardiacConfigs.density;
- double part1 = math.pow(ivsd + lvidd + lvpwd, 3).toDouble();
- double part2 = math.pow(lvidd, 3).toDouble();
- double value = (density * (part1 - part2)) / 1000.0;
- return value;
- }
- /// LVd Mass AL
- @override
- double lvdMassAL(
- double lvadSaxEpi,
- double lvadSaxEndo,
- double lvldApical,
- ) {
- double t =
- math.sqrt(lvadSaxEpi / math.pi) - math.sqrt(lvadSaxEndo / math.pi);
- double mass = 1.05 *
- 5 /
- 6 *
- (lvadSaxEpi * (lvldApical + t) - lvadSaxEndo * lvldApical) /
- 1000;
- return mass;
- }
- /// LVd Mass Index
- @override
- double lvdMassIndex(double lvdmass, double bsa) {
- return lvdmass / bsa * 1000;
- }
- /// %FS
- @override
- double fsPercent(double lvidd, double lvids) {
- return ((lvidd - lvids) / lvidd) * 100;
- }
- /// %IVS
- @override
- double ivsPercent(double ivss, double ivsd) {
- return ((ivss - ivsd) / ivsd) * 100;
- }
- /// %LVPW
- @override
- double lvpwPercent(double lvpws, double lvpwd) {
- return ((lvpws - lvpwd) / lvpwd) * 100;
- }
- /// MAM%
- @override
- double mamPercent(double mapse, double lvidd, double lvids) {
- return mapse / (lvidd - lvids + mapse) * 100;
- }
- /// SI
- ///
- /// (EDV - ESV)/BSA
- ///
- /// [sv] cm³
- ///
- /// [bsa] m²
- ///
- /// return `cm³/m²`
- @override
- double si(double sv, double bsa) {
- double si = sv / bsa;
- return si;
- }
- /// <summary>
- /// <para>MVA VTI = 1/4 x π x (LVOT Diam)^2 x LVOT VTI/MV VTI </para>
- /// <para>AVA VTI = 1/4 x π x (LVOT Diam)^2 x LVOT VTI/AV VTI</para>
- /// <para>TVA VTI = 1/4 x π x (RVOT Diam)^2 x RVOT VTI/TV VTI</para>
- /// <para>PVA VTI = 1/4 x π x (RVOT Diam)^2 x RVOT VTI/PV VTI</para>
- /// </summary>
- /// <param name="otDiam">cm</param>
- /// <param name="otvti">cm</param>
- /// <param name="vti">cm</param>
- /// <returns>cm^2</returns>
- @override
- double flowAreaByVTI(double otDiam, double otvti, double vti) {
- double sv = 0.25 * math.pi * math.pow(otDiam, 2) * otvti / vti;
- return sv;
- }
- /// <param name="otvti">cm</param>
- /// <param name="vti">cm</param>
- /// <returns>Unit None</returns>
- @override
- double dviByVTI(double otvti, double vti) {
- double dvi = double.nan;
- if (!GeneralFormulas.doubleAlmostEquals(vti, 0)) {
- dvi = otvti / vti;
- }
- return dvi;
- }
- /// <summary>
- /// AVA Index = avaByVTI/bsa
- /// </summary>
- /// <param name="avaByVTI">cm2</param>
- /// <param name="bsa">m2</param>
- /// <returns>cm2/m2</returns>
- @override
- double avaIndex(double avaByVTI, double bsa) {
- double index = double.nan;
- if (!GeneralFormulas.doubleAlmostEquals(bsa, 0)) {
- index = avaByVTI / bsa;
- }
- return index;
- }
- /// <summary>
- /// Formular : V= π/4×∑_(i=1)^20▒〖(a_i×b_i)〗×L/20
- /// </summary>
- /// <returns></returns>
- @override
- 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;
- }
- @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;
- }
- @override
- double lvidIndex(double lvid, double bsa) {
- // [LVIDd|Distance"cm;2D"]/[BSA"m2;PatientInfo"]
- double value = lvid / bsa;
- return value;
- }
- @override
- double lvidN(double lvid, double weight) {
- // [LVIDs|Distance"cm;2D"]/pow([Weight"kg;PatientInfo"],0.294)
- double value = lvid / math.pow(weight, 0.294);
- return value;
- }
- }
- /// 实验室小鼠
- class MouseCardiacFormulas extends BaseCardiacFormulas {
- MouseCardiacFormulas() : super();
- }
- /// 人用普通公式
- class AnimalsCardiacFormulas extends BaseCardiacFormulas {
- AnimalsCardiacFormulas() : super();
- // @override
- // double edvTeichholz(double lvidd) {
- // double edv = double.nan;
- // double animalsLvidd = lvidd / 10;
- // if (!NumUtil.almostEquals(animalsLvidd, 0)) {
- // edv = 7.0 * math.pow(animalsLvidd, 3) / (2.4 + animalsLvidd);
- // }
- // return edv;
- // }
- /// CO
- @override
- double co(
- double sv, {
- required int hr,
- }) {
- return (sv - hr);
- }
- /// CI
- @override
- double ci(
- double sv, {
- required int hr,
- required double bsa,
- }) {
- return ((sv - hr)) / bsa;
- }
- /// ESV (Teichholz)
- ///
- /// Formula: `[7.0/(2.4 + LVIDs)] x LVIDs^3`
- ///
- /// [lvids] Unit: `cm`
- ///
- /// Result Unit: `cm³`
- @override
- double esvTeichholz(double lvids) {
- // 计算公式相同,入参不同
- return edvTeichholz(lvids);
- }
- /// <summary>
- /// <para>MVA VTI = 1/4 x π x (LVOT Diam)^2 x LVOT VTI/MV VTI </para>
- /// <para>AVA VTI = 1/4 x π x (LVOT Diam)^2 x LVOT VTI/AV VTI</para>
- /// <para>TVA VTI = 1/4 x π x (RVOT Diam)^2 x RVOT VTI/TV VTI</para>
- /// <para>PVA VTI = 1/4 x π x (RVOT Diam)^2 x RVOT VTI/PV VTI</para>
- /// </summary>
- /// <param name="otDiam">cm</param>
- /// <param name="otvti">cm</param>
- /// <param name="vti">cm</param>
- /// <returns>cm^2</returns>
- /// SV(LVOT)|CO
- @override
- double flowAreaByVTI(double otDiam, double otvti, double vti) {
- double animalsOtDiam = otDiam / 10;
- double animalsOtvti = otvti / 10;
- double animalsVti = vti / 10;
- double sv =
- 0.25 * math.pi * math.pow(animalsOtDiam, 2) * animalsOtvti / animalsVti;
- return sv;
- }
- @override
- double lvdMass(double ivsd, double lvidd, double lvpwd) {
- final density = GlobalCardiacConfigs.density;
- const correctionFactor = GlobalCardiacConfigs.correctionFactor;
- double part1 = math.pow(ivsd + lvidd + lvpwd, 3).toDouble();
- double part2 = math.pow(lvidd, 3).toDouble();
- double value = ((density * part1 - part2) + correctionFactor) / 1000.0;
- return value;
- }
- }
|