Как повернуть вершину вокруг определенной точки?
Представьте, что у вас есть две точки в 2d-пространстве, и вам нужно повернуть одну из этих точек на X градусов, а другая точка действует как центр.
float distX = Math.abs( centerX -point2X );
float distY = Math.abs( centerY -point2Y );
float dist = FloatMath.sqrt( distX*distX + distY*distY );
До сих пор мне просто приходилось находить расстояние между двумя точками... любые идеи, откуда я должен идти от этого?
![enter image description here]()
Ответы
Ответ 1
Самый простой способ - составить три преобразования:
- Перевод, переводящий точку 1 в начало
- Вращение вокруг начала координат на требуемый угол
- Перевод, который возвращает точку 1 в исходное положение
Когда вы все закончите, вы получите следующее преобразование:
newX = centerX + (point2x-centerX)*Math.cos(x) - (point2y-centerY)*Math.sin(x);
newY = centerY + (point2x-centerX)*Math.sin(x) + (point2y-centerY)*Math.cos(x);
Заметим, что это делает предположение, что угол x
отрицателен для вращения по часовой стрелке (так называемая стандартная или правая ориентация для системы координат). Если это не так, тогда вам нужно будет поменять знак на терминах с sin(x)
.
Ответ 2
Вам нужна 2-тактная матрица вращения http://en.wikipedia.org/wiki/Rotation_matrix
Ваша новая точка будет
newX = centerX + ( cosX * (point2X-centerX) + sinX * (point2Y -centerY))
newY = centerY + ( -sinX * (point2X-centerX) + cosX * (point2Y -centerY))
потому что вы вращаетесь по часовой стрелке, а не против часовой стрелки
Ответ 3
Предполагая, что вы используете API-интерфейс Java Graphics2D, попробуйте этот код -
Point2D result = new Point2D.Double();
AffineTransform rotation = new AffineTransform();
double angleInRadians = (angle * Math.PI / 180);
rotation.rotate(angleInRadians, pivot.getX(), pivot.getY());
rotation.transform(point, result);
return result;
где точка поворота - это точка, вокруг которой вы вращаетесь.
Ответ 4
Ответ 5
Вот способ поворота любой точки вокруг любой другой точки в 2D. Обратите внимание, что в 3D это можно использовать как вращение вокруг оси z, z-координату принимаемой точки, так как она не изменяется. Вращение вокруг оси X и оси Y в 3D также может быть легко реализовано.
Код находится в JavaScript. Пронумерованные строки в начале представляют собой набор тестов для функции. Они также служат примером использования.
//A = new Array(0,0)
//S = new Array(-1,0)
//fi = 90
//alert("rotujBod: " + rotatePoint(A, S, fi))
function rotatePoint(A, S, fi) {
/** IN points A - rotated point, S - centre, fi - angle of rotation (rad)
* points in format [Ax, Ay, Az], angle fi (float)
* OUT point B
*/
r = Math.sqrt((A[0] - S[0])*(A[0] - S[0]) + (A[1] - S[1])*(A[1] - S[1]))
originOfRotation = new Array(S[0] + r, S[1])
if (A[1] < S[1]) {
A2 = new Array(A[0], -1*A[1])
originalAngle = -1*sizeOfAngle(originOfRotation, S, A2)
} else {
originalAngle = sizeOfAngle(originOfRotation, S, A)
}
x = S[0] + r*Math.cos(fi + originalAngle)
y = S[1] + r*Math.sin(fi + originalAngle)
B = new Array(x, y)
return(B)
}
function sizeOfAngle(A, S, B) {
ux = A[0] - S[0]
uy = A[1] - S[1]
vx = B[0] - S[0]
vy = B[1] - S[1]
if((Math.sqrt(ux*ux + uy*uy)*Math.sqrt(vx*vx + vy*vy)) == 0) {return 0}
return Math.acos((ux*vx + uy*vy)/(Math.sqrt(ux*ux + uy*uy)*Math.sqrt(vx*vx + vy*vy)))
}
Ответ 6
Здесь версия, которая заботится о направлении вращения. Правый (по часовой стрелке) отрицательный, а левый (против часовой стрелки) положительный. Вы можете отправить точку или 2-й вектор и установить его примитивы в этом методе (последняя строка), чтобы избежать распределения памяти для производительности. Возможно, вам придется заменить vector2 и mathutils на библиотеки, которые вы используете, или на встроенный класс java, и вы можете использовать math.toradians() вместо mathutils.
/**
* rotates the point around a center and returns the new point
* @param cx x coordinate of the center
* @param cy y coordinate of the center
* @param angle in degrees (sign determines the direction + is counter-clockwise - is clockwise)
* @param px x coordinate of point to rotate
* @param py y coordinate of point to rotate
* */
public static Vector2 rotate_point(float cx,float cy,float angle,float px,float py){
float absangl=Math.abs(angle);
float s = MathUtils.sin(absangl * MathUtils.degreesToRadians);
float c = MathUtils.cos(absangl * MathUtils.degreesToRadians);
// translate point back to origin:
px -= cx;
py -= cy;
// rotate point
float xnew;
float ynew;
if (angle > 0) {
xnew = px * c - py * s;
ynew = px * s + py * c;
}
else {
xnew = px * c + py * s;
ynew = -px * s + py * c;
}
// translate point back:
px = xnew + cx;
py = ynew + cy;
return new Vector2(px, py);
}
Обратите внимание, что этот способ имеет большую производительность, чем тот, который вы пытались использовать в своем сообщении. Потому что вы используете sqrt, который является очень дорогостоящим и таким образом конвертирует из градусов в радианы, управляемый с помощью таблицы поиска, если вы задаетесь вопросом. И поэтому он имеет очень высокую производительность.