This commit is contained in:
Luca Warmenhoven
2024-05-15 16:29:22 +02:00
parent 606a05aa13
commit 612b1c8a7c
5 changed files with 56 additions and 358 deletions

View File

@@ -22,6 +22,7 @@
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_sport_menu.xml" value="0.1" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/header.xml" value="0.125" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/toolbar.xml" value="0.125" />
<entry key="app/src/main/res/layout/activity_fitness.xml" value="0.23550724637681159" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.1" />
<entry key="app/src/main/res/layout/activity_sport_item.xml" value="0.2341485507246377" />
<entry key="app/src/main/res/layout/activity_sport_menu.xml" value="0.22056159420289856" />

View File

@@ -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);
}
}

View File

@@ -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))
));
}
/**

View File

@@ -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 + ")";
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.fitbot.ui.components.PersonalMotionPreviewElement
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>