web-dev-qa-db-fra.com

Comment faire pivoter un sommet autour d'un certain point?

Imaginez que vous avez deux points dans l'espace 2d et que vous devez faire pivoter l'un de ces points de X degrés, l'autre point jouant le rôle de centre.

float distX = Math.abs( centerX -point2X );
float distY = Math.abs( centerY -point2Y );

float dist = FloatMath.sqrt( distX*distX + distY*distY );

Jusqu'ici, je viens juste de trouver la distance entre les deux points ... des idées où dois-je aller à partir de cela?

enter image description here

51
Roger Travis

La méthode la plus simple consiste à composer trois transformations:

  1. Une traduction qui amène le point 1 à l'origine
  2. Rotation autour de l'origine par l'angle requis
  3. Une traduction qui ramène le point 1 à sa position initiale

Lorsque vous travaillez tout cela, vous vous retrouvez avec la transformation suivante:

newX = centerX + (point2x-centerX)*Math.cos(x) - (point2y-centerY)*Math.sin(x);

newY = centerY + (point2x-centerX)*Math.sin(x) + (point2y-centerY)*Math.cos(x);

Notez que cela suppose que l'angle x est négatif pour la rotation dans le sens des aiguilles d'une montre (l'orientation dite standard ou l'orientation droite pour le système de coordonnées). Si ce n'est pas le cas, vous devrez inverser le signe sur les termes impliquant sin(x).

58
Ted Hopp

Vous avez besoin d'une matrice de rotation 2D http://en.wikipedia.org/wiki/Rotation_matrix

Votre nouveau point sera 

 newX = centerX + ( cosX * (point2X-centerX) + sinX * (point2Y -centerY))
 newY = centerY + ( -sinX * (point2X-centerX) + cosX * (point2Y -centerY))

parce que vous tournez dans le sens des aiguilles d'une montre plutôt que dans le sens contraire des aiguilles d'une montre

18
mathematician1975

En supposant que vous utilisez l'API Java Graphics2D, essayez ce code -

    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;

où pivot est le point autour duquel vous faites la rotation.

8
Slavcho
  1. Traduire "1" en 0,0

  2. Tourner

    x = sin (angle) * r; y = cos (angle) * r;

  3. Le traduire

2
Tutankhamen

Voici un moyen de faire pivoter n'importe quel point en 2D. Notez qu'en 3D, cela peut être utilisé comme rotation autour de l'axe z, coordonnée z d'un point en cours d'ingénierie puisqu'il ne change pas. La rotation en 3D autour des axes x et y peut également être mise en œuvre facilement.

Le code est en JavaScript. Les lignes commentées au début constituent un ensemble de test pour la fonction. Ils servent également d'exemple d'utilisation.

//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)))
}
0
Jan Kokes

Voici une version qui tient compte du sens de rotation. Right (sens des aiguilles d'une montre) est négatif et gauche (sens des aiguilles d'une montre) est positif. Vous pouvez envoyer un point ou un vecteur 2D et définir ses primitives dans cette méthode (dernière ligne) afin d'éviter toute allocation de mémoire pour les performances. Vous devrez peut-être remplacer vector2 et mathutils par les bibliothèques que vous utilisez ou par la classe de points intégrée de Java. Vous pouvez également utiliser math.toradians () au lieu de 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);
}

Notez que cette façon a plus de performances que la façon dont vous avez essayé dans votre post. Parce que vous utilisez un sqrt qui est très coûteux et que vous convertissez ainsi des degrés en radians gérés avec une table de correspondance, si vous vous le demandez. Et donc, il a de très hautes performances.

0
ömer.bozkurt