// ignore_for_file: constant_identifier_names import 'dart:math' as math; import 'package:fis_measure/interfaces/date_types/point.dart'; class GeneralFormulas { /// Volume:1/6 x π static const double VolumeCofficient = math.pi / 6.0; /// 1/6 x π x D1^2 x D2 (D1 > D2) /// /// 1/6 x π x D1 x D2^2 (D1 ≤ D2) /// /// return unit: cm³ static double volumeTwoLine(double d1, double d2, [bool useBigValue = true]) { double volume = 0; if (!doubleAlmostEquals(d1, 0) && !doubleAlmostEquals(d2, 0)) { if (useBigValue) { if (d1 > d2) { volume = d1 * d1 * d2 * math.pi / 6.0; } else { volume = d1 * d2 * d2 * math.pi / 6.0; } } else { if (d1 > d2) { volume = d2 * d2 * d1 * math.pi / 6.0; } else { volume = d1 * d1 * d2 * math.pi / 6.0; } } } return volume; } /// 带比率系数算体积 /// /// [coefficient] 比率系数 static double volumeWithCoefficient( double d1, double d2, double d3, double coefficient, ) { double volume = 0; if (!doubleAlmostEquals(d1, 0) && !doubleAlmostEquals(d2, 0) && !doubleAlmostEquals(d3, 0)) { volume = d1 * d2 * d3 * coefficient; } return volume; } /// 狭窄率计算 static double countStenosis(double d1, double d2) { double residual; double lumen; if (d1 > d2) { residual = d2; lumen = d1; } else { residual = d1; lumen = d2; } return (1.0 - residual / lumen) * 100; } static bool doubleAlmostEquals(double num1, double num2, [double precision = 0.000001]) { if (num1.isNaN && num2.isNaN) return true; return (num1 - num2).abs() <= precision; } /// 点到线的距离 /// /// [pt1] 线端点1 /// /// [pt2] 线端点2 /// /// [pt] 点 static double distance2Line(DPoint pt1, DPoint pt2, DPoint pt) { double dis = 0; if (pt1.x == pt2.x) { dis = (pt.x - pt1.x).abs(); return dis; } var lineK = (pt2.y - pt1.y) / (pt2.x - pt1.x); var lineC = (pt2.x * pt1.y - pt1.x * pt2.y) / (pt2.x - pt1.x); dis = (lineK * pt.x - pt.y + lineC).abs() / (math.sqrt(lineK * lineK + 1)); return dis; } ///计算斜率 static double countSlope(DPoint p1, DPoint p2) { if (doubleAlmostEquals(p2.x, p1.x)) return 0; double vertical = p2.y - p1.y; double time = (p2.x - p1.x).abs(); double slope = vertical / time; return slope; } ///计算包络时间 ///Origin: Vinno.Modules.MeasureModule\Formulas\GeneralFormulas.cs [632:67] static double countEnvelopeTime(List points) { if (points.length < 2) return 0; double startTime = double.maxFinite; double endTime = -double.maxFinite; for (var point in points) { if (point.x < startTime) { startTime = point.x; } if (point.x > endTime) { endTime = point.x; } } return (endTime - startTime).abs(); } /// /// 4.0 x V^2 /// /// Unit cm/s /// Unit mmHg static double countPressure(double v) { // The velocity is in cm/s, but it should be m/s in this formula, so divide it by 100. double pg = 4.0 * math.pow(v * 0.01, 2); return pg; } /// /// Resistivity Index 阻力指数 /// RI (ED)=(PS - ED)/PS /// RI (MD)=(PS - MD)/PS /// /// Unit cm/s /// Unit cm/s static double countRI(double ps, double mdEd) { ps = ps.abs(); mdEd = mdEd.abs(); double ri = (ps - mdEd) / ps; if (ri < 0) { return double.nan; } return ri; } /// /// 4.0 x |V1^2 - V2^2| /// /// Unit cm/s /// Unit cm/s /// Unit mmHg static double countMaxPG(double v1, double v2) { // The velocity is in cm/s, but it should be m/s in this formula, so divide it by 100. double meanPG = 4.0 * (math.pow(v1 * 0.01, 2) - math.pow(v2 * 0.01, 2)).abs(); return meanPG; } // 计算心率 // TODO: 心脏周期(可配置) DefaultHeartCycle = 2; // Origin: Vinno.Modules.MeasureModule\Primitives\DopplerTraceBase.cs static double countHR(double timeSpan) { const defaultHeartCycle = 1; double hr = (defaultHeartCycle * 60 / timeSpan).roundToDouble(); return hr; } // return [VTI,tiEnv,timeAveragedVelocity,pv,meanPG,hr]; static List countVTI( List tracePoints, ) { var tiEnv = 0.0; var timeAveragedVelocity = 0.0; var pv = 0.0; var meanPG = 0.0; if (tracePoints.length < 2) return [0, 0, 0, 0, 0, 0]; int n = tracePoints.length - 1; double dis = 0; double startTime = 0; double endTime = 0; double pgSum = 0; int positiveCount = 0; int negativeCount = 0; for (int i = 0; i < n; i++) { var p1 = tracePoints[i]; var p2 = tracePoints[i + 1]; if (pv.abs() < (p1.y).abs()) { pv = p1.y; } double meanVelocity = (p1.y + p2.y).abs() / 2; double timeSpan = (p1.x - p2.x).abs(); dis += meanVelocity * timeSpan; pgSum += countPressure(meanVelocity) * timeSpan; if (i == 0) { startTime = p1.x; endTime = p2.x; } else { startTime = math.min(startTime, p2.x); endTime = math.max(endTime, p2.x); } if (p1.y < 0) { negativeCount++; } else { positiveCount++; } } if (tracePoints[n].y < 0) { negativeCount++; } else { positiveCount++; } if (positiveCount < negativeCount) { dis = -dis; } if (pv.abs() < (tracePoints[n].y).abs()) { pv = tracePoints[n].y; } tiEnv = (endTime - startTime).abs(); meanPG = (pgSum / tiEnv); timeAveragedVelocity = (dis / tiEnv); var hr = countHR(tiEnv); return [dis, tiEnv, timeAveragedVelocity, pv, meanPG, hr]; } }