Як обчислити кутові положення / позначки обертового / нахиленого прямокутника?


17

У мене два елементи, 2D точка і прямокутна область. Точка представляє середину цієї області. Я також знаю ширину та висоту цієї області. А площа нахилена на 40 ° щодо сітки.

Тепер я хотів би обчислити абсолютні позиції кожної кутової позначки нахиленої області лише за допомогою цих даних. Це можливо?

Відповіді:


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

Це дасть вам розташування точки, оберненої на θ градусів навколо початку. Оскільки кути квадрата обертаються навколо центру квадрата, а не походження, необхідно додати пару кроків, щоб мати можливість використовувати цю формулу. Спочатку потрібно встановити точку відносно початку. Тоді ви можете використовувати формулу обертання. Після обертання потрібно перенести його назад відносно центру квадрата.

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

Нанесіть це на всі 4 кути, і ви закінчили!


4

Це загальна техніка повертати точку навколо стрижня шляхом перекладу в систему координат, де поворот є початком, а потім обертання навколо цього початку, а потім переведення назад до світових координат. (Дуже вдале пояснення такого підходу є в Академії Хана )

Однак ви не зберігаєте свої кути прямокутника у світових координатах, тому ми можемо підібрати підхід відповідно до наявних у вас даних.

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

Цей підхід може бути легко застосований до трьох інших кутів.


2

На основі інших відповідей та доповнивши їх, мені вдалося створити приклад із P5 тут .

Ось код, якщо ви хочете отримати доступ до нього безпосередньо:

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

Рефакторинг коду, що наведений вище, дає очищену форму, яка також підкреслює простий факт, що кожен кут є, в основному center + height/2 + width/2, зі знаками для кожного кута. Це також справедливо , якщо розглядати height/2і в width/2якості повернених векторів.

Довіряючи перекладачеві, щоб впорядкувати помічників, це повинно бути досить ефективним, якщо ми спробуємо це порівняти.

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

Дивіться статтю Вікіпедії про обертання . Суть така:

(1) Якщо c - центральна точка, то кути - c + ( L / 2, W / 2), +/- тощо, де L і W - довжина і ширина прямокутника.

(2) Перекладіть прямокутник так, щоб центр c був біля початку, віднімаючи c з усіх чотирьох кутів.

(3) Поверніть прямокутник на 40 град. За цитованими формулами.

(4) Перекладіть назад, додавши c до кожної координати.


Дякую за вашу відповідь, але я боюся, що я цього не зрозумію. Як я повинен субстратувати центр (відомий) з кутів (невідомо), якщо вони невідомі? Я маю на увазі, що координати кутів - це саме те, що я намагаюся з’ясувати.
Стакі

Я намагався уточнити.
Джозеф О'Рурк

0

Можливо, існують деякі оптимізації, розділивши проблему на два:

  • обчислити центр верхньої та нижньої сторони, тобто центр + повернутий висоту / 2.
  • обчислити кути відносно цих центральних точок за допомогою обертової ширини / 2
  • Обчисліть фактичний синус і косинус раз і назавжди.

Код нижче, тут прямокутник називається лінійкою. правитель.x, лінійка, y - центр прямокутника.

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

Трохи пізно, але ось компактна функція, яку я використав. Він обчислює верхню та ліву точки, а потім просто перевертає їх за протилежні кути.

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

Стара публікація, але ось ще один спосіб зробити це:

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

Сподіваюся, це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.