Рассчитать углы повернутого прямоугольника в контейнере - PullRequest
0 голосов
/ 25 июня 2018

У меня возникли проблемы с вычислением углов повернутого прямоугольника в повернутом контейнере, причем оба имеют смещенные координаты x / y.

Пивот выключен, но я не уверен в решении. Работают следующие сценарии:

(x, y, rotation)
image = 0, 0, 45
container = 100, 100, 45

image = 200, 0, 45
container = 100, 100, 0

, однако, устанавливает вращение контейнера, и изображения объединяются, например,

image = 200, 0, 45
container = 100, 100, 45

Ниже приведен код для вычисления углов изображения в глобальном координатном пространстве:

public get corners() {
        const worldData = this.worldData;
        //Get angle of object in radians;
        const radAngle = worldData.rotation * Math.PI / 180;
        const pivotX = worldData.pivotX;
        const pivotY = worldData.pivotY;
        const width = this.sourceWidth * worldData.scaleX;
        const height = this.sourceHeight * worldData.scaleY;
        const x = worldData.x;//this.x;
        const y = worldData.y;//this.y;

        //Get the corners
        const c1 = this.getCorner(pivotX, pivotY, x, y, radAngle);
        const c2 = this.getCorner(pivotX, pivotY, x + width, y, radAngle);
        const c3 = this.getCorner(pivotX, pivotY, x + width, y + height, radAngle);
        const c4 = this.getCorner(pivotX, pivotY, x, y + height, radAngle);

        return {c1, c2, c3, c4};
    }

    public get worldData() {
        let x = this.x;
        let y = this.y;
        let pivotX = this.x;
        let pivotY = this.y;
        let rotation = this.rotation;
        let scaleX = this.scaleX;
        let scaleY = this.scaleY;
        let parent = this.parent;

        while(parent) {
            x += parent.x;
            y += parent.y; 
            pivotX += parent.x;
            pivotY += parent.y;
            rotation += parent.rotation;
            scaleX *= parent.scaleX;
            scaleY *= parent.scaleY;
            parent = parent.parent;
        }

        return {x, y, scaleX, scaleY, rotation, pivotX, pivotY}
    }

    protected getCorner(pivotX:number, pivotY:number, cornerX:number, cornerY:number, angle:number) {
        let x, y, distance, diffX, diffY;

        /// get distance from center to point
        diffX = cornerX - pivotX;
        diffY = cornerY - pivotY;
        distance = Math.sqrt(diffX * diffX + diffY * diffY);

        /// find angle from pivot to corner
        angle += Math.atan2(diffY, diffX);

        /// get new x and y and round it off to integer
        x = pivotX + distance * Math.cos(angle);
        y = pivotY + distance * Math.sin(angle);

        return {x, y};
    }

1 Ответ

0 голосов
/ 25 июня 2018

Предположим, что сценарий выглядит следующим образом:

enter image description here

, где нижний левый угол изображения (сплошная линия) имеет координаты (x_i, y_i)и нижний левый угол контейнера (пунктирная линия) имеет координаты (X_c, Y_c).Кроме того, изображение (шириной w и высотой h) поворачивается против часовой стрелки на угол beta относительно корпуса лаборатории, тогда как сам контейнер поворачивается (также против часовой стрелки) на угол alpha..

Теперь давайте сосредоточимся, например, на верхнем правом углу P.Что касается лабораторного кадра (глобальный холст), его координаты могут быть выражены как:

R(beta) . ( w, h ) + ( x_i, y_i )

, где . обозначает умножение матрицы, а R - матрица вращения против часовой стрелки

R(beta) = [ cos(beta) -sin(beta) ]
          [ sin(beta)  cos(beta) ]

Теперь нам нужно преобразовать это в координатную рамку относительно контейнера.Формально это означает, что нам нужно сначала вычесть смещение, а затем повернуть на -alpha (или alpha по часовой стрелке).Таким образом, со всем вместе:

R(-alpha).( R(beta) . (w, h) + (x_i, y_i) - (X_c, Y_c) )

Другие углы можно обрабатывать аналогично, просто заменив (w, h) на правильные координаты ...

С точки зрения кода, можно реализовать этиформулы как:

//counter-clock-wise rotation by given angle in degrees
function rotateCCWBy(angle, {x, y}) {
  const angle_rad = angle * Math.PI / 180;
  const cos_a = Math.cos(angle_rad),
        sin_a = Math.sin(angle_rad);

  return {
    x: cos_a * x - sin_a * y,
    y: sin_a * x + cos_a * y
  };
}

//shift by a multiple fac of an offset {xref, yref}
function offsetBy(fac, {x:xref, y:yref}, {x, y}) {
  return {
    x: fac*xref + x,
    y: fac*yref + y
  };
}

const image = {
  coords: {x: 200, y: 0}, //lab-frame coordinates
  angle: 45, //lab-frame rotation angle
  width: 50,
  height: 10
};

const container = {
  coords: {x: 100, y: 100}, //lab-frame coordinates
  angle: 45 //lab-frame rotation angle
};

//calculate the coordinates of the image's top-right corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
  offsetBy(
    -1, container.coords,
    offsetBy(
      +1, image.coords,
      rotateCCWBy(image.angle,
        {x: image.width, y: image.height}
      )
    )
  )
);

console.log(corner);

РЕДАКТИРОВАТЬ:

В случае, если ось Y должна указывать «вниз», вышеприведенные формулы также работают, нужно просто интерпретировать углы как часы-вместо против часовой стрелки (поэтому в принципе функцию rotateCCWBy следует переименовать в rotateCWBy).В качестве примера рассмотрим этот сценарий:

enter image description here

Здесь верхний левый угол контейнера расположен в позиции (2,1) иСам контейнер поворачивается на 15 градусов.Изображение (черный прямоугольник) шириной 4 и высотой 2 поворачивается на 30 градусов, а его верхний левый угол находится в положении (3, 3).Теперь мы хотим вычислить координаты (x, y) точки P относительно контейнера.

Используя:

const image = {
  coords: {x: 3, y: 3}, //lab-frame coordinates
  angle: 30, //lab-frame rotation angle
  width: 4,
  height: 2
};

const container = {
  coords: {x: 2, y: 1}, //lab-frame coordinates
  angle: 15 //lab-frame rotation angle
};

//calculate the coordinates of the image's top-left corner
//with respect to the container
const corner = rotateCCWBy(-container.angle,
  offsetBy(
    -1, container.coords,
    offsetBy(
      +1, image.coords,
      rotateCCWBy(image.angle,
        {x: image.width, y: image.height}
      )
    )
  )
);

console.log(corner);

, получаем

{ x: 4.8296291314453415, y: 4.640160440463835 }

, которые могут быть(приблизительно) визуально проверено на прилагаемом рисунке.

EDIT2:

После дополнительного уточнения координаты изображения не должны быть "лабораторными рамками" (т.е. относительно холста), но относительно уже повернутого контейнера.Таким образом, преобразование должно быть адаптировано как:

const corner = 
  offsetBy(
    +1, container.coords,
        rotateCCWBy(container.angle,    
      offsetBy(
        +1, image.coords,
        rotateCCWBy(image.angle,
          {x: image.width, y: image.height}
        )
      )
    )
  );

function rotateCCWBy(angle, {x, y}) {
  const angle_rad = angle * Math.PI / 180;
  const cos_a = Math.cos(angle_rad),
        sin_a = Math.sin(angle_rad);

  return {
    x: cos_a * x - sin_a * y,
    y: sin_a * x + cos_a * y
  };
}
...