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, } class Exercise { final int reps; final int series; final Criteria startMovement; final Criteria endMovement; const Exercise({ required this.reps, required this.series, required this.startMovement, required this.endMovement, }); 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 int threshold; const CriteriaDistance({ required this.jointStart, required this.jointEnd, required this.axis, required this.threshold, }); @override bool isAtPosition(MeanFilteredData meanFilteredData) { final start = meanFilteredData[jointStart.index][axis]; final end = meanFilteredData[jointEnd.index][axis]; final distance = (start - end).abs(); return distance < threshold; } } class CriteriaAngle implements Criteria { final AuthorizedTypeIndex jointStart; final AuthorizedTypeIndex jointCenter; final AuthorizedTypeIndex jointEnd; final int threshold; const CriteriaAngle({ required this.jointStart, required this.jointCenter, required this.jointEnd, required this.threshold, }); @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 angle > threshold; } }