Updated PersonalMotionPreviewElement and FitnessActivity to match functionality
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
package com.example.fitbot.ui.activities;
|
package com.example.fitbot.ui.activities;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import com.aldebaran.qi.sdk.QiContext;
|
import com.aldebaran.qi.sdk.QiContext;
|
||||||
import com.aldebaran.qi.sdk.QiSDK;
|
import com.aldebaran.qi.sdk.QiSDK;
|
||||||
@@ -42,7 +45,6 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
gesturePathBuilder.addVector(new Vector3f(-.5f, .5f, -.5f));
|
gesturePathBuilder.addVector(new Vector3f(-.5f, .5f, -.5f));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
personalMotionPreviewElement = findViewById(R.id.personalMotionPreviewElement);
|
personalMotionPreviewElement = findViewById(R.id.personalMotionPreviewElement);
|
||||||
personalMotionPreviewElement.post(() -> {
|
personalMotionPreviewElement.post(() -> {
|
||||||
Log.i("FitnessActivity", "PersonalMotionPreviewElement.post()");
|
Log.i("FitnessActivity", "PersonalMotionPreviewElement.post()");
|
||||||
@@ -56,7 +58,7 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
@Override
|
@Override
|
||||||
public void onRobotFocusGained(QiContext qiContext) {
|
public void onRobotFocusGained(QiContext qiContext) {
|
||||||
// Implement your logic when the robot focus is gained
|
// Implement your logic when the robot focus is gained
|
||||||
Animate("bicepcurl", qiContext);
|
Animations.Animate("bicepcurl", qiContext);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,10 +78,4 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
public static class PersonalMotionPreviewElement extends View {
|
|
||||||
|
|
||||||
public PersonalMotionPreviewElement(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
// Initialize your custom view here (optional)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -25,12 +25,23 @@ public class PersonalMotionPreviewElement extends View {
|
|||||||
private double pathTime = 0.0D; // The timestamp at which the path is currently at.
|
private double pathTime = 0.0D; // The timestamp at which the path is currently at.
|
||||||
private MotionProcessor motionProcessor;
|
private MotionProcessor motionProcessor;
|
||||||
|
|
||||||
|
private Exercise exercise;
|
||||||
|
|
||||||
private Path referencePath; // The path the user is supposed to follow.
|
private Path referencePath; // The path the user is supposed to follow.
|
||||||
private Path performingPath; // The path the user is currently following.
|
private Path performingPath; // The path the user is currently following.
|
||||||
private Path stickmanPath; // The path of the stickman that is drawn on the screen.
|
private Path stickmanPath; // The path of the stickman that is drawn on the screen.
|
||||||
|
|
||||||
private Paint referencePaint;
|
private Paint referencePaint;
|
||||||
private Paint performingPaint;
|
private Paint performingPaint;
|
||||||
|
private Paint textPaint;
|
||||||
|
|
||||||
|
// Matrices for the projection of the path segments onto the screen.
|
||||||
|
// Depth buffering sadly is not supported yet due to brain dysfunction
|
||||||
|
private Matrix4f modelViewMatrix = new Matrix4f();
|
||||||
|
private Matrix4f projectionMatrix = new Matrix4f();
|
||||||
|
|
||||||
|
private double timePassed = 0.0D; // The time that has passed since the start of the exercise, in seconds.
|
||||||
|
private long startingTime = 0L;
|
||||||
|
|
||||||
private Paint backgroundColor = new Paint();
|
private Paint backgroundColor = new Paint();
|
||||||
|
|
||||||
@@ -40,7 +51,7 @@ public class PersonalMotionPreviewElement extends View {
|
|||||||
private final float FOV = 80.0f; // The field of view of the preview path
|
private final float FOV = 80.0f; // The field of view of the preview path
|
||||||
private final float Z_NEAR = 0.1f; // The near clipping plane
|
private final float Z_NEAR = 0.1f; // The near clipping plane
|
||||||
private final float Z_FAR = 1000.0f; // The far clipping plane
|
private final float Z_FAR = 1000.0f; // The far clipping plane
|
||||||
private Vector3f cameraPosition = new Vector3f(0.0f, 0.0f, -1.5f); // The position of the camera
|
private Vector3f objectPosition = new Vector3f(0.0f, 0.0f, 0.0f); // The position of the camera
|
||||||
private Vector2f screenDimensions = new Vector2f(); // Width and height dimensions of the screen
|
private Vector2f screenDimensions = new Vector2f(); // Width and height dimensions of the screen
|
||||||
private Vector2f rotation = new Vector2f(); // Rotation vector (yaw, pitch)
|
private Vector2f rotation = new Vector2f(); // Rotation vector (yaw, pitch)
|
||||||
|
|
||||||
@@ -56,12 +67,34 @@ public class PersonalMotionPreviewElement extends View {
|
|||||||
this.performingPaint.setColor(0xFF0000FF); // Blue
|
this.performingPaint.setColor(0xFF0000FF); // Blue
|
||||||
this.performingPaint.setStyle(Paint.Style.STROKE);
|
this.performingPaint.setStyle(Paint.Style.STROKE);
|
||||||
this.performingPaint.setStrokeWidth(5.0f);
|
this.performingPaint.setStrokeWidth(5.0f);
|
||||||
|
|
||||||
|
this.textPaint = new Paint();
|
||||||
|
this.textPaint.setColor(-1);
|
||||||
|
this.textPaint.setStyle(Paint.Style.FILL);
|
||||||
|
this.textPaint.setTextSize(50.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for updating the stickman gestures.
|
||||||
|
*
|
||||||
|
* This method will update the stickman gestures based on the current
|
||||||
|
* motion data that is being processed.
|
||||||
|
*/
|
||||||
private void updateStickmanGestures() {
|
private void updateStickmanGestures() {
|
||||||
// Reset previous path
|
// Reset previous path
|
||||||
stickmanPath.reset();
|
stickmanPath.reset();
|
||||||
|
|
||||||
|
// TODO: Define all arm segments:
|
||||||
|
// - Upper left and right arm
|
||||||
|
// - Lower left and right arm
|
||||||
|
// - Upper left and right leg
|
||||||
|
// - Lower left and right leg
|
||||||
|
// Update all segments based on the perceived motion data.
|
||||||
|
PathSegment upperLeftArm = new PathSegment(
|
||||||
|
new Vector3f(),
|
||||||
|
new Vector3f()
|
||||||
|
);
|
||||||
|
|
||||||
PathSegment[] bodySegments = new PathSegment[] {
|
PathSegment[] bodySegments = new PathSegment[] {
|
||||||
new PathSegment(new Vector3f(0.0f, -.5f, -.5f), new Vector3f(0, 0, 0)), // Left leg
|
new PathSegment(new Vector3f(0.0f, -.5f, -.5f), new Vector3f(0, 0, 0)), // Left leg
|
||||||
new PathSegment(new Vector3f(0.0f, -.5f, .5f), new Vector3f(0, 0, 0)), // Right leg
|
new PathSegment(new Vector3f(0.0f, -.5f, .5f), new Vector3f(0, 0, 0)), // Right leg
|
||||||
@@ -70,12 +103,15 @@ public class PersonalMotionPreviewElement extends View {
|
|||||||
new PathSegment(new Vector3f(.25f, .25f, 0f), new Vector3f(0, 0, 0)) // Right arm
|
new PathSegment(new Vector3f(.25f, .25f, 0f), new Vector3f(0, 0, 0)) // Right arm
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate new path for stickman
|
// TODO: Generate new path for stickman
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for initializing the PersonalMotionPreviewElement.
|
* Method for initializing the PersonalMotionPreviewElement.
|
||||||
|
* This method has to be called with a "post" function when the element has been
|
||||||
|
* created, otherwise the dimensions of the element aren't initialized yet, which
|
||||||
|
* will cause the vertex projections to fail (0 width and height).
|
||||||
*
|
*
|
||||||
* @param exercise The exercise that the user is currently performing.
|
* @param exercise The exercise that the user is currently performing.
|
||||||
*/
|
*/
|
||||||
@@ -89,7 +125,10 @@ public class PersonalMotionPreviewElement extends View {
|
|||||||
this.performingPath = new Path();
|
this.performingPath = new Path();
|
||||||
this.referencePath = new Path();
|
this.referencePath = new Path();
|
||||||
|
|
||||||
this.path = path;
|
this.startingTime = System.nanoTime(); // Set the last time to the current time
|
||||||
|
|
||||||
|
this.exercise = exercise;
|
||||||
|
this.path = exercise.getPath();
|
||||||
this.motionProcessor = new MotionProcessor();
|
this.motionProcessor = new MotionProcessor();
|
||||||
this.motionProcessor.startListening();
|
this.motionProcessor.startListening();
|
||||||
this.motionProcessor.setMotionDataEventHandler((processed, preprocessed, sampleIndex, sampleRate, deviceId) -> {
|
this.motionProcessor.setMotionDataEventHandler((processed, preprocessed, sampleIndex, sampleRate, deviceId) -> {
|
||||||
@@ -137,22 +176,23 @@ public class PersonalMotionPreviewElement extends View {
|
|||||||
* @return The transformed vector in screen coordinates ranging from (0, 0) to (virtualWidth, virtualHeight).
|
* @return The transformed vector in screen coordinates ranging from (0, 0) to (virtualWidth, virtualHeight).
|
||||||
*/
|
*/
|
||||||
private Vector2f projectVertex(Vector3f point, int virtualWidth, int virtualHeight) {
|
private Vector2f projectVertex(Vector3f point, int virtualWidth, int virtualHeight) {
|
||||||
Log.i("VertexProjection", "Projecting vertex to screen coordinates: " + point.toString() + " with virtual width " + virtualWidth + " and virtual height " + virtualHeight + ".");
|
|
||||||
Matrix4f modelViewMatrix = new Matrix4f()
|
modelViewMatrix
|
||||||
.translate(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z)
|
.identity()
|
||||||
|
.translate(-objectPosition.x, -objectPosition.y, -objectPosition.z)
|
||||||
.rotateX((float) Math.toRadians(rotation.y))
|
.rotateX((float) Math.toRadians(rotation.y))
|
||||||
.rotateY((float) Math.toRadians(rotation.x));
|
.rotateY((float) Math.toRadians(rotation.x));
|
||||||
|
|
||||||
Matrix4f projectionMatrix = new Matrix4f()
|
// Transform the projection matrix to a perspective projection matrix
|
||||||
|
// Perspective transformation conserves the depth of the object
|
||||||
|
projectionMatrix
|
||||||
|
.identity()
|
||||||
.perspective((float) Math.toRadians(FOV), (float) virtualWidth / virtualHeight, Z_NEAR, Z_FAR);
|
.perspective((float) Math.toRadians(FOV), (float) virtualWidth / virtualHeight, Z_NEAR, Z_FAR);
|
||||||
|
|
||||||
// Calculate Model-View-Projection matrix
|
// Convert world coordinates to screen-space using MVP matrix
|
||||||
Matrix4f MVP = new Matrix4f(projectionMatrix)
|
|
||||||
.mul(modelViewMatrix);
|
|
||||||
|
|
||||||
// Convert to screen coordinates
|
|
||||||
Vector4f screenCoordinates = new Vector4f(point, 1.0f)
|
Vector4f screenCoordinates = new Vector4f(point, 1.0f)
|
||||||
.mul(MVP);
|
.mul(this.modelViewMatrix)
|
||||||
|
.mul(this.projectionMatrix);
|
||||||
|
|
||||||
// Normalize screen coordinates from (-1, 1) to (0, virtualWidth) and (0, virtualHeight)
|
// Normalize screen coordinates from (-1, 1) to (0, virtualWidth) and (0, virtualHeight)
|
||||||
float normalizedX = (screenCoordinates.x / screenCoordinates.w + 1.0f) * 0.5f * virtualWidth;
|
float normalizedX = (screenCoordinates.x / screenCoordinates.w + 1.0f) * 0.5f * virtualWidth;
|
||||||
@@ -194,14 +234,18 @@ public class PersonalMotionPreviewElement extends View {
|
|||||||
public void onDraw(Canvas canvas) {
|
public void onDraw(Canvas canvas) {
|
||||||
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundColor);
|
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundColor);
|
||||||
this.setBackgroundColor(0xFF000000); // Black
|
this.setBackgroundColor(0xFF000000); // Black
|
||||||
if (path == null)
|
if (this.exercise == null)
|
||||||
return;
|
return;
|
||||||
// Draw the sport preview canvas
|
// Draw the sport preview canvas
|
||||||
canvas.drawPath(referencePath, referencePaint);
|
canvas.drawPath(referencePath, referencePaint);
|
||||||
canvas.drawPath(performingPath, performingPaint);
|
canvas.drawPath(performingPath, performingPaint);
|
||||||
|
|
||||||
|
canvas.drawText(this.exercise.getTitle(), 10, 40, textPaint);
|
||||||
|
|
||||||
|
timePassed = (System.nanoTime() - startingTime) / 1E9D;
|
||||||
|
|
||||||
this.rotation.add(1f, 0);
|
this.rotation.add(1f, 0);
|
||||||
this.referencePath = getDrawablePath(this.path.getSegments());
|
this.referencePath = getDrawablePath(this.path.getSegments());
|
||||||
this.invalidate();
|
this.invalidate(); // Causes a redraw.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user