exercise.dart 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import 'package:body_detection/models/pose_landmark_type.dart';
  2. import '../../../navigation/utils/geometry_utils.dart';
  3. import '../widgets/pose_detector.dart';
  4. enum AuthorizedTypeIndex {
  5. nose,
  6. leftShoulder,
  7. rightShoulder,
  8. leftElbow,
  9. rightElbow,
  10. leftWrist,
  11. rightWrist,
  12. leftHip,
  13. rightHip,
  14. leftKnee,
  15. rightKnee,
  16. leftAnkle,
  17. rightAnkle,
  18. }
  19. enum Comparator {
  20. greater,
  21. lesser,
  22. }
  23. class Exercise {
  24. final int reps;
  25. final int series;
  26. final Criteria startMovement;
  27. final Criteria endMovement;
  28. late final List<PoseLandmarkType> jointsOnScreen;
  29. Exercise({
  30. required this.reps,
  31. required this.series,
  32. required this.startMovement,
  33. required this.endMovement,
  34. required List<AuthorizedTypeIndex> jointsOnScreen,
  35. }) {
  36. this.jointsOnScreen = jointsOnScreen.map((joint) => authorizedType[joint.index]).toList();
  37. }
  38. bool isAtStartMovement(MeanFilteredData meanFilteredData) {
  39. return startMovement.isAtPosition(meanFilteredData);
  40. }
  41. bool isAtEndMovement(MeanFilteredData meanFilteredData) {
  42. return endMovement.isAtPosition(meanFilteredData);
  43. }
  44. static const authorizedType = [
  45. PoseLandmarkType.nose,
  46. PoseLandmarkType.leftShoulder,
  47. PoseLandmarkType.rightShoulder,
  48. PoseLandmarkType.leftElbow,
  49. PoseLandmarkType.rightElbow,
  50. PoseLandmarkType.leftWrist,
  51. PoseLandmarkType.rightWrist,
  52. PoseLandmarkType.leftHip,
  53. PoseLandmarkType.rightHip,
  54. PoseLandmarkType.leftKnee,
  55. PoseLandmarkType.rightKnee,
  56. PoseLandmarkType.leftAnkle,
  57. PoseLandmarkType.rightAnkle,
  58. ];
  59. }
  60. abstract class Criteria {
  61. bool isAtPosition(MeanFilteredData meanFilteredData);
  62. }
  63. class CriteriaDistance implements Criteria {
  64. final AuthorizedTypeIndex jointStart;
  65. final AuthorizedTypeIndex jointEnd;
  66. final int axis;
  67. final num threshold;
  68. final Comparator comparator;
  69. const CriteriaDistance({
  70. required this.jointStart,
  71. required this.jointEnd,
  72. required this.axis,
  73. required this.threshold,
  74. required this.comparator,
  75. });
  76. @override
  77. bool isAtPosition(MeanFilteredData meanFilteredData) {
  78. final start = meanFilteredData[jointStart.index][axis];
  79. final end = meanFilteredData[jointEnd.index][axis];
  80. final distance = (start - end).abs();
  81. return _compare(distance, threshold);
  82. }
  83. bool _compare(num distance, num threshold) {
  84. if (comparator == Comparator.greater) {
  85. return distance > threshold;
  86. } else {
  87. return distance < threshold;
  88. }
  89. }
  90. }
  91. class CriteriaAngle implements Criteria {
  92. final AuthorizedTypeIndex jointStart;
  93. final AuthorizedTypeIndex jointCenter;
  94. final AuthorizedTypeIndex jointEnd;
  95. final num threshold;
  96. final Comparator comparator;
  97. const CriteriaAngle({
  98. required this.jointStart,
  99. required this.jointCenter,
  100. required this.jointEnd,
  101. required this.threshold,
  102. required this.comparator,
  103. });
  104. @override
  105. bool isAtPosition(MeanFilteredData meanFilteredData) {
  106. final start = Point3D(
  107. x: meanFilteredData[jointStart.index][0],
  108. y: meanFilteredData[jointStart.index][1],
  109. z: meanFilteredData[jointStart.index][2]);
  110. final center = Point3D(
  111. x: meanFilteredData[jointCenter.index][0],
  112. y: meanFilteredData[jointCenter.index][1],
  113. z: meanFilteredData[jointCenter.index][2]);
  114. final end = Point3D(
  115. x: meanFilteredData[jointEnd.index][0],
  116. y: meanFilteredData[jointEnd.index][1],
  117. z: meanFilteredData[jointEnd.index][2]);
  118. final angle = DistanceUtils.angleBetweenThreePoints(start, center, end).round();
  119. return _compare(angle, threshold);
  120. }
  121. bool _compare(num angle, num threshold) {
  122. if (comparator == Comparator.greater) {
  123. return angle > threshold;
  124. } else {
  125. return angle < threshold;
  126. }
  127. }
  128. }