|
@@ -19,34 +19,121 @@ enum AuthorizedTypeIndex {
|
|
|
rightAnkle,
|
|
rightAnkle,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+AuthorizedTypeIndex typeIndexFromString(String typeIndex) {
|
|
|
|
|
+ switch (typeIndex) {
|
|
|
|
|
+ case "nose":
|
|
|
|
|
+ return AuthorizedTypeIndex.nose;
|
|
|
|
|
+ case "leftShoulder":
|
|
|
|
|
+ return AuthorizedTypeIndex.leftShoulder;
|
|
|
|
|
+ case "rightShoulder":
|
|
|
|
|
+ return AuthorizedTypeIndex.rightShoulder;
|
|
|
|
|
+ case "leftElbow":
|
|
|
|
|
+ return AuthorizedTypeIndex.leftElbow;
|
|
|
|
|
+ case "rightElbow":
|
|
|
|
|
+ return AuthorizedTypeIndex.rightElbow;
|
|
|
|
|
+ case "leftWrist":
|
|
|
|
|
+ return AuthorizedTypeIndex.leftWrist;
|
|
|
|
|
+ case "rightWrist":
|
|
|
|
|
+ return AuthorizedTypeIndex.rightWrist;
|
|
|
|
|
+ case "leftHip":
|
|
|
|
|
+ return AuthorizedTypeIndex.leftHip;
|
|
|
|
|
+ case "rightHip":
|
|
|
|
|
+ return AuthorizedTypeIndex.rightHip;
|
|
|
|
|
+ case "leftKnee":
|
|
|
|
|
+ return AuthorizedTypeIndex.leftKnee;
|
|
|
|
|
+ case "rightKnee":
|
|
|
|
|
+ return AuthorizedTypeIndex.rightKnee;
|
|
|
|
|
+ case "leftAnkle":
|
|
|
|
|
+ return AuthorizedTypeIndex.leftAnkle;
|
|
|
|
|
+ case "rightAnkle":
|
|
|
|
|
+ return AuthorizedTypeIndex.rightAnkle;
|
|
|
|
|
+ default:
|
|
|
|
|
+ throw const FormatException("Incorrect type name");
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
enum Comparator {
|
|
enum Comparator {
|
|
|
greater,
|
|
greater,
|
|
|
lesser,
|
|
lesser,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+Comparator comparatorFromString(String comparator) {
|
|
|
|
|
+ switch (comparator) {
|
|
|
|
|
+ case "greater":
|
|
|
|
|
+ return Comparator.greater;
|
|
|
|
|
+ case "lesser":
|
|
|
|
|
+ return Comparator.lesser;
|
|
|
|
|
+ default:
|
|
|
|
|
+ throw const FormatException("Incorrect comparator name");
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
class Exercise {
|
|
class Exercise {
|
|
|
- final int reps;
|
|
|
|
|
- final int series;
|
|
|
|
|
- final Criteria startMovement;
|
|
|
|
|
- final Criteria endMovement;
|
|
|
|
|
|
|
+ final int repetitions;
|
|
|
|
|
+ final int sets;
|
|
|
|
|
+ final Criteria? startMovement;
|
|
|
|
|
+ final Criteria? endMovement;
|
|
|
|
|
+ final String description;
|
|
|
|
|
+ final String name;
|
|
|
|
|
+ final int difficulty;
|
|
|
|
|
+ final String id;
|
|
|
late final List<PoseLandmarkType> jointsOnScreen;
|
|
late final List<PoseLandmarkType> jointsOnScreen;
|
|
|
|
|
|
|
|
Exercise({
|
|
Exercise({
|
|
|
- required this.reps,
|
|
|
|
|
- required this.series,
|
|
|
|
|
|
|
+ required this.repetitions,
|
|
|
|
|
+ required this.sets,
|
|
|
required this.startMovement,
|
|
required this.startMovement,
|
|
|
required this.endMovement,
|
|
required this.endMovement,
|
|
|
|
|
+ required this.description,
|
|
|
|
|
+ required this.name,
|
|
|
|
|
+ required this.difficulty,
|
|
|
|
|
+ required this.id,
|
|
|
required List<AuthorizedTypeIndex> jointsOnScreen,
|
|
required List<AuthorizedTypeIndex> jointsOnScreen,
|
|
|
}) {
|
|
}) {
|
|
|
this.jointsOnScreen = jointsOnScreen.map((joint) => authorizedType[joint.index]).toList();
|
|
this.jointsOnScreen = jointsOnScreen.map((joint) => authorizedType[joint.index]).toList();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool isAtStartMovement(MeanFilteredData meanFilteredData) {
|
|
bool isAtStartMovement(MeanFilteredData meanFilteredData) {
|
|
|
- return startMovement.isAtPosition(meanFilteredData);
|
|
|
|
|
|
|
+ final start = startMovement;
|
|
|
|
|
+ if (start != null) {
|
|
|
|
|
+ return start.isAtPosition(meanFilteredData);
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool isAtEndMovement(MeanFilteredData meanFilteredData) {
|
|
bool isAtEndMovement(MeanFilteredData meanFilteredData) {
|
|
|
- return endMovement.isAtPosition(meanFilteredData);
|
|
|
|
|
|
|
+ final end = endMovement;
|
|
|
|
|
+ if (end != null) {
|
|
|
|
|
+ return end.isAtPosition(meanFilteredData);
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, dynamic> toMap() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ "repetitions": repetitions,
|
|
|
|
|
+ "sets": sets,
|
|
|
|
|
+ "start_movement": startMovement?.toMap(),
|
|
|
|
|
+ "end_movement": endMovement?.toMap(),
|
|
|
|
|
+ "description": description,
|
|
|
|
|
+ "name": name,
|
|
|
|
|
+ "difficulty": difficulty,
|
|
|
|
|
+ "joints_on_screen": jointsOnScreen.map((j) => j.name).toList(),
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ factory Exercise.fromMap(String id, Map<String, dynamic> map) {
|
|
|
|
|
+ return Exercise(
|
|
|
|
|
+ repetitions: map["repetitions"],
|
|
|
|
|
+ sets: map["sets"],
|
|
|
|
|
+ startMovement: map.containsKey("start_movement") ? Criteria.fromMap(map["start_movement"]) : null,
|
|
|
|
|
+ endMovement: map.containsKey("end_movement") ? Criteria.fromMap(map["end_movement"]) : null,
|
|
|
|
|
+ description: map["description"],
|
|
|
|
|
+ name: map["name"],
|
|
|
|
|
+ difficulty: map["difficulty"],
|
|
|
|
|
+ id: id,
|
|
|
|
|
+ jointsOnScreen: map.containsKey("joints_on_screen") ? List<String>.from(map["joints_on_screen"]).map((e) => typeIndexFromString(e)).toList() : [],
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static const authorizedType = [
|
|
static const authorizedType = [
|
|
@@ -68,6 +155,17 @@ class Exercise {
|
|
|
|
|
|
|
|
abstract class Criteria {
|
|
abstract class Criteria {
|
|
|
bool isAtPosition(MeanFilteredData meanFilteredData);
|
|
bool isAtPosition(MeanFilteredData meanFilteredData);
|
|
|
|
|
+ Map<String, dynamic> toMap();
|
|
|
|
|
+ static Criteria fromMap(Map<String, dynamic> map) {
|
|
|
|
|
+ switch (map["type"]) {
|
|
|
|
|
+ case "distance":
|
|
|
|
|
+ return CriteriaDistance.fromMap(map);
|
|
|
|
|
+ case "angle":
|
|
|
|
|
+ return CriteriaAngle.fromMap(map);
|
|
|
|
|
+ default:
|
|
|
|
|
+ throw FormatException("Type should be distance or angle but is ${map['type']}");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class CriteriaDistance implements Criteria {
|
|
class CriteriaDistance implements Criteria {
|
|
@@ -100,6 +198,27 @@ class CriteriaDistance implements Criteria {
|
|
|
return distance < threshold;
|
|
return distance < threshold;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ @override
|
|
|
|
|
+ Map<String, dynamic> toMap() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ "joint_start": jointStart.name,
|
|
|
|
|
+ "joint_end": jointEnd.name,
|
|
|
|
|
+ "threshold": threshold,
|
|
|
|
|
+ "comparator": comparator.name,
|
|
|
|
|
+ "type": "distance",
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ factory CriteriaDistance.fromMap(Map<String, dynamic> map) {
|
|
|
|
|
+ return CriteriaDistance(
|
|
|
|
|
+ jointStart: typeIndexFromString(map["joint_start"]),
|
|
|
|
|
+ jointEnd: typeIndexFromString(map["joint_end"]),
|
|
|
|
|
+ axis: map["axis"],
|
|
|
|
|
+ threshold: map["threshold"],
|
|
|
|
|
+ comparator: comparatorFromString(map["comparator"]),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class CriteriaAngle implements Criteria {
|
|
class CriteriaAngle implements Criteria {
|
|
@@ -142,4 +261,26 @@ class CriteriaAngle implements Criteria {
|
|
|
return angle < threshold;
|
|
return angle < threshold;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ @override
|
|
|
|
|
+ Map<String, dynamic> toMap() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ "joint_start": jointStart.name,
|
|
|
|
|
+ "joint_center": jointCenter.name,
|
|
|
|
|
+ "joint_end": jointEnd.name,
|
|
|
|
|
+ "threshold": threshold,
|
|
|
|
|
+ "comparator": comparator.name,
|
|
|
|
|
+ "type": "angle",
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ factory CriteriaAngle.fromMap(Map<String, dynamic> map) {
|
|
|
|
|
+ return CriteriaAngle(
|
|
|
|
|
+ jointStart: typeIndexFromString(map["joint_start"]),
|
|
|
|
|
+ jointCenter: typeIndexFromString(map["joint_center"]),
|
|
|
|
|
+ jointEnd: typeIndexFromString(map["joint_end"]),
|
|
|
|
|
+ threshold: map["threshold"],
|
|
|
|
|
+ comparator: comparatorFromString(map["comparator"]),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|