general.dart 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // ignore_for_file: constant_identifier_names
  2. import 'dart:math' as math;
  3. import 'package:fis_measure/interfaces/date_types/point.dart';
  4. class GeneralFormulas {
  5. /// Volume:1/6 x π
  6. static const double VolumeCofficient = math.pi / 6.0;
  7. /// 1/6 x π x D1^2 x D2 (D1 > D2)
  8. ///
  9. /// 1/6 x π x D1 x D2^2 (D1 ≤ D2)
  10. ///
  11. /// return unit: cm³</returns>
  12. static double volumeTwoLine(double d1, double d2, [bool useBigValue = true]) {
  13. double volume = 0;
  14. if (!doubleAlmostEquals(d1, 0) && !doubleAlmostEquals(d2, 0)) {
  15. if (useBigValue) {
  16. if (d1 > d2) {
  17. volume = d1 * d1 * d2 * math.pi / 6.0;
  18. } else {
  19. volume = d1 * d2 * d2 * math.pi / 6.0;
  20. }
  21. } else {
  22. if (d1 > d2) {
  23. volume = d2 * d2 * d1 * math.pi / 6.0;
  24. } else {
  25. volume = d1 * d1 * d2 * math.pi / 6.0;
  26. }
  27. }
  28. }
  29. return volume;
  30. }
  31. /// 带比率系数算体积
  32. ///
  33. /// [coefficient] 比率系数
  34. static double volumeWithCoefficient(
  35. double d1,
  36. double d2,
  37. double d3,
  38. double coefficient,
  39. ) {
  40. double volume = 0;
  41. if (!doubleAlmostEquals(d1, 0) &&
  42. !doubleAlmostEquals(d2, 0) &&
  43. !doubleAlmostEquals(d3, 0)) {
  44. volume = d1 * d2 * d3 * coefficient;
  45. }
  46. return volume;
  47. }
  48. /// 狭窄率计算
  49. static double countStenosis(double d1, double d2) {
  50. double residual;
  51. double lumen;
  52. if (d1 > d2) {
  53. residual = d2;
  54. lumen = d1;
  55. } else {
  56. residual = d1;
  57. lumen = d2;
  58. }
  59. return (1.0 - residual / lumen) * 100;
  60. }
  61. static bool doubleAlmostEquals(double num1, double num2,
  62. [double precision = 0.000001]) {
  63. if (num1.isNaN && num2.isNaN) return true;
  64. return (num1 - num2).abs() <= precision;
  65. }
  66. /// 点到线的距离
  67. ///
  68. /// [pt1] 线端点1
  69. ///
  70. /// [pt2] 线端点2
  71. ///
  72. /// [pt] 点
  73. static double distance2Line(DPoint pt1, DPoint pt2, DPoint pt) {
  74. double dis = 0;
  75. if (pt1.x == pt2.x) {
  76. dis = (pt.x - pt1.x).abs();
  77. return dis;
  78. }
  79. var lineK = (pt2.y - pt1.y) / (pt2.x - pt1.x);
  80. var lineC = (pt2.x * pt1.y - pt1.x * pt2.y) / (pt2.x - pt1.x);
  81. dis = (lineK * pt.x - pt.y + lineC).abs() / (math.sqrt(lineK * lineK + 1));
  82. return dis;
  83. }
  84. ///计算斜率
  85. static double countSlope(DPoint p1, DPoint p2) {
  86. if (doubleAlmostEquals(p2.x, p1.x)) return 0;
  87. double vertical = p2.y - p1.y;
  88. double time = (p2.x - p1.x).abs();
  89. double slope = vertical / time;
  90. return slope;
  91. }
  92. ///计算包络时间
  93. ///Origin: Vinno.Modules.MeasureModule\Formulas\GeneralFormulas.cs [632:67]
  94. static double countEnvelopeTime(List<DPoint> points) {
  95. if (points.length < 2) return 0;
  96. double startTime = double.maxFinite;
  97. double endTime = -double.maxFinite;
  98. for (var point in points) {
  99. if (point.x < startTime) {
  100. startTime = point.x;
  101. }
  102. if (point.x > endTime) {
  103. endTime = point.x;
  104. }
  105. }
  106. return (endTime - startTime).abs();
  107. }
  108. /// <summary>
  109. /// 4.0 x V^2
  110. /// </summary>
  111. /// <param name="v">Unit cm/s</param>
  112. /// <returns>Unit mmHg</returns>
  113. static double countPressure(double v) {
  114. // The velocity is in cm/s, but it should be m/s in this formula, so divide it by 100.
  115. double pg = 4.0 * math.pow(v * 0.01, 2);
  116. return pg;
  117. }
  118. /// <summary>
  119. /// Resistivity Index 阻力指数
  120. /// <para>RI (ED)=(PS - ED)/PS </para>
  121. /// <para>RI (MD)=(PS - MD)/PS </para>
  122. /// </summary>
  123. /// <param name="ps">Unit cm/s</param>
  124. /// <param name="mdEd">Unit cm/s</param>
  125. static double countRI(double ps, double mdEd) {
  126. ps = ps.abs();
  127. mdEd = mdEd.abs();
  128. double ri = (ps - mdEd) / ps;
  129. if (ri < 0) {
  130. return double.nan;
  131. }
  132. return ri;
  133. }
  134. /// <summary>
  135. /// 4.0 x |V1^2 - V2^2|
  136. /// </summary>
  137. /// <param name="v1">Unit cm/s</param>
  138. /// <param name="v2">Unit cm/s</param>
  139. /// <returns>Unit mmHg</returns>
  140. static double countMaxPG(double v1, double v2) {
  141. // The velocity is in cm/s, but it should be m/s in this formula, so divide it by 100.
  142. double meanPG =
  143. 4.0 * (math.pow(v1 * 0.01, 2) - math.pow(v2 * 0.01, 2)).abs();
  144. return meanPG;
  145. }
  146. // 计算心率
  147. // TODO: 心脏周期(可配置) DefaultHeartCycle = 2;
  148. // Origin: Vinno.Modules.MeasureModule\Primitives\DopplerTraceBase.cs
  149. static double countHR(double timeSpan) {
  150. const defaultHeartCycle = 1;
  151. double hr = (defaultHeartCycle * 60 / timeSpan).roundToDouble();
  152. return hr;
  153. }
  154. // return [VTI,tiEnv,timeAveragedVelocity,pv,meanPG,hr];
  155. static List<double> countVTI(
  156. List<DPoint> tracePoints,
  157. ) {
  158. var tiEnv = 0.0;
  159. var timeAveragedVelocity = 0.0;
  160. var pv = 0.0;
  161. var meanPG = 0.0;
  162. if (tracePoints.length < 2) return [0, 0, 0, 0, 0, 0];
  163. int n = tracePoints.length - 1;
  164. double dis = 0;
  165. double startTime = 0;
  166. double endTime = 0;
  167. double pgSum = 0;
  168. int positiveCount = 0;
  169. int negativeCount = 0;
  170. for (int i = 0; i < n; i++) {
  171. var p1 = tracePoints[i];
  172. var p2 = tracePoints[i + 1];
  173. if (pv.abs() < (p1.y).abs()) {
  174. pv = p1.y;
  175. }
  176. double meanVelocity = (p1.y + p2.y).abs() / 2;
  177. double timeSpan = (p1.x - p2.x).abs();
  178. dis += meanVelocity * timeSpan;
  179. pgSum += countPressure(meanVelocity) * timeSpan;
  180. if (i == 0) {
  181. startTime = p1.x;
  182. endTime = p2.x;
  183. } else {
  184. startTime = math.min(startTime, p2.x);
  185. endTime = math.max(endTime, p2.x);
  186. }
  187. if (p1.y < 0) {
  188. negativeCount++;
  189. } else {
  190. positiveCount++;
  191. }
  192. }
  193. if (tracePoints[n].y < 0) {
  194. negativeCount++;
  195. } else {
  196. positiveCount++;
  197. }
  198. if (positiveCount < negativeCount) {
  199. dis = -dis;
  200. }
  201. if (pv.abs() < (tracePoints[n].y).abs()) {
  202. pv = tracePoints[n].y;
  203. }
  204. tiEnv = (endTime - startTime).abs();
  205. meanPG = (pgSum / tiEnv);
  206. timeAveragedVelocity = (dis / tiEnv);
  207. var hr = countHR(tiEnv);
  208. return [dis, tiEnv, timeAveragedVelocity, pv, meanPG, hr];
  209. }
  210. }