Come calcolare le posizioni / i segni degli angoli di un rettangolo ruotato / inclinato?


17

Ho due elementi, un punto 2D e un'area rettangolare. Il punto rappresenta il centro di quell'area. Conosco anche la larghezza e l'altezza di quella zona. E l'area è inclinata di 40 ° rispetto alla griglia.

Ora vorrei calcolare le posizioni assolute di ogni segno d'angolo di quell'area inclinata usando solo questi dati. È possibile?

Risposte:


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

Questo ti darà la posizione di un punto ruotato di θ gradi attorno all'origine. Poiché gli angoli del quadrato vengono ruotati attorno al centro del quadrato e non all'origine, è necessario aggiungere un paio di passaggi per poter utilizzare questa formula. Per prima cosa devi impostare il punto relativo all'origine. Quindi è possibile utilizzare la formula di rotazione. Dopo la rotazione è necessario spostarlo indietro rispetto al centro del quadrato.

// 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;

Applicalo su tutti e 4 gli angoli e il gioco è fatto!


4

È una tecnica comune ruotare un punto attorno a un perno traducendo in un sistema di coordinate in cui il perno è l'origine, quindi ruota attorno a questa origine, quindi si traduce in coordinate del mondo. (Un'ottima spiegazione di questo approccio è disponibile presso la Khan Academy )

Tuttavia non stai memorizzando i tuoi angoli rettangolari in coordinate mondiali in modo da poter personalizzare un approccio in base ai dati disponibili.

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(θ))

Questo approccio può quindi essere facilmente applicato agli altri tre angoli.


2

Sulla base delle altre risposte e per completarle, sono riuscito a creare un esempio con P5 qui .

Ecco il codice, nel caso tu voglia accedervi direttamente:

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>


1

Il refactoring del codice sopra riportato fornisce un modulo pulito che evidenzia anche il semplice fatto che ogni angolo è sostanzialmente center + height/2 + width/2, con segni appropriati per ogni angolo. Questo vale anche se trattate height/2e width/2come vettori ruotati.

Fidarsi dell'interprete per integrare gli helper, questo dovrebbe essere abbastanza efficace, se dovessimo provare a confrontarlo.

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);
}

0

Vedi l'articolo di Wikipedia sulla rotazione . L'essenza è questa:

(1) Se c è il punto centrale, gli angoli sono c + ( L / 2, W / 2), +/- ecc., Dove L e W sono la lunghezza e la larghezza del rettangolo.

(2) Traduci il rettangolo in modo che il centro c sia all'origine, sottraendo c da tutti e quattro gli angoli.

(3) Ruota il rettangolo di 40 gradi tramite le formule di trigger citate.

(4) Traduci indietro aggiungendo c a ciascuna coordinata.


Grazie per la tua risposta, ma temo di non averlo capito. Come posso sottrarre il centro (noto) dagli angoli (sconosciuto) se sono sconosciuti? Voglio dire, le coordinate degli angoli sono le stesse cose che sto cercando di scoprire.
Stacky

Ho cercato di chiarire.
Joseph O'Rourke,

0

Forse, ci sono alcune ottimizzazioni disponibili dividendo il problema in due:

  • calcola il centro della parte superiore e inferiore, ovvero il centro + l'altezza ruotata / 2.
  • calcola gli angoli relativi a questi punti centrali usando la larghezza ruotata / 2
  • Calcola il seno e il coseno attuali una volta per tutte.

Codice sotto, qui il rettangolo si chiama righello. ruler.x, ruler, y è il centro del rettangolo.

/** 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)
    }
}

0

Un po 'in ritardo, ma ecco una funzione compatta che ho usato. Calcola i punti superiore e sinistro, quindi li capovolge per gli angoli opposti.

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);
}

0

Vecchio post, ma ecco un altro modo per farlo:

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;
}

Spero che sia d'aiuto!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.