Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66
This commit is contained in:
31
.idea/workspace.xml
generated
31
.idea/workspace.xml
generated
@@ -14,10 +14,9 @@
|
||||
</configurations>
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="00599d5b-7eb5-44da-ad7f-98bf42384c16" name="Changes" comment="Renamed files, added motion-tracking-system-analysis.md">
|
||||
<list default="true" id="00599d5b-7eb5-44da-ad7f-98bf42384c16" name="Changes" comment="Updated onderzoek-voorbeeld.md & motion-tracking-system-analysis.md">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docs/documentation/research-questions/motion-tracking-system-analysis.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/documentation/research-questions/motion-tracking-system-analysis.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docs/personal-documentation/Luca/literatuuronderzoek/onderzoek-voorbeeld.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/personal-documentation/Luca/literatuuronderzoek/onderzoek-voorbeeld.md" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -144,7 +143,7 @@
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-js-predefined-1d06a55b98c1-2e7d6887c066-JavaScript-WS-241.15989.47" />
|
||||
<option value="bundled-js-predefined-1d06a55b98c1-91d5c284f522-JavaScript-WS-241.15989.105" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
@@ -164,7 +163,9 @@
|
||||
<workItem from="1715686350378" duration="91000" />
|
||||
<workItem from="1715687332786" duration="822000" />
|
||||
<workItem from="1715724270673" duration="5481000" />
|
||||
<workItem from="1715765990621" duration="4442000" />
|
||||
<workItem from="1715765990621" duration="8538000" />
|
||||
<workItem from="1715777647522" duration="725000" />
|
||||
<workItem from="1715779408605" duration="3840000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Changes">
|
||||
<created>1713528225837</created>
|
||||
@@ -242,7 +243,23 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1715767477412</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="11" />
|
||||
<task id="LOCAL-00011" summary="Updated onderzoek-voorbeeld.md and motion-tracking-system-analysis.md">
|
||||
<option name="closed" value="true" />
|
||||
<created>1715773120402</created>
|
||||
<option name="number" value="00011" />
|
||||
<option name="presentableId" value="LOCAL-00011" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1715773120402</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00012" summary="Updated onderzoek-voorbeeld.md & motion-tracking-system-analysis.md">
|
||||
<option name="closed" value="true" />
|
||||
<created>1715780873394</created>
|
||||
<option name="number" value="00012" />
|
||||
<option name="presentableId" value="LOCAL-00012" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1715780873394</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="13" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -271,6 +288,8 @@
|
||||
<MESSAGE value="onderzoek-voorbeeld.md" />
|
||||
<MESSAGE value="Updated onderzoek-voorbeeld.md" />
|
||||
<MESSAGE value="Renamed files, added motion-tracking-system-analysis.md" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Renamed files, added motion-tracking-system-analysis.md" />
|
||||
<MESSAGE value="Updated onderzoek-voorbeeld.md and motion-tracking-system-analysis.md" />
|
||||
<MESSAGE value="Updated onderzoek-voorbeeld.md & motion-tracking-system-analysis.md" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Updated onderzoek-voorbeeld.md & motion-tracking-system-analysis.md" />
|
||||
</component>
|
||||
</project>
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.configuration.updateBuildConfiguration": "interactive"
|
||||
}
|
1
code/src/Fitbot/.idea/misc.xml
generated
1
code/src/Fitbot/.idea/misc.xml
generated
@@ -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" />
|
||||
|
@@ -34,6 +34,7 @@ dependencies {
|
||||
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
|
||||
implementation 'com.android.support:cardview-v7:28.0.0'
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
implementation 'org.joml:joml:1.10.5'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
|
@@ -4,6 +4,10 @@
|
||||
|
||||
<uses-feature android:name="com.softbank.hardware.pepper" />
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@@ -11,10 +15,6 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Fitbot" >
|
||||
<activity
|
||||
android:name=".ui.SportMenuActivity"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.activities.MainActivity"
|
||||
android:exported="true" >
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package com.example.yourapp;
|
||||
package com.example.fitbot.ui.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import com.aldebaran.qi.sdk.QiContext;
|
||||
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
|
||||
import com.aldebaran.qi.sdk.design.activity.RobotActivity;
|
||||
@@ -11,7 +10,6 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_fitness);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package com.example.fitbot;
|
||||
package com.example.fitbot.ui.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
@@ -9,14 +8,10 @@ import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.widget.Button;
|
||||
|
||||
import com.example.fitbot.R;
|
||||
import com.example.fitbot.util.processing.GesturePath;
|
||||
import com.example.fitbot.util.processing.MotionProcessor;
|
||||
import com.example.fitbot.util.processing.Vector3;
|
||||
|
||||
public class MainScreen extends AppCompatActivity {
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
//Variables
|
||||
DrawerLayout drawerLayout;
|
||||
@@ -41,7 +36,7 @@ public class MainScreen extends AppCompatActivity {
|
||||
navigationView.bringToFront();
|
||||
|
||||
ActionBarDrawerToggle toggle=new
|
||||
ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.navigation_drawer_open,R.string.navigation_drawer_close);
|
||||
ActionBarDrawerToggle(this,drawerLayout,toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
|
||||
drawerLayout.addDrawerListener(toggle);
|
||||
toggle.syncState();
|
||||
}
|
||||
|
@@ -2,42 +2,164 @@ 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.processing.GesturePath;
|
||||
import com.example.fitbot.util.path.GesturePath;
|
||||
import com.example.fitbot.util.path.PathSegment;
|
||||
import com.example.fitbot.util.processing.MotionData;
|
||||
import com.example.fitbot.util.processing.MotionProcessor;
|
||||
import com.example.fitbot.util.processing.Vector3;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
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 targetPath, personalPath;
|
||||
private Path referencePath, performingPath;
|
||||
private Paint referencePaint, performingPaint;
|
||||
|
||||
/**
|
||||
* Method that calculates the path that will be drawn on the
|
||||
* canvas. This method will be called every time new motion data is received.
|
||||
* Constants for the preview path projection.
|
||||
*/
|
||||
private void calculateDrawingPath(Vector3 transformedVector, MotionData motionData, int sampleIndex, double sampleRate) {
|
||||
|
||||
}
|
||||
|
||||
private final float FOV = 70.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 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);
|
||||
this.path = path;
|
||||
this.motionProcessor = new MotionProcessor();
|
||||
this.motionProcessor.startListening();
|
||||
this.motionProcessor.setMotionDataEventHandler(this::calculateDrawingPath);
|
||||
this.targetPath = new Path();
|
||||
this.personalPath = new Path();
|
||||
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();
|
||||
|
||||
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(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.
|
||||
*
|
||||
* @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) {
|
||||
this.rotation.set(Math.toRadians(yaw), Math.toRadians(pitch));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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);
|
||||
|
||||
Matrix4f projectionMatrix = new Matrix4f()
|
||||
.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
|
||||
Vector4f screenCoordinates = new Vector4f(point, 1.0f)
|
||||
.mul(MVP);
|
||||
|
||||
// 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;
|
||||
|
||||
return new Vector2f(normalizedX, normalizedY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return The generated path object.
|
||||
*/
|
||||
private Path getDrawablePath(PathSegment... segments) {
|
||||
|
||||
Path calculatedPath = new Path();
|
||||
|
||||
// Starting point
|
||||
Vector2f origin = projectVertex(segments[0].getStart(), getWidth(), getHeight());
|
||||
calculatedPath.moveTo(origin.x, origin.y);
|
||||
|
||||
// Draw the path segments
|
||||
for (PathSegment segment : segments) {
|
||||
Vector2f startProjected = projectVertex(segment.getStart(), getWidth()/2, getHeight());
|
||||
Vector2f endProjected = projectVertex(segment.getEnd(), getWidth()/2, getHeight());
|
||||
calculatedPath.lineTo(startProjected.x, startProjected.y);
|
||||
calculatedPath.lineTo(endProjected.x, endProjected.y);
|
||||
}
|
||||
|
||||
return calculatedPath;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
// Draw the sport preview canvas
|
||||
canvas.drawPath(referencePath, referencePaint);
|
||||
canvas.drawPath(performingPath, performingPaint);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,124 @@
|
||||
package com.example.fitbot.util.path;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class GesturePath {
|
||||
|
||||
// The vectors that make up the path.
|
||||
private final PathSegment[] segments;
|
||||
private double curvature;
|
||||
|
||||
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)
|
||||
{
|
||||
if ( vectors.length < 2)
|
||||
throw new IllegalArgumentException("A path must have at least two points.");
|
||||
|
||||
this.curvature = curvature;
|
||||
this.segments = new PathSegment[vectors.length - 1];
|
||||
for ( int i = 0; i < vectors.length - 1; i++)
|
||||
segments[i] = new PathSegment(vectors[i], vectors[i + 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a GesturePath with provided PathSegments.
|
||||
* @param segments The PathSegments to initialize the path with.
|
||||
*/
|
||||
public GesturePath(PathSegment... segments) {
|
||||
this.segments = segments;
|
||||
this.curvature = 0.0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter method for retrieving the path segments of this GesturePath.
|
||||
*
|
||||
* @return The path segments.
|
||||
*/
|
||||
public PathSegment[] getSegments() {
|
||||
return segments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for retrieving the closest path segment to a reference point.
|
||||
*
|
||||
* @param reference The reference point to find the closest path segment to.
|
||||
* @return The closest path segment to the reference point.
|
||||
*/
|
||||
public PathSegment closest(Vector3f reference) {
|
||||
// If there's only one segment, return that one.
|
||||
if ( segments.length == 1)
|
||||
return segments[0];
|
||||
|
||||
return Arrays
|
||||
.stream(segments)
|
||||
.reduce(segments[0], (a, b) -> PathSegment.closer(a, b, reference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error between an arbitrary path segment and the reference point.
|
||||
*
|
||||
* @param referencePoint The reference point to calculate the error of.
|
||||
* @return The error offset between the path and the reference point.
|
||||
*/
|
||||
public double getError(Vector3f referencePoint) {
|
||||
return closest(referencePoint).difference(referencePoint); // Get the closest segment and calculate the error.
|
||||
}
|
||||
|
||||
// Builder class for the GesturePath object.
|
||||
public static class Builder {
|
||||
|
||||
// List of vectors to add to the GesturePath object.
|
||||
private final List<Vector3f> vectors;
|
||||
|
||||
/**
|
||||
* Constructor for the Builder object.
|
||||
*
|
||||
* @param vectors The list of vectors to add.
|
||||
*/
|
||||
public Builder(List<Vector3f> vectors) {
|
||||
this.vectors = vectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for the Builder object.
|
||||
*/
|
||||
public Builder() {
|
||||
this.vectors = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a vector to the GesturePath object.
|
||||
*
|
||||
* @param vector The vector to add.
|
||||
* @return The Builder object.
|
||||
*/
|
||||
public Builder addVector(Vector3f vector) {
|
||||
vectors.add(vector);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the GesturePath object.
|
||||
*
|
||||
* @return The GesturePath object.
|
||||
*/
|
||||
public GesturePath build() {
|
||||
return new GesturePath(vectors.toArray(new Vector3f[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
package com.example.fitbot.util.path;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public class PathSegment {
|
||||
|
||||
private final Vector3f start, end;
|
||||
private final double distance;
|
||||
|
||||
/**
|
||||
* Constructor for creating a PathSegment of two lines, with the normal vector
|
||||
* pointing straight upwards relative to the line, with a curvature of 0.0.
|
||||
*
|
||||
* @param start The starting point of the line segment
|
||||
* @param end The end point of the line segment.
|
||||
*/
|
||||
public PathSegment(Vector3f start, Vector3f end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.distance = start.distance(end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that interpolates between the start and end points of the path segment,
|
||||
* depending on the curvature of the curve. If the curvature is unset, or set to 0
|
||||
* then this method will use linear interpolation. Otherwise, it will use a curve.
|
||||
*
|
||||
* @param dst The destination vector to interpolate to.
|
||||
* @param t The interpolation value between 0 and 1.
|
||||
*/
|
||||
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)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for calculating the difference between the provided vector and the
|
||||
* path segment, depending on the normal vector and the curvature.
|
||||
* If the provided vector does not lie on the path segment, this method will return
|
||||
* the linear distance to the path.
|
||||
*
|
||||
* @param other The vector to calculate the difference to.
|
||||
* @return The difference between the vector and the path segment.
|
||||
*/
|
||||
public double difference(Vector3f other) {
|
||||
|
||||
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))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the normal vector of the path segment.
|
||||
*
|
||||
* @return The normal vector of the path segment.
|
||||
*/
|
||||
public Vector3f getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the end point of the path segment.
|
||||
*
|
||||
* @return The end point of the path segment.
|
||||
*/
|
||||
public Vector3f getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for returning the distance to the closest point on the path segment.
|
||||
*
|
||||
* @param reference The reference point to calculate the distance to.
|
||||
* @return The distance to the closest point on the path segment.
|
||||
*/
|
||||
public double distance(Vector3f reference) {
|
||||
if ( this.start.distanceSquared(reference) > this.end.distanceSquared(reference))
|
||||
return this.end.distance(reference);
|
||||
return this.start.distance(reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for returning the closest path segment to a reference point.
|
||||
*
|
||||
* @param first The first path segment to compare.
|
||||
* @param second The second path segment to compare.
|
||||
* @param referencePoint The reference point to compare to.
|
||||
* @return The closest path segment to the reference point.
|
||||
*/
|
||||
public static PathSegment closer(PathSegment first, PathSegment second, Vector3f referencePoint) {
|
||||
if (first.distance(referencePoint) < second.distance(referencePoint))
|
||||
return first;
|
||||
return second;
|
||||
}
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
package com.example.fitbot.util.processing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GesturePath {
|
||||
|
||||
// The vectors that make up the path.
|
||||
private final Vector3[] vectors;
|
||||
|
||||
public GesturePath(Vector3[] vectors) {
|
||||
this.vectors = vectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error between an arbitrary path segment and the reference point.
|
||||
*
|
||||
* @param referencePoint The reference point to calculate the error of.
|
||||
* @return The error offset between the path and the reference point.
|
||||
*/
|
||||
public double getError(Vector3 referencePoint) {
|
||||
// If there are no vectors, return 0.
|
||||
if ( vectors.length == 0)
|
||||
return 0;
|
||||
|
||||
// If there's only one vector, return the distance to that vector.
|
||||
if ( vectors.length == 1)
|
||||
return vectors[0].distance(referencePoint);
|
||||
|
||||
double distance = Double.MAX_VALUE;
|
||||
double currentDistSq, nextDistSq;
|
||||
int closestVectorIdx = 0;
|
||||
|
||||
// Acquire two closest points to the reference point.
|
||||
for ( int i = 0; i < vectors.length - 1; i++) {
|
||||
currentDistSq = vectors[i].distanceSq(referencePoint);
|
||||
nextDistSq = vectors[i + 1].distanceSq(referencePoint);
|
||||
|
||||
if ( currentDistSq < distance) {
|
||||
distance = currentDistSq;
|
||||
closestVectorIdx = i;
|
||||
} else if ( nextDistSq < distance) {
|
||||
distance = nextDistSq;
|
||||
closestVectorIdx = i + 1;
|
||||
i++; // Skip the next iteration; this point is already closer.
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the error between the two closest points.
|
||||
Vector3 pointB = (closestVectorIdx == vectors.length - 1) ?
|
||||
vectors[closestVectorIdx - 1] : // If the closest point is the last point, use the 1 to last one
|
||||
(closestVectorIdx > 0 && // Find the closer point between the surrounding points.
|
||||
(vectors[closestVectorIdx - 1].distanceSq(referencePoint) < vectors[closestVectorIdx + 1].distanceSq(referencePoint))) ?
|
||||
vectors[closestVectorIdx - 1] :
|
||||
vectors[closestVectorIdx + 1];
|
||||
|
||||
return referencePoint.distanceToLine(vectors[closestVectorIdx], pointB);
|
||||
}
|
||||
|
||||
// Builder class for the GesturePath object.
|
||||
public static class Builder {
|
||||
|
||||
// List of vectors to add to the GesturePath object.
|
||||
private final List<Vector3> vectors;
|
||||
|
||||
/**
|
||||
* Constructor for the Builder object.
|
||||
*
|
||||
* @param vectors The list of vectors to add.
|
||||
*/
|
||||
public Builder(List<Vector3> vectors) {
|
||||
this.vectors = vectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for the Builder object.
|
||||
*/
|
||||
public Builder() {
|
||||
this.vectors = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a vector to the GesturePath object.
|
||||
*
|
||||
* @param vector The vector to add.
|
||||
* @return The Builder object.
|
||||
*/
|
||||
public Builder addVector(Vector3 vector) {
|
||||
vectors.add(vector);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the GesturePath object.
|
||||
*
|
||||
* @return The GesturePath object.
|
||||
*/
|
||||
public GesturePath build() {
|
||||
return new GesturePath(vectors.toArray(new Vector3[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.example.fitbot.util.processing;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public interface IMotionDataConsumer {
|
||||
|
||||
/**
|
||||
* Function for accepting motion data and the transformed vector.
|
||||
* @param transformedVector The transformed vector.
|
||||
* @param motionData The input motion data.
|
||||
* @param sampleIndex The index of the current sample
|
||||
* @param sampleRate The sample rate.
|
||||
*/
|
||||
void accept(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate);
|
||||
|
||||
}
|
@@ -1,11 +1,13 @@
|
||||
package com.example.fitbot.util.processing;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MotionData {
|
||||
|
||||
// Data of the motion sensor
|
||||
public Vector3 acceleration, rotation;
|
||||
public Vector3f acceleration, rotation;
|
||||
|
||||
// Delimiter for the data received from the motion sensor
|
||||
private static final String DATA_DELIMITER = ";";
|
||||
@@ -20,9 +22,9 @@ public class MotionData {
|
||||
* @param rotationY The rotation in the Y axis in degrees.
|
||||
* @param rotationZ The rotation in the Z axis in degrees.
|
||||
*/
|
||||
public MotionData(double accelerationX, double accelerationY, double accelerationZ, double rotationX, double rotationY, double rotationZ) {
|
||||
this.acceleration = new Vector3(accelerationX, accelerationY, accelerationZ);
|
||||
this.rotation = new Vector3(rotationX, rotationY, rotationZ);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,7 +33,7 @@ public class MotionData {
|
||||
* @param acceleration The acceleration vector in m/s^2.
|
||||
* @param rotation The rotation vector in degrees.
|
||||
*/
|
||||
public MotionData(Vector3 acceleration, Vector3 rotation) {
|
||||
public MotionData(Vector3f acceleration, Vector3f rotation) {
|
||||
this.acceleration = acceleration;
|
||||
this.rotation = rotation;
|
||||
}
|
||||
@@ -52,12 +54,12 @@ public class MotionData {
|
||||
return null;
|
||||
|
||||
return new MotionData(
|
||||
Double.parseDouble(parts[0]),
|
||||
Double.parseDouble(parts[1]),
|
||||
Double.parseDouble(parts[2]),
|
||||
Double.parseDouble(parts[3]),
|
||||
Double.parseDouble(parts[4]),
|
||||
Double.parseDouble(parts[5])
|
||||
Float.parseFloat(parts[0]),
|
||||
Float.parseFloat(parts[1]),
|
||||
Float.parseFloat(parts[2]),
|
||||
Float.parseFloat(parts[3]),
|
||||
Float.parseFloat(parts[4]),
|
||||
Float.parseFloat(parts[5])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -2,10 +2,12 @@ package com.example.fitbot.util.processing;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.example.fitbot.util.path.GesturePath;
|
||||
import com.example.fitbot.util.server.IWebSocketHandler;
|
||||
import com.example.fitbot.util.server.WebSocket;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -16,10 +18,11 @@ public class MotionProcessor {
|
||||
public static final String DELIMITER = ";";
|
||||
|
||||
private final List<MotionData> preprocessedData = new ArrayList<>(); // Preprocessed motion data
|
||||
private final List<Vector3> relativePath = new ArrayList<>(); // Relative path of the motion data
|
||||
private Vector3 ZERO = new Vector3(0, 0, 0);
|
||||
private double sampleRate = 1.0D; // samples/second
|
||||
private DataConsumer motionDataConsumer = (p1, p2, p3, p4) -> {};
|
||||
private final List<Vector3f> relativePath = new ArrayList<>(); // Relative path of the motion data
|
||||
private Vector3f ZERO = new Vector3f(0, 0, 0);
|
||||
|
||||
private float sampleRate = 1.0F; // samples/second
|
||||
private IMotionDataConsumer motionDataConsumer = (p1, p2, p3, p4) -> {};
|
||||
private GesturePath path;
|
||||
private WebSocket socket;
|
||||
|
||||
@@ -77,14 +80,14 @@ public class MotionProcessor {
|
||||
// Otherwise check if it starts with 'calibrate', this is the ZERO point.
|
||||
} else if ( data.startsWith("zero")) { // message to calibrate device
|
||||
String[] vectorData = data.split(" ")[1].split(DELIMITER);
|
||||
ZERO = new Vector3(
|
||||
ZERO = new Vector3f(
|
||||
Float.parseFloat(vectorData[0]),
|
||||
Float.parseFloat(vectorData[1]),
|
||||
Float.parseFloat(vectorData[2])
|
||||
);
|
||||
Log.i("MotionProcessor", "Device calibrated at " + ZERO.toString());
|
||||
} else if ( data.startsWith("sampleRate")) {
|
||||
this.sampleRate = Double.parseDouble(data.split(" ")[1]);
|
||||
this.sampleRate = Float.parseFloat(data.split(" ")[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +107,8 @@ public class MotionProcessor {
|
||||
*/
|
||||
public void addMotionData(MotionData data) {
|
||||
preprocessedData.add(data);
|
||||
Vector3 previous = this.relativePath.isEmpty() ? ZERO : this.relativePath.get(this.relativePath.size() - 1);
|
||||
Vector3 relativeVector = getRelativeVector(data).add(previous);
|
||||
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);
|
||||
}
|
||||
@@ -115,7 +118,7 @@ public class MotionProcessor {
|
||||
*
|
||||
* @param relativePath The new relative path.
|
||||
*/
|
||||
public void setRelativePath(List<Vector3> relativePath) {
|
||||
public void setRelativePath(List<Vector3f> relativePath) {
|
||||
this.relativePath.clear();
|
||||
this.relativePath.addAll(relativePath);
|
||||
}
|
||||
@@ -124,7 +127,7 @@ public class MotionProcessor {
|
||||
* Function for setting the motion data receiver.
|
||||
* @param consumer The consumer to set.
|
||||
*/
|
||||
public void setMotionDataEventHandler(DataConsumer consumer) {
|
||||
public void setMotionDataEventHandler(IMotionDataConsumer consumer) {
|
||||
if ( consumer != null)
|
||||
this.motionDataConsumer = consumer;
|
||||
}
|
||||
@@ -138,15 +141,17 @@ public class MotionProcessor {
|
||||
* @param motionData The motion data to calculate the relative vector for.
|
||||
* @return The relative vector of the motion data.
|
||||
*/
|
||||
public Vector3 getRelativeVector(MotionData motionData) {
|
||||
public Vector3f getRelativeVector(MotionData motionData) {
|
||||
|
||||
// Rotate the acceleration vector back by the rotation vector to make it
|
||||
// perpendicular to the gravity vector, then apply double integration to get the relative position.
|
||||
// s = 1/2 * a * t^2
|
||||
return motionData.acceleration
|
||||
.rotate(motionData.rotation.negate())
|
||||
.divide(2)
|
||||
.multiply(sampleRate * sampleRate);
|
||||
.rotateX(-motionData.rotation.x)
|
||||
.rotateY(-motionData.rotation.y)
|
||||
.rotateZ(-motionData.rotation.z)
|
||||
.div(2)
|
||||
.mul(sampleRate * sampleRate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +190,7 @@ public class MotionProcessor {
|
||||
* @param referencePoint The reference point to compare the motion data to.
|
||||
* @return The error of the motion data compared to the reference path.
|
||||
*/
|
||||
public double getError(GesturePath path, Vector3 referencePoint)
|
||||
public double getError(GesturePath path, Vector3f referencePoint)
|
||||
{
|
||||
return path.getError(referencePoint);
|
||||
}
|
||||
@@ -197,7 +202,7 @@ public class MotionProcessor {
|
||||
* @param referencePoint The reference point to compare the path data to.
|
||||
* @return The error of the motion data compared to the reference path.
|
||||
*/
|
||||
public double getError(Vector3 referencePoint) {
|
||||
public double getError(Vector3f referencePoint) {
|
||||
if ( path == null)
|
||||
return 0;
|
||||
return path.getError(referencePoint);
|
||||
@@ -240,19 +245,5 @@ public class MotionProcessor {
|
||||
Log.i("MotionProcessor", "Path length: " + relativePath.size());
|
||||
Log.i("MotionProcessor", "Sample rate: " + sampleRate);
|
||||
Log.i("MotionProcessor", "Calibration point: " + ZERO.toString());
|
||||
|
||||
/**
|
||||
* Interface that accepts motion data and the transformed vector.
|
||||
*/
|
||||
public interface DataConsumer {
|
||||
|
||||
/**
|
||||
* Function for accepting motion data and the transformed vector.
|
||||
* @param transformedVector The transformed vector.
|
||||
* @param motionData The input motion data.
|
||||
* @param sampleIndex The index of the current sample
|
||||
* @param sampleRate The sample rate.
|
||||
*/
|
||||
void accept(Vector3 transformedVector, MotionData motionData, int sampleIndex, double sampleRate);
|
||||
}
|
||||
}
|
||||
|
@@ -1,258 +0,0 @@
|
||||
package com.example.fitbot.util.processing;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class Vector3 {
|
||||
|
||||
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 Vector3(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 Vector3 copy() {
|
||||
return new Vector3(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the zero vector.
|
||||
*
|
||||
* @return The zero vector.
|
||||
*/
|
||||
public static Vector3 zero() {
|
||||
return new Vector3(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 Vector3 normalize() {
|
||||
double mag = this.magnitude();
|
||||
if (mag == 0) throw new IllegalArgumentException("Cannot normalize the zero vector.");
|
||||
return new Vector3(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 Vector3 subtract(Vector3 other) {
|
||||
return new Vector3(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 Vector3 add(Vector3 other) {
|
||||
return new Vector3(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 Vector3 multiply(double scalar) {
|
||||
return new Vector3(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 Vector3 divide(double scalar) {
|
||||
if (scalar == 0) throw new IllegalArgumentException("Cannot divide by zero.");
|
||||
return new Vector3(this.x / scalar, this.y / scalar, this.z / scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the vector.
|
||||
*
|
||||
* @return The negated vector.
|
||||
*/
|
||||
public Vector3 negate() {
|
||||
return new Vector3(-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 Vector3 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 Vector3(newX, newY, newZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the vector around the X, Y, and Z axes.
|
||||
*
|
||||
* @param rotation The rotation vector.
|
||||
* @return The rotated vector.
|
||||
*/
|
||||
public Vector3 rotate(Vector3 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 Vector3 rotateX(double angle) {
|
||||
double sinTheta = Math.sin(angle);
|
||||
double cosTheta = Math.cos(angle);
|
||||
return new Vector3(
|
||||
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 Vector3 rotateY(double angle) {
|
||||
double sinTheta = Math.sin(angle);
|
||||
double cosTheta = Math.cos(angle);
|
||||
return new Vector3(
|
||||
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 Vector3 rotateZ(double angle) {
|
||||
double sinTheta = Math.sin(angle);
|
||||
double cosTheta = Math.cos(angle);
|
||||
return new Vector3(
|
||||
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(Vector3 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(Vector3 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(Vector3 lineStart, Vector3 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 Vector3(
|
||||
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 Vector3 closest(Vector3 ... vectors) {
|
||||
return Arrays.stream(vectors).min(Comparator.comparingDouble(this::distanceSq)).orElse(null);
|
||||
}
|
||||
|
||||
public Vector3 map(VectorMapFunction function) {
|
||||
return function.apply(this);
|
||||
}
|
||||
|
||||
public interface VectorMapFunction {
|
||||
Vector3 apply(Vector3 vector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Vector3(" + this.x + ", " + this.y + ", " + this.z + ")";
|
||||
}
|
||||
}
|
10
code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml
Normal file
10
code/src/Fitbot/app/src/main/res/layout/activity_fitness.xml
Normal 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>
|
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
BIN
docs/documentation/assets/motion-path-example-path-error.png
Normal file
BIN
docs/documentation/assets/motion-path-example-path-error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
BIN
docs/documentation/assets/motion-path-example-vertices.png
Normal file
BIN
docs/documentation/assets/motion-path-example-vertices.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 863 B |
@@ -12,7 +12,7 @@ and where they've placed the tracking devices.
|
||||
|
||||
A path can look like the following
|
||||
|
||||
<img height="128" src="../assets/motion-path-example-vertices.png" width="128"/>
|
||||
<img height="128" src="../assets/motion-path-example-vertices.png" width="128" alt="Path Point Example"/>
|
||||
|
||||
To be able to measure the position of our tracking device, we'll have to use sensors that allow us
|
||||
to retrieve useful information that can provide us with either position or velocity. The device will have
|
||||
@@ -45,4 +45,6 @@ Second, to convert our relative acceleration rotation to a useful position, we'l
|
||||
acceleration vector `A(x, y, z)` and rotation vector `R(x, y, z)` to an acceleration vector that is
|
||||
perpendicular to the normal vector of the earth. This is because the acceleration vector of the device
|
||||
is relative to its own axes, and not to the earth's normal vector.
|
||||
To convert this, we'll have to multiply the acceleration vector `A(x, y, z)` by the rotation matrix
|
||||
To convert this, we'll have to multiply the acceleration vector `A(x, y, z)` by the rotation matrix
|
||||
with negative angles, to rotate it back to be perpendicular with the normal of the earth.
|
||||
After this transformation
|
@@ -55,7 +55,8 @@ The software of the system will consist of the following:
|
||||
|
||||
The Wii Fit Board will be connected to Pepper using the Wiiboard-simple library. The library will be used to read the sensor data from the Wii Fit Board and transfer it to Pepper. The position tracking algorithm will process the sensor data and determine the user's position.
|
||||
|
||||
Challenge:
|
||||
Challenge:
|
||||
- Connecting to the wii fit board. It is not possible to connect directly to the Wii Fit Board, it is necessary to use a library that can interpret the data sent by the Wii Fit Board.
|
||||
- The Wii Fit Balance Board sends data in a specific format. To interpret this data, it's necessary to understand the format and how to convert it to a usable format.
|
||||
- The Wii Fit Balance Board uses Bluetooth 2.0 to communicate. Pepper uses Bluetooth 4.0 this means that there might be compatibility issues/latancy issues.
|
||||
|
||||
@@ -79,6 +80,9 @@ To be added
|
||||
## References
|
||||
|
||||
[Wiiboard lib](https://code.google.com/archive/p/wiiboard-simple/wikis/Documentation.wiki)
|
||||
https://advanti-lab.sb.dfki.de/?page_id=64
|
||||
https://github.com/paulburton/fitscales
|
||||
https://github.com/micromu/WiiRemoteJ
|
||||
|
||||
## Appendices
|
||||
|
||||
|
@@ -44,6 +44,13 @@ om deze toe te passen om te helpen met het eenzaamheidsprobleem bij ouderen.
|
||||
|
||||
### Op welke manier kunnen we kunstmatige intelligentie inzetten om eenzaamheid onder ouderen te bestrijden?
|
||||
|
||||
Zoals al eerder was vermeld worden robots al langer gebruikt bij het helpen van ouderen met huishoudelijke taken die voor hen te zwaar zijn.
|
||||
Daarom valt het idee ook te overwegen om robots in te zetten om ouderen te helpen met het bestrijden van eenzaamheid. Hiervoor kan er
|
||||
gebruik gemaakt worden van kunstmatige intelligentie. Kunstmatige intelligentie kan gebruikt worden om de robot te leren hoe het om moet gaan met
|
||||
de gebruiker, om zowel te horen wat de gebruiker zegt, inhoudelijke reacties te geven op de gebruiker of om de gebruiker te helpen met bepaalde taken als ernaar
|
||||
gevraagd wordt. Dit kan ervoor zorgen dat de ouderen zich minder eenzaam voelen, en dat ze zich meer op hun gemak voelen in hun eigen huis.
|
||||
|
||||
|
||||
### Hoe kunnen we ervoor zorgen dat dit gedaan kan worden zonder de privacy van ouderen te schenden?
|
||||
|
||||
|
||||
|
@@ -80,6 +80,6 @@ Wat moet er beter? Wat ging er goed? Welke SMART leerdoelen hebben jullie voor d
|
||||
|
||||
We zijn samen gaan zitten voor de retrospective, hier uit is het volgende voort gekomen (we hebben gebruik gemaakt van the 4 L's):
|
||||
|
||||

|
||||

|
||||
|
||||
De leerdoelen zet iedereen in zijn eigen scorion formulier.
|
Reference in New Issue
Block a user