Цель Терапия заключается в том, чтобы заставить пациента выровнять два датчика. Для начала они принимают «позу», которая по сути обнуляет все. Пациент вытягивает руку перед собой и старается держать ее как можно ближе ко лбу и удерживать в течение 3 секунд. В течение этого периода ось X датчика 1 и ось Z датчика 2 должны находиться на одной линии.
В чем мне нужна помощь: Я пытаюсь использовать круги на экране, чтобы визуализировать расстояние между датчиками, но я не уверен, с какой способностью я смогу проецировать кватернионы в двумерное пространство. Я решил, что, поскольку меня действительно интересует вращение только двух из трех осей вращения каждого датчика (Z и Y в датчике 1 и X и Y в датчике 2), это можно сделать, используя следующий метод:
Моя идея: Я хочу иметь два круга: больший, который всегда остается в центре экрана и представляет цель для пациента, и меньший, который перемещается в зависимости от углового расстояния между двумя датчиками. Скажем, например, датчик 1 совершил поворот на 45 градусов по часовой стрелке по оси Z, а затем еще на 30 градусов вверх по оси Y. Я хочу, чтобы меньший круг переместился вправо, а затем немного вверх на экране. чтобы представить разницу между кватернионами двух датчиков. Затем, предположим, пациент повернул голову в противоположном направлении, поэтому он повернул датчик 2 вокруг оси X еще на 20 градусов. На экране это будет отображаться в виде перемещения меньшего размера вправо, даже если датчик 1 не будет двигаться. **При необходимости я могу подробнее рассказать об этом.
Текущие реализации: Я сотрудничаю с ChatGPT, чтобы решить эту проблему (потому что я все еще немного разбираюсь в этом вопросе). новичок в кватернионах), и это неудивительно, что ChatGPT тоже с трудом работает с кватернионами, но, тем не менее, это то, что у меня пока есть.
- Определение расстояния – Чтобы определить расстояние, я объединяю кватернионы положения датчиков, используя относительное вращение, а затем делаю то же самое и для текущих кватернионов.
Код: Выделить всё
public Quaternion findRelativeRotation(Quaternion q1, Quaternion q2) {
Quaternion q1Conjugate = conjugateQuat(q1);
return multiplyQuat(q1Conjugate, q2);
}
Код: Выделить всё
public float quaternionDistance(Quaternion q1, Quaternion q2) {
float dotProduct = q1.w() * q2.w() + q1.x() * q2.x() + q1.y() * q2.y() + q1.z() * q2.z();
if (dotProduct > .999 && dotProduct < 1.001) return 0;
return (float) (Math.acos(2 * dotProduct * dotProduct - 1) * (180 / 3.14159));
}
- Класс SensorView – ChatGPT рекомендовал создать приведенный ниже класс SensorView, который используется для создания отображаемых точек:
Код: Выделить всё
public class SensorView extends View {
private Paint paint;
private PointF point;
public SensorView(Context context) {
super(context);
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle((Paint.Style.FILL));
}
public void updateOrientation(Quaternion quaternion) {
point = QuaternionTo2D.quaternionTo2DPoint(quaternion);
invalidate();
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (point != null) {
canvas.drawCircle(getWidth() / 2 + point.x, getHeight() / 2 + point.y, 10, paint);
}
}
}
- Функция QuaternionTo2D. Здесь я как бы теряю понимание того, что пытается сделать ChatGPT. Он предоставил мне эту функцию, которая включает математические вычисления для определения координат, но поскольку она предназначена для ChatGPT, я не могу быть уверен, что вычисления верны.
Код: Выделить всё
private PointF quaternionTo2D(Quaternion q) {
float angleX = (float) Math.atan2(2.0f * (q.w() * q.x() + q.y() * q.z()), 1.0f - 2.0f * (q.x() * q.x() + q.y() * q.y()));
float angleY = (float) Math.asin(2.0f * (q.w() * q.y() - q.z() * q.x()));
// Mapping angles to screen coordinates
float x = (float) Math.sin(angleX);
float y = (float) Math.sin(angleY);
Log.i("QuaternionTo2D", "Quaternion: " + q + " -> PointF: x=" + x + ", y=" + y);
return new PointF(x, y);
}
- Полное использование –
Код: Выделить всё
circleGoalWithNotch.post(() -> {
initialX = circleGoalWithNotch.getX() + circleGoalWithNotch.getWidth() / 2 - circleUserWithNotch.getWidth() / 2;
initialY = circleGoalWithNotch.getY() + circleGoalWithNotch.getHeight() / 2 - circleUserWithNotch.getHeight() / 2;
circleUserWithNotch.setX(initialX);
circleUserWithNotch.setY(initialY);
});
Код: Выделить всё
private void updateCirclePosition(Quaternion s1Quaternion, Quaternion s2Quaternion) {
executorService.execute(() -> {
PointF point = quaternionTo2D(findRelativeRotation(s1Quaternion, s2Quaternion));
uiHandler.post(() -> {
float scaledX = point.x * SCALING_FACTOR;
float scaledY = point.y * SCALING_FACTOR;
float newX = initialX + scaledX;
float newY = initialY + scaledY;
newX = Math.max(0, Math.min(newX, view.getWidth() - circleUserWithNotch.getWidth()));
newY = Math.max(0, Math.min(newY, view.getHeight() - circleUserWithNotch.getHeight()));
circleUserWithNotch.setX(newX);
circleUserWithNotch.setY(newY);
Log.i("TherapyMainFragment", "Updated User Circle Position: X - " + newX + " Y - " + newY);
});
});
}
Результаты: Для моего Сюрприз, это было не совсем бесполезно. Меньший круг по большей части перемещался относительно той ориентации, в которой я его задавал; однако его определенно можно было бы улучшить, и иногда маленький круг полностью исчезал на несколько секунд, а затем возвращался. Основная проблема заключалась в том, что если бы я расположил датчики так, как они должны быть, а затем не переместил бы их, меньший круг и больший круг не совпали бы, хотя их ориентация была идентична той, которой они должны быть. Наверное, это главное, что мне нужно выяснить.
Надеюсь, эта информация окажется полезной. Если вам нужны какие-либо разъяснения по чему-либо, я буду рад добавить дополнительную информацию или поделиться своим кодом.
TLDR Мне нужно сравнение двух кватернионов. чтобы их различия отображались в пространстве между двумя кругами на экране.
Подробнее здесь: https://stackoverflow.com/questions/786 ... dimensions