Bagaimana cara menghitung posisi sudut / tanda persegi panjang yang diputar / miring?

17

Saya punya dua elemen, titik 2D dan area persegi panjang. Titik mewakili tengah area itu. Saya juga tahu lebar dan tinggi daerah itu. Dan area dimiringkan oleh 40 ° relatif terhadap grid.

Sekarang saya ingin menghitung posisi absolut dari setiap tanda sudut area miring hanya menggunakan data ini. Apakah itu mungkin?

Stacky
sumber

Jawaban:

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

Ini akan memberi Anda lokasi titik diputar θ derajat di sekitar titik asal. Karena sudut-sudut alun-alun diputar di sekitar pusat kotak dan bukan asal, beberapa langkah perlu ditambahkan untuk dapat menggunakan rumus ini. Pertama, Anda perlu mengatur titik relatif ke titik asal. Kemudian Anda bisa menggunakan rumus rotasi. Setelah rotasi, Anda perlu memindahkannya kembali relatif ke tengah alun-alun.

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

Terapkan ini ke semua 4 sudut dan Anda selesai!

Aholio
sumber
4

Ini adalah teknik umum untuk memutar titik tentang pivot dengan menerjemahkan ke sistem koordinat di mana pivot adalah asal, kemudian memutar tentang asal ini, lalu menerjemahkan kembali ke koordinat dunia. (Penjelasan yang sangat baik tentang pendekatan ini tersedia di Khan Academy )

Namun Anda tidak menyimpan sudut persegi panjang di koordinat dunia sehingga kami dapat menyesuaikan pendekatan yang sesuai dengan data yang Anda miliki.

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

Pendekatan ini kemudian dapat dengan mudah diterapkan pada tiga sudut lainnya.

Kelly Thomas
sumber
2

Berdasarkan jawaban lain, dan untuk melengkapi mereka, saya berhasil membuat contoh dengan P5 di sini .

Ini kodenya, jika Anda ingin mengaksesnya langsung:

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
sumber
1

Refactoring kode di atas memberikan formulir yang dibersihkan yang juga menyoroti fakta sederhana bahwa setiap sudut pada dasarnya center + height/2 + width/2, dengan tanda-tanda yang sesuai untuk setiap sudut. Ini juga berlaku jika Anda memperlakukan height/2dan width/2sebagai vektor yang diputar.

Memercayai penerjemah untuk menyejajarkan para penolong, ini seharusnya cukup efektif, haruskah kita mencoba membandingkan ini.

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
sumber
0

Lihat artikel Wikipedia tentang rotasi . Intinya adalah ini:

(1) Jika c adalah titik tengah, maka sudutnya adalah c + ( L / 2, W / 2), +/- dll., Di mana L dan W adalah panjang & lebar dari persegi panjang.

(2) Terjemahkan persegi panjang sehingga pusat c pada titik asal, dengan mengurangi c dari keempat sudut.

(3) Putar persegi dengan 40 deg melalui rumus trigonometri yang dikutip.

(4) Terjemahkan kembali dengan menambahkan c ke setiap koordinat.

Joseph O'Rourke
sumber
Terima kasih atas jawaban Anda, tetapi saya rasa saya tidak mengerti. Bagaimana saya bisa mengurangi pusat (dikenal) dari sudut (tidak diketahui) jika mereka tidak diketahui? Maksud saya, koordinat sudut adalah hal-hal yang saya coba cari tahu.
Stacky
Saya mencoba mengklarifikasi.
Joseph O'Rourke
0

Mungkin, ada beberapa optimasi yang tersedia dengan membagi masalah menjadi dua:

  • hitung pusat sisi atas dan bawah yaitu, tengah + tinggi yang diputar / 2.
  • hitung sudut relatif ke titik-titik tengah ini menggunakan lebar yang diputar / 2
  • Hitung sinus dan kosinus yang sebenarnya untuk selamanya.

Kode di bawah ini, di sini persegi panjang disebut penggaris. ruler.x, ruler, y adalah pusat persegi panjang.

/** 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
sumber
0

Sedikit terlambat, tapi inilah fungsi ringkas yang saya gunakan. Ini menghitung poin atas dan kiri, lalu membalikkannya ke sudut yang berlawanan.

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
sumber
0

Posting lama, tapi di sini ada cara lain untuk melakukannya:

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

Semoga ini bisa membantu!

DiligentKarma
sumber