diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 02ead3a..b85ca9c 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -14,10 +14,9 @@ - - + + - - @@ -327,6 +333,7 @@ - \ No newline at end of file diff --git a/code/src/Fitbot/.idea/misc.xml b/code/src/Fitbot/.idea/misc.xml index e88f6f5..569b9cc 100644 --- a/code/src/Fitbot/.idea/misc.xml +++ b/code/src/Fitbot/.idea/misc.xml @@ -31,6 +31,7 @@ + diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/AbstractExercise.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java similarity index 72% rename from code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/AbstractExercise.java rename to code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java index daf7d8b..7beb007 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/AbstractExercise.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/Exercise.java @@ -8,14 +8,17 @@ import com.example.fitbot.util.server.WebSocket; import java.util.Objects; -public abstract class AbstractExercise implements IWebSocketHandler { +public class Exercise implements IWebSocketHandler { private EMuscleGroup muscleGroup; private GesturePath path; + private String title; + private String description; + private float segmentsPerSecond; // Static fields. private static WebSocket webSocket; - private static AbstractExercise currentExercise = null; + private static Exercise currentExercise = null; /** @@ -23,10 +26,17 @@ public abstract class AbstractExercise implements IWebSocketHandler { * * @param muscleGroup The muscle group of the exercise. * @param path The path of the exercise. + * @param title The title of the exercise. + * @param description The description of the exercise. + * @param segmentsPerSecond The number of segments per second. + * This determines how fast the exercise should be performed. */ - public AbstractExercise(EMuscleGroup muscleGroup, GesturePath path) { + public Exercise(EMuscleGroup muscleGroup, String title, String description, GesturePath path, float segmentsPerSecond) { this.muscleGroup = muscleGroup; + this.title = title; + this.description = description; this.path = path; + this.segmentsPerSecond = segmentsPerSecond; } /** @@ -101,4 +111,19 @@ public abstract class AbstractExercise implements IWebSocketHandler { public GesturePath getPath() { return path; } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + /** + * Get the speed of the exercise. + */ + public double getSegmentsPerSecond() { + return segmentsPerSecond; + } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseBuilder.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseBuilder.java new file mode 100644 index 0000000..a770475 --- /dev/null +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/ExerciseBuilder.java @@ -0,0 +1,41 @@ +package com.example.fitbot.exercise; + +import com.example.fitbot.util.processing.IMotionDataConsumer; +import com.example.fitbot.util.processing.MotionData; +import com.example.fitbot.util.processing.MotionProcessor; +import com.example.fitbot.util.server.IWebSocketHandler; +import com.example.fitbot.util.server.WebSocket; + +import org.joml.Vector3f; + +import java.net.Socket; + +public class ExerciseBuilder implements IWebSocketHandler, IMotionDataConsumer { + + private MotionProcessor processor; + + public ExerciseBuilder() { + this.processor = new MotionProcessor(); + this.processor.setMotionDataEventHandler(this); + } + + @Override + public void onDisconnected(Socket socket) { + IWebSocketHandler.super.onDisconnected(socket); + } + + @Override + public void onMessageReceived(WebSocket.Message message, WebSocket.MessageReply replier) { + IWebSocketHandler.super.onMessageReceived(message, replier); + } + + @Override + public void onError(Socket socket, String error) { + IWebSocketHandler.super.onError(socket, error); + } + + @Override + public void accept(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate, int sensorId) { + + } +} diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/FitnessManager.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/FitnessManager.java index ada8292..5036a0a 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/FitnessManager.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/exercise/FitnessManager.java @@ -50,7 +50,7 @@ public class FitnessManager { * @param uniqueIdentifier The unique identifier of the exercise * @return The exercise, if it exists on the server. Otherwise null. */ - public static AbstractExercise acquireExercise(String uniqueIdentifier, Class referenceClass) { + public static Exercise acquireExercise(String uniqueIdentifier, Class referenceClass) { String response = sendHTTP( HOST_ADDRESS + "/acquire", "GET", "application/json", "{\"kind\":\"" + uniqueIdentifier + "\"}" ); diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/FitnessActivity.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/FitnessActivity.java index cc2331b..8f886fa 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/FitnessActivity.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/FitnessActivity.java @@ -1,12 +1,8 @@ package com.example.fitbot.ui.activities; -import static com.example.fitbot.sports.Animations.Animate; - -import android.content.Context; import android.net.Uri; import android.os.Bundle; -import android.util.AttributeSet; -import android.view.View; +import android.util.Log; import android.widget.MediaController; import android.widget.VideoView; @@ -14,38 +10,67 @@ import com.aldebaran.qi.sdk.QiContext; import com.aldebaran.qi.sdk.QiSDK; import com.aldebaran.qi.sdk.RobotLifecycleCallbacks; import com.aldebaran.qi.sdk.design.activity.RobotActivity; -import com.example.fitbot.ui.activities.EndScreenActivity; import com.example.fitbot.R; import com.example.fitbot.sports.Animations; +import com.example.fitbot.ui.components.PersonalMotionPreviewElement; +import com.example.fitbot.util.path.GesturePath; + +import org.joml.Vector3f; public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks { +// PersonalMotionPreviewElement personalMotionPreviewElement; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // Set the content view to the appropriate layout setContentView(R.layout.activity_fitness); + // Find the VideoView by its ID VideoView videoView = findViewById(R.id.videoView); - videoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.bicepvideo)); - MediaController mediaController = new MediaController(this); - videoView.setMediaController(mediaController); - videoView.start(); + if (videoView != null) { + Uri videoUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.bicepvideo); + videoView.setVideoURI(videoUri); + videoView.start(); + } else { + Log.e("FitnessActivity", "VideoView is null. Check your layout XML."); + } com.example.fitbot.util.ButtonNavigation.setupButtonNavigation(this, R.id.homeButton, MainActivity.class); com.example.fitbot.util.ButtonNavigation.setupButtonNavigation(this, R.id.buttonComplete, EndScreenActivity.class); + + GesturePath.Builder gesturePathBuilder = new GesturePath.Builder(); + + gesturePathBuilder.addVector(new Vector3f(-.5f, -.5f, -.5f)); + gesturePathBuilder.addVector(new Vector3f(.5f, -.5f, -.5f)); + gesturePathBuilder.addVector(new Vector3f(.5f, -.5f, .5f)); + gesturePathBuilder.addVector(new Vector3f(-.5f, -.5f, .5f)); + gesturePathBuilder.addVector(new Vector3f(-.5f, -.5f, -.5f)); + + gesturePathBuilder.addVector(new Vector3f(-.5f, .5f, -.5f)); + gesturePathBuilder.addVector(new Vector3f(.5f, .5f, -.5f)); + gesturePathBuilder.addVector(new Vector3f(.5f, .5f, .5f)); + gesturePathBuilder.addVector(new Vector3f(-.5f, .5f, .5f)); + gesturePathBuilder.addVector(new Vector3f(-.5f, .5f, -.5f)); + + // Uncomment and fix if needed for personalMotionPreviewElement + // personalMotionPreviewElement = findViewById(R.id.personalMotionPreviewElement); + // personalMotionPreviewElement.post(() -> { + // Log.i("FitnessActivity", "PersonalMotionPreviewElement.post()"); + // + // Exercise exercise = new Exercise(EMuscleGroup.ARMS, "Bicep Curls", "Oefening voor de biceps.", gesturePathBuilder.build(), 1); + // + // personalMotionPreviewElement.initialize(exercise); + // }); } - -// QiSDK.register(this, this); -// -// - @Override public void onRobotFocusGained(QiContext qiContext) { // Implement your logic when the robot focus is gained - Animate("bicepcurl", qiContext); - + Animations.Animate("bicepcurl", qiContext); } @Override @@ -61,15 +86,6 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall @Override protected void onDestroy() { QiSDK.unregister(this, this); - super.onDestroy(); } - public static class PersonalMotionPreviewElement extends View { - - public PersonalMotionPreviewElement(Context context, AttributeSet attrs) { - super(context, attrs); - // Initialize your custom view here (optional) - } - } - } \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java index ef111ad..d482362 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/components/PersonalMotionPreviewElement.java @@ -4,9 +4,11 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; +import android.util.AttributeSet; import android.util.Log; import android.view.View; +import com.example.fitbot.exercise.Exercise; import com.example.fitbot.util.path.GesturePath; import com.example.fitbot.util.path.PathSegment; import com.example.fitbot.util.processing.MotionData; @@ -22,50 +24,116 @@ public class PersonalMotionPreviewElement extends View { private GesturePath path; private double pathTime = 0.0D; // The timestamp at which the path is currently at. private MotionProcessor motionProcessor; - private Path referencePath, performingPath; - private Paint referencePaint, performingPaint; + + private Exercise exercise; + + private Path referencePath; // The path the user is supposed to follow. + 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 Paint referencePaint; + 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(); /** * Constants for the preview path projection. */ - private final float FOV = 70.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_FAR = 1000.0f; // The far clipping plane - private Vector3f cameraPosition = new Vector3f(0.0f, 0.0f, 0.0f); // 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 rotation = new Vector2f(); // Rotation vector (yaw, pitch) - /** - * Constructor for the PersonalMotionPreviewElement class. - * - * @param context The context in which this element is created. - * @param path The gesture path that will be drawn on the canvas. - */ - public PersonalMotionPreviewElement(Context context, GesturePath path) { - super(context); - Log.i("PersonalMotionPreviewElement", "Creating new PersonalMotionPreviewElement."); - this.backgroundColor = new Paint(); - this.backgroundColor.setColor(0xFF000000); // Black - this.path = path; - this.motionProcessor = new MotionProcessor(); - this.motionProcessor.startListening(); - this.motionProcessor.setMotionDataEventHandler((processed, preprocessed, sampleIndex, sampleRate) -> { - // TODO: Implement the calculation of the `performingPath` based on the motion data - }); - - this.referencePath = getDrawablePath(path.getSegments()); - this.performingPath = new Path(); + public PersonalMotionPreviewElement(Context context, AttributeSet attrs) { + super(context, attrs); this.referencePaint = new Paint(); - this.referencePaint.setColor(-1); // White + this.referencePaint.setColor(0xFFFF0000); // Red this.referencePaint.setStyle(Paint.Style.STROKE); this.referencePaint.setStrokeWidth(5.0f); + this.performingPaint = new Paint(); this.performingPaint.setColor(0xFF0000FF); // Blue this.performingPaint.setStyle(Paint.Style.STROKE); 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() { + // Reset previous path + 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[] { + 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, 0.0f), new Vector3f(0, 0, 0)), // Body + new PathSegment(new Vector3f(-.25f, .25f, 0f), new Vector3f(0, 0, 0)), // Left arm + new PathSegment(new Vector3f(.25f, .25f, 0f), new Vector3f(0, 0, 0)) // Right arm + }; + + // TODO: Generate new path for stickman + + } + + /** + * 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. + */ + public void initialize(Exercise exercise) { + Log.i("PersonalMotionPreviewElement", "Creating new PersonalMotionPreviewElement."); + this.backgroundColor = new Paint(); + this.backgroundColor.setColor(0xFF000000); // Black + + this.screenDimensions.x = this.getWidth(); + this.screenDimensions.y = this.getHeight(); + this.performingPath = new Path(); + this.referencePath = new 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.startListening(); + this.motionProcessor.setMotionDataEventHandler((processed, preprocessed, sampleIndex, sampleRate, deviceId) -> { + // TODO: Implement the calculation of the `performingPath` based on the motion data + }); } /** @@ -90,7 +158,7 @@ public class PersonalMotionPreviewElement extends View { /** * Method for setting the rotation of the preview path. * - * @param yaw The yaw rotation of the preview path. + * @param yaw The yaw rotation of the preview path. * @param pitch The pitch rotation of the preview path. */ public void setRotation(float yaw, float pitch) { @@ -98,38 +166,38 @@ public class PersonalMotionPreviewElement extends View { } /** - * Method for projecting a 3D point onto the screen. - * This method converts the 3D point to 2D space using a Model-View-Projection matrix transformation. + * Method for projecting a 3D point onto the screen. + * This method converts the 3D point to 2D space using a Model-View-Projection matrix transformation. * - * @param point The point to cast to the screen. - * @param virtualWidth The width of the virtual screen. - * This is used to normalize the screen coordinates. + * @param point The point to cast to the screen. + * @param virtualWidth The width of the virtual screen. + * This is used to normalize the screen coordinates. * @param virtualHeight The height of the virtual screen. * @return The transformed vector in screen coordinates ranging from (0, 0) to (virtualWidth, virtualHeight). */ private Vector2f projectVertex(Vector3f point, int virtualWidth, int virtualHeight) { - Matrix4f modelViewMatrix = new Matrix4f() - .rotateX((float) Math.toRadians(rotation.x)) - .rotateY((float) Math.toRadians(rotation.y)) - .translate(cameraPosition); + modelViewMatrix + .identity() + .translate(-objectPosition.x, -objectPosition.y, -objectPosition.z) + .rotateX((float) Math.toRadians(rotation.y)) + .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); - // Calculate Model-View-Projection matrix - Matrix4f MVP = new Matrix4f() - .set(projectionMatrix) - .mul(modelViewMatrix); - - // Convert to screen coordinates + // Convert world coordinates to screen-space using MVP matrix 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) float normalizedX = (screenCoordinates.x / screenCoordinates.w + 1.0f) * 0.5f * virtualWidth; float normalizedY = (1.0f - screenCoordinates.y / screenCoordinates.w) * 0.5f * virtualHeight; - + Log.i("VertexProjection", "Projected vertex to screen coordinates: (" + normalizedX + ", " + normalizedY + ")."); return new Vector2f(normalizedX, normalizedY); } @@ -137,9 +205,9 @@ public class PersonalMotionPreviewElement extends View { * Method that converts a sequence of vectors to a Path object. * This path is a set of bezier curves that will be drawn on the canvas. * - * @param segments The path segments in the path. - * These segments will be connected by bezier curves, which - * all have unique curvature values. + * @param segments The path segments in the path. + * These segments will be connected by bezier curves, which + * all have unique curvature values. * @return The generated path object. */ private Path getDrawablePath(PathSegment... segments) { @@ -152,8 +220,8 @@ public class PersonalMotionPreviewElement extends View { // Draw the path segments for (PathSegment segment : segments) { - Vector2f startProjected = projectVertex(segment.getStart(), getWidth()/2, getHeight()); - Vector2f endProjected = projectVertex(segment.getEnd(), getWidth()/2, getHeight()); + Vector2f startProjected = projectVertex(segment.getStart(), getWidth(), getHeight()); + Vector2f endProjected = projectVertex(segment.getEnd(), getWidth(), getHeight()); calculatedPath.lineTo(startProjected.x, startProjected.y); calculatedPath.lineTo(endProjected.x, endProjected.y); } @@ -165,8 +233,19 @@ public class PersonalMotionPreviewElement extends View { @Override public void onDraw(Canvas canvas) { canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundColor); + this.setBackgroundColor(0xFF000000); // Black + if (this.exercise == null) + return; // Draw the sport preview canvas canvas.drawPath(referencePath, referencePaint); canvas.drawPath(performingPath, performingPaint); + + canvas.drawText(this.exercise.getTitle(), 10, 40, textPaint); + + timePassed = (System.nanoTime() - startingTime) / 1E9D; + + this.rotation.add(1f, 0); + this.referencePath = getDrawablePath(this.path.getSegments()); + this.invalidate(); // Causes a redraw. } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java index 88c41ad..61229c2 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/GesturePath.java @@ -11,17 +11,12 @@ public class GesturePath { // The vectors that make up the path. private final PathSegment[] segments; - public GesturePath(Vector3f[] vectors) { - this(vectors, 0.0D); - } - /** * Create a new gesture path with a given set of vectors and curvature. * * @param vectors The vectors that make up the path. - * @param curvature The curvature of the path. */ - public GesturePath(Vector3f[] vectors, double curvature) + public GesturePath(Vector3f[] vectors) { if ( vectors.length < 2) throw new IllegalArgumentException("A path must have at least two points."); diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IMotionDataConsumer.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IMotionDataConsumer.java index b09726d..dd3220c 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IMotionDataConsumer.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/IMotionDataConsumer.java @@ -11,6 +11,6 @@ public interface IMotionDataConsumer { * @param sampleIndex The index of the current sample * @param sampleRate The sample rate. */ - void accept(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate); + void accept(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate, int sensorId); } \ No newline at end of file diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java index 37e016f..fae42fd 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java @@ -8,6 +8,7 @@ public class MotionData { // Data of the motion sensor public Vector3f acceleration, rotation; + public int sensorId; // Delimiter for the data received from the motion sensor private static final String DATA_DELIMITER = ";"; @@ -21,10 +22,10 @@ public class MotionData { * @param rotationX The rotation in the X axis in degrees. * @param rotationY The rotation in the Y axis in degrees. * @param rotationZ The rotation in the Z axis in degrees. + * @param sensorId The sensor id. */ - public MotionData(float accelerationX, float accelerationY, float accelerationZ, float rotationX, float rotationY, float rotationZ) { - this.acceleration = new Vector3f(accelerationX, accelerationY, accelerationZ); - this.rotation = new Vector3f(rotationX, rotationY, rotationZ); + public MotionData(float accelerationX, float accelerationY, float accelerationZ, float rotationX, float rotationY, float rotationZ, int sensorId) { + this(new Vector3f(accelerationX, accelerationY, accelerationZ), new Vector3f(rotationX, rotationY, rotationZ), sensorId); } /** @@ -33,9 +34,10 @@ public class MotionData { * @param acceleration The acceleration vector in m/s^2. * @param rotation The rotation vector in degrees. */ - public MotionData(Vector3f acceleration, Vector3f rotation) { + public MotionData(Vector3f acceleration, Vector3f rotation, int sensorId) { this.acceleration = acceleration; this.rotation = rotation; + this.sensorId = sensorId; } /** @@ -50,7 +52,7 @@ public class MotionData { Objects.requireNonNull(data); // Ensure data is not null String[] parts = data.split(DATA_DELIMITER); - if (parts.length != 6) + if (parts.length != 7) return null; return new MotionData( @@ -59,7 +61,8 @@ public class MotionData { Float.parseFloat(parts[2]), Float.parseFloat(parts[3]), Float.parseFloat(parts[4]), - Float.parseFloat(parts[5]) + Float.parseFloat(parts[5]), + Integer.parseInt(parts[6]) ); } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java index 9a04461..b5d2b2b 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java @@ -22,7 +22,7 @@ public class MotionProcessor { private Vector3f ZERO = new Vector3f(0, 0, 0); private float sampleRate = 1.0F; // samples/second - private IMotionDataConsumer motionDataConsumer = (p1, p2, p3, p4) -> {}; + private IMotionDataConsumer motionDataConsumer = (p1, p2, p3, p4, p5) -> {}; private GesturePath path; private WebSocket socket; @@ -110,7 +110,7 @@ public class MotionProcessor { Vector3f previous = this.relativePath.isEmpty() ? ZERO : this.relativePath.get(this.relativePath.size() - 1); Vector3f relativeVector = getRelativeVector(data).add(previous); this.relativePath.add(relativeVector); - motionDataConsumer.accept(relativeVector, data, this.relativePath.size(), this.sampleRate); + motionDataConsumer.accept(relativeVector, data, this.relativePath.size(), this.sampleRate, data.sensorId); } /** diff --git a/code/src/Fitbot/app/src/main/res/layout/activity_main.xml b/code/src/Fitbot/app/src/main/res/layout/activity_main.xml index 901a002..958965c 100644 --- a/code/src/Fitbot/app/src/main/res/layout/activity_main.xml +++ b/code/src/Fitbot/app/src/main/res/layout/activity_main.xml @@ -9,67 +9,77 @@ tools:context=".ui.activities.MainActivity" tools:openDrawer="start"> - + android:orientation="horizontal"> + layout="@layout/toolbar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + android:textSize="64sp" + app:layout_constraintStart_toStartOf="parent" /> + android:textSize="32sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" />