Comment calculer les positions / marques de coin d'un rectangle tourné / incliné?

17

J'ai deux éléments, un point 2D et une zone rectangulaire. Le point représente le milieu de cette zone. Je connais également la largeur et la hauteur de cette zone. Et la zone est inclinée de 40 ° par rapport à la grille.

Maintenant, je voudrais calculer les positions absolues de chaque marque de coin de cette zone inclinée en utilisant uniquement ces données. Est-ce possible?

Stacky
la source

Réponses:

30
X = x*cos(θ) - y*sin(θ)
Y = x*sin(θ) + y*cos(θ)

Cela vous donnera l'emplacement d'un point tourné de θ degrés autour de l'origine. Étant donné que les coins du carré tournent autour du centre du carré et non de l'origine, quelques étapes doivent être ajoutées pour pouvoir utiliser cette formule. Vous devez d'abord définir le point par rapport à l'origine. Ensuite, vous pouvez utiliser la formule de rotation. Après la rotation, vous devez le reculer par rapport au centre du carré.

// cx, cy - center of square coordinates
// x, y - coordinates of a corner point of the square
// theta is the angle of rotation

// translate point to origin
float tempX = x - cx;
float tempY = y - cy;

// now apply rotation
float rotatedX = tempX*cos(theta) - tempY*sin(theta);
float rotatedY = tempX*sin(theta) + tempY*cos(theta);

// translate back
x = rotatedX + cx;
y = rotatedY + cy;

Appliquez ceci aux 4 coins et vous avez terminé!

Aholio
la source
4

C'est une technique courante de faire pivoter un point autour d'un pivot en se traduisant par un système de coordonnées où le pivot est l'origine, puis en tournant autour de cette origine, puis en se traduisant par les coordonnées du monde. (Une très bonne explication de cette approche est disponible à la Khan Academy )

Cependant, vous ne stockez pas vos coins rectangulaires en coordonnées mondiales, nous pouvons donc adapter une approche en fonction des données dont vous disposez.

Cx, Cy // the coordinates of your center point in world coordinates
W      // the width of your rectangle
H      // the height of your rectangle
θ      // the angle you wish to rotate

//The offset of a corner in local coordinates (i.e. relative to the pivot point)
//(which corner will depend on the coordinate reference system used in your environment)
Ox = W / 2
Oy = H / 2

//The rotated position of this corner in world coordinates    
Rx = Cx + (Ox  * cos(θ)) - (Oy * sin(θ))
Ry = Cy + (Ox  * sin(θ)) + (Oy * cos(θ))

Cette approche peut ensuite être facilement appliquée aux trois autres coins.

Kelly Thomas
la source
2

Sur la base des autres réponses, et pour les compléter, j'ai réussi à créer un exemple avec P5 ici .

Voici le code, au cas où vous souhaiteriez y accéder directement:

function setup() {
createCanvas(400, 400);
}

var count = 0;

function draw() {
  background(250);
  rectMode(CENTER);
  stroke(0,0,255);
  fill(0,0,255);
  count += 1;

  var box1X = 100;
  var box1Y = 100;
  var box2X = 160;
  var box2Y = 100;
  var box1R = count;
  var box2R = -60-count;
  var box1W = 50;
  var box1H = 50;
  var box2W = 50;
  var box2H = 50;

  translate(box1X, box1Y);
  rotate(radians(box1R));
  rect(0, 0, box1W, box1H);
  rotate(radians(-box1R));
  translate(-box1X, -box1Y);

  translate(box2X, box2Y);
  rotate(radians(box2R));
  rect(0, 0, box2W, box2H);
  rotate(radians(-box2R));
  translate(-box2X, -box2Y);

  stroke(255,0,0);
  fill(255,0,0);

  var pointRotated = [];
  pointRotated.push(GetPointRotated(box1X, box1Y, box1R, -box1W/2, box1H/2));  // Dot1
  pointRotated.push(GetPointRotated(box1X, box1Y, box1R, box1W/2, box1H/2));   // Dot2
  pointRotated.push(GetPointRotated(box1X, box1Y, box1R, -box1W/2, -box1H/2)); // Dot3
  pointRotated.push(GetPointRotated(box1X, box1Y, box1R, box1W/2, -box1H/2));  // Dot4
  pointRotated.push(createVector(box1X, box1Y)); // Dot5

  for (var i=0;i<pointRotated.length;i++){
ellipse(pointRotated[i].x,pointRotated[i].y,3,3);
  }
}

function GetPointRotated(X, Y, R, Xos, Yos){
// Xos, Yos // the coordinates of your center point of rect
// R      // the angle you wish to rotate

//The rotated position of this corner in world coordinates    
var rotatedX = X + (Xos  * cos(radians(R))) - (Yos * sin(radians(R)))
var rotatedY = Y + (Xos  * sin(radians(R))) + (Yos * cos(radians(R)))

return createVector(rotatedX, rotatedY)
}
<script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.3.3/p5.min.js"></script>

Danfus
la source
1

La refactorisation du code ci-dessus donne un formulaire nettoyé qui met également en évidence le simple fait que chaque coin est fondamentalement center + height/2 + width/2, avec des signes appropriés pour chaque coin. Cela vaut également si vous traitez height/2et width/2comme des vecteurs en rotation.

Faire confiance à l'interprète pour aligner les assistants, cela devrait être assez efficace, si nous essayons de comparer cela.

function addPoints(p1, p2) {
    return { x: p1.x + p2.x, y: p1.y + p2.y }
}

function subPoints(p1, p2 ) {
    return { x: p1.x - p2.x, y: p1.y - p2.y }
}

function multPoints(p1, p2 ) {
    return { x: p1.x * p2.x, y: p1.y * p2.y }
}

function getRulerCorners() {
    const sin = Math.sin(ruler.angle);
    const cos = Math.cos(ruler.angle);
    const height = { x: sin * ruler.height/2, y: cos * ruler.height/2 };
    const heightUp = addPoints(ruler, multPoints({x: 1, y :-1}, height));
    const heightDown = addPoints(ruler, multPoints({x: -1, y: 1}, height));
    const width = { x: cos * ruler.width/2, y: sin * ruler.width/2 };
    ruler.nw = subPoints(heightUp, width);
    ruler.ne = addPoints(heightUp, width );
    ruler.sw = subPoints(heightDown, width);
    ruler.se = addPoints(heightDown, width);
}
leamas
la source
0

Voir l'article Wikipedia sur la rotation . L'essence est la suivante:

(1) Si c est le point central, les coins sont c + ( L / 2, W / 2), +/- etc., où L et W sont la longueur et la largeur du rectangle.

(2) Traduisez le rectangle de sorte que le centre c soit à l'origine, en soustrayant c des quatre coins.

(3) Faites pivoter le rectangle de 40 degrés via les formules trigonométriques citées.

(4) Reculez en ajoutant c à chaque coordonnée.

Joseph O'Rourke
la source
Merci pour votre réponse mais je crains de ne pas l'avoir. Comment suis-je censé soustraire le centre (connu) des coins (inconnu) s'ils sont inconnus? Je veux dire, les coordonnées des coins sont les choses mêmes que j'essaie de découvrir.
Stacky
J'ai essayé de clarifier.
Joseph O'Rourke
0

Il est possible que certaines optimisations soient disponibles en divisant le problème en deux:

  • calculer le centre du haut et du bas, c'est-à-dire le centre + la hauteur pivotée / 2.
  • calculer les coins par rapport à ces points centraux en utilisant la largeur pivotée / 2
  • Calculez le sinus et le cosinus réels une fois pour toutes.

Code ci-dessous, ici le rectangle est appelé règle. ruler.x, ruler, y est le centre du rectangle.

/** Middle point on rulers's top side. */
function getRulerTopMiddle(cos, sin) {
    return {
        x : ruler.x + sin * ruler.height/2,
        y : ruler.y - cos * ruler.height/2
    }
 }

/** Middle point on rulers's bottom side. */
function getRulerBottomMiddle(cos, sin) {
    return {
        x : ruler.x - sin * ruler.height/2,
        y : ruler.y + cos * ruler.height/2
    }
 }

/** Update ruler's four corner coordinates. */
function getRulerCorners() {
    const sin = Math.sin(ruler.angle);
    const cos = Math.cos(ruler.angle);
    const topMiddle = getRulerTopMiddle(cos, sin);
    const bottomMiddle = getRulerBottomMiddle(cos, sin);

    ruler.nw = {
        x: topMiddle.x - (cos * ruler.width/2),
        y: topMiddle.y - (sin * ruler.width/2)
    }   
    ruler.ne = {
        x: topMiddle.x + (cos * ruler.width/2),
        y: topMiddle.y + (sin * ruler.width/2)
    }   
    ruler.sw = {
        x: bottomMiddle.x - (cos * ruler.width/2),
        y: bottomMiddle.y - (sin * ruler.width/2)
    }   
    ruler.se = {
        x: bottomMiddle.x + (cos * ruler.width/2),
        y: bottomMiddle.y + (sin * ruler.width/2)
    }
}
Alec Leamas
la source
0

Un peu tard, mais voici une fonction compacte que j'ai utilisée. Il calcule les points haut et gauche, puis les retourne simplement pour les coins opposés.

rotatedRect(float x, float y, float halfWidth, float halfHeight, float angle)
{
    float c = cos(angle);
    float s = sin(angle);
    float r1x = -halfWidth * c - halfHeight * s;
    float r1y = -halfWidth * s + halfHeight * c;
    float r2x =  halfWidth * c - halfHeight * s;
    float r2y =  halfWidth * s + halfHeight * c;

    // Returns four points in clockwise order starting from the top left.
    return
        (x + r1x, y + r1y),
        (x + r2x, y + r2y),
        (x - r1x, y - r1y),
        (x - r2x, y - r2y);
}
cmann
la source
0

Ancien poste, mais voici une autre façon de le faire:

public static Point[] GetRotatedCorners(Rectangle rectangleToRotate, float angle)
{

    // Calculate the center of rectangle.
    Point center = new Point(rectangleToRotate.Left + (rectangleToRotate.Left + rectangleToRotate.Right) / 2, rectangleToRotate.Top + (rectangleToRotate.Top + rectangleToRotate.Bottom) / 2);

    Matrix m = new Matrix();
    // Rotate the center.
    m.RotateAt(360.0f - angle, center);

    // Create an array with rectangle's corners, starting with top-left corner and going clock-wise.
    Point[] corners = new Point[]
        {
            new Point(rectangleToRotate.Left, rectangleToRotate.Top), // Top-left corner.
            new Point(rectangleToRotate.Right, rectangleToRotate.Top),    // Top-right corner.
            new Point(rectangleToRotate.Right, rectangleToRotate.Bottom), // Bottom-right corner.
            new Point(rectangleToRotate.Left, rectangleToRotate.Bottom),  // Botton-left corner
        };

    // Now apply the matrix to every corner of the rectangle.
    m.TransformPoints(corners);

    // Return the corners of rectangle rotated by the provided angle.
    return corners;
}

J'espère que cela aide!

DiligentKarma
la source