import 'package:body_detection/models/pose_landmark_type.dart'; import '../../../navigation/utils/geometry_utils.dart'; import '../widgets/pose_detector.dart'; enum AuthorizedTypeIndex { nose, leftShoulder, rightShoulder, leftElbow, rightElbow, leftWrist, rightWrist, leftHip, rightHip, leftKnee, rightKnee, leftAnkle, rightAnkle, } enum Comparator { greater, lesser, } class Exercise { final int reps; final int series; final Criteria startMovement; final Criteria endMovement; late final List jointsOnScreen; Exercise({ required this.reps, required this.series, required this.startMovement, required this.endMovement, required List jointsOnScreen, }) { this.jointsOnScreen = jointsOnScreen.map((joint) => authorizedType[joint.index]).toList(); } bool isAtStartMovement(MeanFilteredData meanFilteredData) { return startMovement.isAtPosition(meanFilteredData); } bool isAtEndMovement(MeanFilteredData meanFilteredData) { return endMovement.isAtPosition(meanFilteredData); } static const authorizedType = [ PoseLandmarkType.nose, PoseLandmarkType.leftShoulder, PoseLandmarkType.rightShoulder, PoseLandmarkType.leftElbow, PoseLandmarkType.rightElbow, PoseLandmarkType.leftWrist, PoseLandmarkType.rightWrist, PoseLandmarkType.leftHip, PoseLandmarkType.rightHip, PoseLandmarkType.leftKnee, PoseLandmarkType.rightKnee, PoseLandmarkType.leftAnkle, PoseLandmarkType.rightAnkle, ]; } abstract class Criteria { bool isAtPosition(MeanFilteredData meanFilteredData); } class CriteriaDistance implements Criteria { final AuthorizedTypeIndex jointStart; final AuthorizedTypeIndex jointEnd; final int axis; final num threshold; final Comparator comparator; const CriteriaDistance({ required this.jointStart, required this.jointEnd, required this.axis, required this.threshold, required this.comparator, }); @override bool isAtPosition(MeanFilteredData meanFilteredData) { final start = meanFilteredData[jointStart.index][axis]; final end = meanFilteredData[jointEnd.index][axis]; final distance = (start - end).abs(); return _compare(distance, threshold); } bool _compare(num distance, num threshold) { if (comparator == Comparator.greater) { return distance > threshold; } else { return distance < threshold; } } } class CriteriaAngle implements Criteria { final AuthorizedTypeIndex jointStart; final AuthorizedTypeIndex jointCenter; final AuthorizedTypeIndex jointEnd; final num threshold; final Comparator comparator; const CriteriaAngle({ required this.jointStart, required this.jointCenter, required this.jointEnd, required this.threshold, required this.comparator, }); @override bool isAtPosition(MeanFilteredData meanFilteredData) { final start = Point3D( x: meanFilteredData[jointStart.index][0], y: meanFilteredData[jointStart.index][1], z: meanFilteredData[jointStart.index][2]); final center = Point3D( x: meanFilteredData[jointCenter.index][0], y: meanFilteredData[jointCenter.index][1], z: meanFilteredData[jointCenter.index][2]); final end = Point3D( x: meanFilteredData[jointEnd.index][0], y: meanFilteredData[jointEnd.index][1], z: meanFilteredData[jointEnd.index][2]); final angle = DistanceUtils.angleBetweenThreePoints(start, center, end).round(); return _compare(angle, threshold); } bool _compare(num angle, num threshold) { if (comparator == Comparator.greater) { return angle > threshold; } else { return angle < threshold; } } }