diff --git a/code/src/Fitbot/.idea/misc.xml b/code/src/Fitbot/.idea/misc.xml index 135ab11..a67315e 100644 --- a/code/src/Fitbot/.idea/misc.xml +++ b/code/src/Fitbot/.idea/misc.xml @@ -22,6 +22,7 @@ + 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 d70c88c..32631ee 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 @@ -2,12 +2,12 @@ package com.example.fitbot.ui.components; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Path; import android.view.View; import com.example.fitbot.util.path.GesturePath; import com.example.fitbot.util.path.PathSegment; -import com.example.fitbot.util.path.Point3D; import com.example.fitbot.util.processing.MotionData; import com.example.fitbot.util.processing.MotionProcessor; @@ -22,6 +22,7 @@ public class PersonalMotionPreviewElement extends View { 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; /** * Constants for the preview path projection. @@ -45,22 +46,41 @@ public class PersonalMotionPreviewElement extends View { this.motionProcessor = new MotionProcessor(); this.motionProcessor.startListening(); this.motionProcessor.setMotionDataEventHandler((processed, preprocessed, sampleIndex, sampleRate) -> { - // TODO: Implement the calculation of the drawing path + // TODO: Implement the calculation of the `performingPath` based on the motion data }); - this.referencePath = generatePath() + this.referencePath = getDrawablePath(path.getSegments()); this.performingPath = new Path(); + + this.referencePaint = new Paint(); + this.referencePaint.setColor(-1); // White + 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); } /** * Method that calculates the path that will be drawn on the * canvas. This method will be called every time new motion data is received. */ - private void calculateDrawingPath(Point3D transformedVector, MotionData motionData, int sampleIndex, double sampleRate) { + private void calculateDrawingPath(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate) { // Recalculate the personal path based on the new motion data } + /** + * Method for setting the gesture path that will be drawn on the canvas. + * + * @param path The gesture path to draw. + */ + public void setGesturePath(GesturePath path) { + this.path = path; + this.referencePath = getDrawablePath(path.getSegments()); + } + /** * Method for setting the rotation of the preview path. * @@ -111,17 +131,12 @@ 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 curvature The curvature of the bezier curves. - * This number must be between 0 and 1, and it represents - * by how much the path segments will be curved. - * A value of 0 represents no curvature at all, - * while values closer to 1 approach full circular curvature. * @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(double curvature, PathSegment... segments) { + private Path getDrawablePath(PathSegment... segments) { Path calculatedPath = new Path(); @@ -144,8 +159,7 @@ public class PersonalMotionPreviewElement extends View { @Override public void onDraw(Canvas canvas) { // Draw the sport preview canvas - - - + canvas.drawPath(referencePath, referencePaint); + canvas.drawPath(performingPath, performingPaint); } } diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java index 05f58a7..9f0c361 100644 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java +++ b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/PathSegment.java @@ -4,11 +4,8 @@ import org.joml.Vector3f; public class PathSegment { - private final double curvature; - private final Vector3f start, end, normal; - private final double horizontalDistance; + private final Vector3f start, end; private final double distance; - private final double vectorAngle; // The angle of the vector from the start to the end point. /** * Constructor for creating a PathSegment of two lines, with the normal vector @@ -18,48 +15,8 @@ public class PathSegment { * @param end The end point of the line segment. */ public PathSegment(Vector3f start, Vector3f end) { - this.curvature = 0.0D; this.start = start; this.end = end; - this.horizontalDistance = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.z - start.z, 2)); - this.vectorAngle = Math.atan2(end.y - start.y, horizontalDistance); - this.distance = start.distance(end); - - // Normal vector calculation - double horizontalAngle = Math.atan2(end.z - start.z, end.x - start.x); - double verticalAngle = Math.atan2(end.y - start.y, horizontalDistance); - float sinVertical = (float)Math.sin(verticalAngle); - float cosVertical = (float)Math.cos(verticalAngle); - float sinHorizontal = (float)Math.sin(horizontalAngle); - float cosHorizontal = (float)Math.cos(horizontalAngle); - // The normal vector faces directly upward relative to the line between start and end. - // This means the normal vector is the perpendicular bisecting line from the line segment. - this.normal = new Vector3f( - sinVertical * cosHorizontal, - cosVertical, - sinVertical * sinHorizontal - ); - } - - /** - * Create a new path segment with a given start and end point. - * - * @param start The start point of the path segment. - * @param end The end point of the path segment. - * A value of 0 will result in the normal vector pointing upwards. - * @param normal The normal vector of the path segment. - * This vector determines how the line curves, if it has a positive curvature. - * @param curvature The curvature of the path segment. - * This value is between -1 and 1, and is used to determine the curvature of the path, - * around the normal vector. - */ - public PathSegment(Vector3f start, Vector3f end, Vector3f normal, double curvature) { - this.curvature = curvature; - this.start = start; - this.end = end; - this.horizontalDistance = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.z - start.z, 2)); - this.vectorAngle = Math.atan2(end.y - start.y, horizontalDistance); - this.normal = normal; this.distance = start.distance(end); } @@ -71,40 +28,9 @@ public class PathSegment { * @param dst The destination vector to interpolate to. * @param t The interpolation value between 0 and 1. */ - public void interpolate(Vector3f dst, double t) { - t = Math.min(1.0D, Math.max(0.0D, t)); // Ensure boundaries - - // If curvature is 0, use linear interpolation. - if (this.curvature == 0.0D) { - dst.set(start).lerp(end, (float) t); - } else { - // Interpolate over the ellipse. - double angle = t * Math.PI + vectorAngle; // Angle for on the ellipse - double cos = Math.cos(angle); - double sin = Math.sin(angle); - - double - - // Calculate the ellipse. - - - } - } - - /** - * Method for returning the control point of the path segment. - * This point is the point that the path segment curves around. - * - * @return The control point of the path segment. - */ - public Vector3f getControlPoint() { - return new Vector3f( - (this.start.x + this.end.x) / 2.0F, - (this.start.y + this.end.y) / 2.0F, - (this.start.z + this.end.z) / 2.0F - ) - .add(this.normal - .mul((float) this.curvature * (float) this.distance / 2.0F)); + public Vector3f interpolate(Vector3f dst, double t) { + return new Vector3f(this.start) + .lerp(this.end, (float) Math.min(1.0F, Math.max(0.0F, t))); } /** @@ -117,16 +43,21 @@ public class PathSegment { * @return The difference between the vector and the path segment. */ public double difference(Vector3f other) { - return 0.0D; // TODO: Implement. - } - /** - * Get the curvature of the path segment. - * - * @return The curvature of the path segment. - */ - public double getVectorAngle() { - return this.vectorAngle; + if (this.distance == 0) + return this.start.distance(other); + + double t = ((other.x - this.start.x) * (this.end.x - this.start.x) + + (other.y - this.start.y) * (this.end.y - this.start.y) + + (other.z - this.start.z) * (this.end.z - this.start.z)) / distance; + + t = Math.max(0, Math.min(1, t)); + + return other.distance(new Vector3f( + (float) (this.start.x + t * (this.end.x - this.start.x)), + (float) (this.start.y + t * (this.end.y - this.start.y)), + (float) (this.start.z + t * (this.end.z - this.start.z)) + )); } /** diff --git a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/Point3D.java b/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/Point3D.java deleted file mode 100644 index de14c78..0000000 --- a/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/path/Point3D.java +++ /dev/null @@ -1,258 +0,0 @@ -package com.example.fitbot.util.path; - -import java.util.Arrays; -import java.util.Comparator; - -public class Point3D { - - public double x, y, z; - - /** - * Constructor for creating a new vector. - * - * @param x The X component of the vector. - * @param y The Y component of the vector. - * @param z The Z component of the vector. - */ - public Point3D(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** - * Copy the vector. - * - * @return A new vector with the same values. - */ - public Point3D copy() { - return new Point3D(this.x, this.y, this.z); - } - - /** - * Get the zero vector. - * - * @return The zero vector. - */ - public static Point3D zero() { - return new Point3D(0, 0, 0); - } - - /** - * Get the magnitude of the vector. - * - * @return The magnitude of the vector. - */ - public double magnitude() { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); - } - - /** - * Normalize the vector. - * - * @return The normalized vector. - */ - public Point3D normalize() { - double mag = this.magnitude(); - if (mag == 0) throw new IllegalArgumentException("Cannot normalize the zero vector."); - return new Point3D(this.x / mag, this.y / mag, this.z / mag); - } - - /** - * Subtract the vector from another vector. - * - * @param other The other vector to subtract. - * @return The new vector. - */ - public Point3D subtract(Point3D other) { - return new Point3D(this.x - other.x, this.y - other.y, this.z - other.z); - } - - /** - * Add the vector to another vector. - * - * @param other The other vector to add. - * @return The new vector. - */ - public Point3D add(Point3D other) { - return new Point3D(this.x + other.x, this.y + other.y, this.z + other.z); - } - - /** - * Multiply the vector by a scalar. - * - * @param scalar The scalar to multiply by. - * @return The multiplied vector. - */ - public Point3D multiply(double scalar) { - return new Point3D(this.x * scalar, this.y * scalar, this.z * scalar); - } - - /** - * Divide the vector by a scalar. - * - * @param scalar The scalar to divide by. - * @return The divided vector. - */ - public Point3D divide(double scalar) { - if (scalar == 0) throw new IllegalArgumentException("Cannot divide by zero."); - return new Point3D(this.x / scalar, this.y / scalar, this.z / scalar); - } - - /** - * Negate the vector. - * - * @return The negated vector. - */ - public Point3D negate() { - return new Point3D(-this.x, -this.y, -this.z); - } - - /** - * Rotate the vector around the X, Y, and Z axes. - * - * @param radX Rotation around the X axis in radians. - * @param radY Rotation around the Y axis in radians. - * @param radZ Rotation around the Z axis in radians. - * @return The rotated vector. - */ - public Point3D rotate(double radX, double radY, double radZ) { - double cosX = Math.cos(radX); - double cosY = Math.cos(radY); - double cosZ = Math.cos(radZ); - double sinX = Math.sin(radX); - double sinY = Math.sin(radY); - double sinZ = Math.sin(radZ); - double newX = x * cosY * cosZ + y * cosY * sinZ - z * sinY; - double newY = x * (sinX * sinY * cosZ - cosX * sinZ) + y * (sinX * sinY * sinZ + cosX * cosZ) + z * sinX * cosY; - double newZ = x * (cosX * sinY * cosZ + sinX * sinZ) + y * (cosX * sinY * sinZ - sinX * cosZ) + z * cosX * cosY; - return new Point3D(newX, newY, newZ); - } - - /** - * Rotate the vector around the X, Y, and Z axes. - * - * @param rotation The rotation vector. - * @return The rotated vector. - */ - public Point3D rotate(Point3D rotation) { - return rotate(rotation.x, rotation.y, rotation.z); - } - - /** - * Rotate the vector around the X axis. - * - * @param angle Rotation around the X axis in radians. - * @return The rotated vector. - */ - public Point3D rotateX(double angle) { - double sinTheta = Math.sin(angle); - double cosTheta = Math.cos(angle); - return new Point3D( - x, - y * cosTheta - z * sinTheta, - y * sinTheta + z * cosTheta - ); - } - - /** - * Rotate the vector around the Y axis. - * - * @param angle Rotation around the Y axis in radians. - * @return The rotated vector. - */ - public Point3D rotateY(double angle) { - double sinTheta = Math.sin(angle); - double cosTheta = Math.cos(angle); - return new Point3D( - x * cosTheta + z * sinTheta, - y, - -x * sinTheta + z * cosTheta - ); - } - - /** - * Rotate the vector around the Z axis. - * - * @param angle Rotation around the Z axis in radians. - * @return The rotated vector. - */ - public Point3D rotateZ(double angle) { - double sinTheta = Math.sin(angle); - double cosTheta = Math.cos(angle); - return new Point3D( - x * cosTheta - y * sinTheta, - x * sinTheta + y * cosTheta, - z - ); - } - - /** - * Get the squared distance between this vector and another vector. - * - * @param compare The other vector. - * @return The squared distance between the two vectors. - */ - public double distanceSq(Point3D compare) { - return Math.pow(compare.x - x, 2) + Math.pow(compare.y - y, 2) + Math.pow(compare.z - z, 2); - } - - /** - * Get the distance between this vector and another vector. - * - * @param compare The other vector. - * @return The distance between the two vectors. - */ - public double distance(Point3D compare) { - return Math.sqrt(distanceSq(compare)); - } - - /** - * Calculate the distance to a line defined by two points. - * - * @param lineStart The starting point of the line. - * @param lineEnd The ending point of the line. - * @return The distance to the line. - */ - public double distanceToLine(Point3D lineStart, Point3D lineEnd) { - double lineDistance = lineStart.distanceSq(lineEnd); - if (lineDistance == 0) - return this.distanceSq(lineStart); - - double t = ((this.x - lineStart.x) * (lineEnd.x - lineStart.x) + - (this.y - lineStart.y) * (lineEnd.y - lineStart.y) + - (this.z - lineStart.z) * (lineEnd.z - lineStart.z)) / lineDistance; - - t = Math.max(0, Math.min(1, t)); - - return this.distanceSq(new Point3D( - lineStart.x + t * (lineEnd.x - lineStart.x), - lineStart.y + t * (lineEnd.y - lineStart.y), - lineStart.z + t * (lineEnd.z - lineStart.z)) - ); - } - - /** - * Retrieve the closest vector to this one given a list of vectors. - * - * @param vectors The list of vectors to compare. - * @return The closest vector. - */ - public Point3D closest(Point3D... vectors) { - return Arrays.stream(vectors).min(Comparator.comparingDouble(this::distanceSq)).orElse(null); - } - - public Point3D map(VectorMapFunction function) { - return function.apply(this); - } - - public interface VectorMapFunction { - Point3D apply(Point3D vector); - } - - @Override - public String toString() - { - return "Vector3(" + this.x + ", " + this.y + ", " + this.z + ")"; - } -} diff --git a/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml b/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml new file mode 100644 index 0000000..35990c8 --- /dev/null +++ b/code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file