Собственно, весь вопрос поставлен в заголовке. Однако, при вращении обнаружены некоторые баги. Для начала алгоритм вращения:
Вращаю я Pane. Но, это совсем не важно. Артефакты я отобразил на видео ниже. Как видно, при большом радиусе между центром и положением мыши всё хорошо, но чем меньше радиус - тем больше вылезает артефактов. Как побороть? Спасибо.
youtube.com
Как видно, в первом случае вращение отрабатывает правильно, во - втором случае на 270 - 360 градусах происходит убыстрение вращения, а в - третьем случае вращение доходит лишь до ~230 градусов. И напоследок - код:
private double oldX;
private double oldY;
private double a = 0;
// ........
setOnMousePressed(e -> {
if(e.getButton() == MouseButton.SECONDARY){
Bounds bbox = localToScene(getBoundsInParent());
centerX = (bbox.getMinX() + bbox.getWidth()) / 2;
centerY = (bbox.getMinY() + bbox.getHeight()) / 2;
oldX = e.getSceneX();
oldY = e.getSceneY();
}
});
setOnMouseDragged(e -> {
if(e.getButton() == MouseButton.SECONDARY){
double _x = e.getSceneX();
double _y = e.getSceneY();
// получаем угол между векторами
Vector2 v1 = new Vector2(oldX - centerX, oldY - centerY);
Vector2 v2 = new Vector2(_x - centerX, _y - centerY);
double angle = v1.degreeAngleForVectors((v2));
// получаем направление поворота
Vector2 v3 = new Vector2(_x - oldX, _y - oldY);
double z = v1.cross(v3);
// меняем градусы в зависимости от направления поворота
angle = z >= 0 ? angle : -angle;
oldX = _x;
oldY = _y;
a += angle;
// поворачиваем контрол
setRotate(a);
}
});
Класс вектор:
public class Vector2 extends Vector {
public Vector2(double x, double y){
super(x, y);
}
public Vector2(double x1, double x2, double y1, double y2){
super(x2-x1, y2-y1);
}
@Override
public double scalar(Vector v) {
return x * v.x + y * v.y;
}
@Override
public double length() {
return Math.abs(Math.sqrt((x * x) + (y * y)));
}
@Override
public double degreeAngleForVectors(Vector v) {
double scalar = scalar(v);
double length = length() * v.length();
double result = scalar / length;
return (Math.acos(result) * 180.) / Math.PI;
}
@Override
public double cross(Vector v) {
return x*v.y - v.x * y;
}
}
UPD1: Сделал способом, который посоветовал Serhii Dikobrazko:
public class TestControl extends Pane {
private double a;
private double centerX;
private double centerY;
private double angleStart;
private double angleStartPane;
public TestControl(){
super();
a = 0;
angleStart = 0;
// events
setOnMousePressed(e -> {
if(e.getButton() == MouseButton.SECONDARY){
Bounds bbox = localToScene(getBoundsInParent());
centerX = (bbox.getMinX() + bbox.getWidth()) / 2;
centerY = (bbox.getMinY() + bbox.getHeight()) / 2;
oldX = e.getSceneX();
oldY = e.getSceneY();
angleStart = Math.atan((oldY - centerY) / (oldX - centerX));
angleStartPane = getRotate();
}
});
setOnMouseDragged(e -> {
if(e.getButton() == MouseButton.SECONDARY){
double _x = e.getSceneX();
double _y = e.getSceneY();
double angleCurrent = Math.atan((_y - centerY) / (_x - centerX));
double angleFinal = angleCurrent - angleStart + angleStartPane;
a += angleFinal;
System.out.println(a);
setRotate(a);
}
});
}
}
Результат: youtube.com Как видно, при вращении по часовой вновь ошибки. когда завершается поворот(почти полные 360), а в обратную сторону проблемы ещё более серьёзные. P.S.: JavaFX угол не запоминает, поэтому я его "накапливаю" в поле a.
UPD 2: youtube.com Результат сильно похож на изначальную проблему, если не полностью её повторяет.
Вариант без векторов. Ошибку искать трудно Готовое решение не дам, но алгоритм покажу
Point center; // координаты центра панели в родительском узле
Point cursor; // координаты курсора в родительском узле
Теперь когда правой кнопкой мыши зажимаем и тянем, срабатывает наше событие для поворота.
При первом вызове необходимо запомнить угол наклона отрезка от центра панели, до курсора. Найти угол по двум точкам просто. Не помню точно, вроде бы (x1 - x2)/(y1 - y2). И еще угол поворота самой панели
float cursorStartAngle; // стартовый
float paneStartAngle = pane.getRotate();
Он понадобится чтобы потом сделать смещение. Это как бы стартовое значение угла
Теперь при каждом следующем перемещении нужно считать этот же угол и записывать его в другую переменную
float cursorAngle; // угол по направлению к курсору
А теперь панель нужно повернуть на разницу между углом что есть сейчас и углом, что был изначально при срабатывании события драга правой кнопкой мыши float rotateAngle = cursorAngle - cursorStartAngle; Я не знаю как в javaFx поворот работает, но если он не плюсуется, то при каждом присвоении будет сбрасываться в ноль
float rotateAngle = cursorAngle - cursorStartAngle + paneStartAngle;
И уже его присвоить нужной панели.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Есть ли такая утилита как man в Линуксе, чтобы можно было читать мануал по классам(например Thread)
Такая ситуация: существует условный метод play(), в котором помимо основного кода создаётся объект с помощью ссылочной переменнойВопрос заключается...
Пожалуйста, опишите, для чего нужен метод setPaint() класса Graphics2d и какие он использует аргументы
Есть задачка, довольно простая, я думаюРешение пришло сразу же: Мы ищем максимальный из дней (d-итых), и выводим какой это день недели