当前位置: 首页 > 知识库问答 >
问题:

Konva:获取旋转矩形的角坐标

况景龙
2023-03-14

如何获得旋转矩形的角坐标(以矩形为中心)?

我已经尝试了以下链接中的所有解决方案,但似乎没有任何运气。

将一个点绕另一个点旋转(2D)

找到给定中心点和旋转的旋转矩形的角

https://game dev . stack exchange . com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilted-rectangle

这是代码

// make a rectangle with zero rotation
const rect1 = new Konva.Rect({
  x: 200,
  y: 200,
  width: 100,
  height: 50,
  fill: "#00D2FF",
  draggable: true,
  rotation: 0,
  name: "rect"
});

// convert degree to rad
const degToRad = (deg: number) => deg * (Math.PI / 180);

// here's the code i use to rotate it around its center (from https://konvajs.org/docs/posts/Position_vs_Offset.html)

const rotateAroundCenter = (node: Rect, rotation: number) => {
     const topLeft = {
    x: -node.width() / 2,
    y: -node.height() / 2
  };
  console.log(`current X: ${node.x()}, current Y: ${node.y()},`)

  const currentRotatePoint = rotatePoint(topLeft, degToRad(node.rotation()));
  const afterRotatePoint = rotatePoint(topLeft, degToRad(rotation));
  const dx = afterRotatePoint.x - currentRotatePoint.x;
  const dy = afterRotatePoint.y - currentRotatePoint.y;

  node.rotation(rotation);
  node.x(node.x() + dx);
  node.y(node.y() + dy);
  layer.draw();

console.log(`the actual position x: ${node.x()}, y: ${node.y()}`);
};

// the code that i expected to give me the corner point

const computeCornerPoint = (r:Rect) => {
  // for now we want to compute top left corner point(as it's the easiest corner to get)
  let corner = {
     x: r.x(),
     y: r.y()
  };

  // the coordinate of rectangle's center (in stage coordinate)
  const cx = r.x() + r.width() / 2;
  const cy = r.y();

  // sine and cosine of the rectangle's rotation
  const s = Math.sin(degToRad(r.rotation()));
  const c = Math.cos(degToRad(r.rotation()));

  // rotate the corner point
  let xnew = c * (corner.x - cx) - s * (corner.y - cy) + cx;
  let ynew = s * (corner.x - cx) + c * (corner.y - cy) + cy;

  console.log(`based on this function calculation: xnew : ${xnew}, ynew: ${ynew}`);
  return [xnew, ynew];
}

根据上面的代码,如果初始旋转角度为0,我将矩形顺时针旋转30度,那么实际位置将与computeCornerPoint中的值相同,即(219,178),如果我将它再次顺时针旋转30度,实际位置将为(246,169),而computeCornerPoint中的值将为(275,175)。

共有2个答案

林雅畅
2023-03-14

我最近学习了一种新的、更简单的方法来使用内置的Konva函数实现这一点。node.getTransform及其密切关系node.getAbsoluteTransform方法将检索应用于节点(形状)的转换。绝对版本获取包括父转换在内的转换,而普通getTransform获取相对于节点父的转换。

都返回一个Konva。transform对象,它本身具有point()方法,该方法将接受给定的{x,y}对象并对其应用转换。

使用应用于形状的变换意味着我们不必关心如何模仿该变换的步骤——我们只是要求将相同的变换应用于我们的点。

这意味着我们可以做到这一点...

// assuming we have a Konva rect already...
let rect = new Konva.Rect({
  x: 100,
  y: 80,
  width: 60,
  height: 20,
  fill: 'cyan'
  rotation: 45    
})

let corners = [],
    size = rect.size();

// Now get the 4 corner points
corners[0] = {x: 0, y: 0 }; // top left
corners[1] = {x: size.width, y: 0 }; // top right
corners[2] = {x: size.width, y: size.height }; // bottom right
corners[4] = {x: 0, y: size.height }; // bottom left

// And rotate the corners using the same transform as the rect.
for (let i = 0; i < 4; i++){
  // Here be the magic
  corners[i] = rect.getAbsoluteTransform().point(corners[i]); // top left
}

// At this point we have the rotated positions of the corners.

重要说明

你会看到,在上面的代码中,矩形的角是相对于原点设置的,而不是相对于矩形位置。换句话说,左上角是{x: 0,y: 0}而不是{x: rect.x(),y: rect.y()},右下角是{x: rect.width,y: rect.height}。这是因为rect的变换是:

  1. 移动(x, y)
  2. 旋转(角度)

如果我们在决定未旋转的角点时不否定移动,那么它们将看起来经历了2次移动变换。

moveto转换并不明显-它是在形状的初始声明中设置shape. x()和shape. y()的效果。

这是一个使用getAbsolteTransform()方法的工作片段。

// Function to rotate a point.
// node = the shape we are using to deterine the transform of the pt.
// pt = {x,y} of point to rotate, 
// returns {x, y} giving the new point.
function rotatePoint(node, pt){

  return node.getAbsoluteTransform().point(pt);
}

// This is just about drawing the circles at the corners.
function drawCorners(rect, angle){

  var rectPos = rect.position();
  
  var x = 0, y = 0;
  for (var i = 0; i < 4; i = i + 1){

  switch (i){
    
    case 0: 
      x = 0; y = 0;
      break;

    case 1: 
      x = rect.width(); y = 0;
      break;

    case 2: 
      x = rect.width(); y = rect.height();
      break;

    case 3: 
      x = 0; y = rect.height();
      break;

     }

    var pt = rotatePoint(rect, {x: x, y: y})
    circles[i].position(pt)

  }
 }


// rotate and redraw the rectangle
function rotateUnderMouse(){


  // Get the stage position of the mouse
  var mousePos = stage.getPointerPosition();

  // get the stage position of the mouse
  var shapePos = rect.position();

  // compute the vector for the difference
  var rel = {x: mousePos.x - shapePos.x, y: mousePos.y - shapePos.y} 

  // Now apply the rotation
  angle = angle + 90;

  circle.position({x: mousePos.x, y: mousePos.y});
  circle.show();
  
  // and reposition the shape to keep the same point in the shape under the mouse 
  var newPos = ({x: mousePos.x  + rel.y , y: mousePos.y - rel.x}) 

  rect.position(newPos);
  rect.rotation(angle);

  // re-calculate and draw the circle positions.
  drawCorners(rect, angle)

  stage.draw()
}





function setup() {

// Set up a stage and a shape
stage = new Konva.Stage({
  container: 'canvas-container',
  width: 650,
  height: 300
});


layer = new Konva.Layer();
stage.add(layer);

newPos = {x: 80, y: 100};
rect = new Konva.Rect({
   width: 140, height: 50, x: newPos.x, y: newPos.y, draggable: true, stroke: 'silver', fill: 'cyan'
  })

// not very dry, setting up the corner circles.
circle = new Konva.Circle({x: newPos.x, y: newPos.y, radius: 10, fill: 'magenta', listening: false}) 
circles[0] = circle.clone();
circles[0].fill('lime')
layer.add(circles[0]);
circles[1] = circle.clone();
circles[1].fill('gold')
layer.add(circles[1]);
circles[2] = circle.clone();
circles[2].fill('blue')
layer.add(circles[2]);
circles[3] = circle.clone();
circles[3].fill('darkviolet')

layer.add(circles[3]);

layer.add(rect);
layer.add(circle);
circle.hide()

drawCorners(rect, 0)

stage.draw()

rect.on('mousedown', function(){
  rotateUnderMouse()
})

}

var stage, layer, rect, circles = [], angle = 0;

setup()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/4.0.13/konva.js"></script>

<p>Click the rectangle - it will rotate 90 degrees clockwise under the mouse and coloured circles will be drawn consistently at the corners. These circles have their position derived via the rect.transform - not calculated. NB: No dragging !</p>

<div id="canvas-container"></div>
毛胜
2023-03-14

在画布的世界里,生活是矩形的,所以我们要预测角落位置,就要知道左上角的形状和旋转角度,然后应用一些高中数学。旋转点的数学运算在函数 rotatePoint() 中。代码段的其余部分是为使用和说明结果而设置的。

也许最好在全屏模式下运行代码段。

// Function to rotate a point.
// pt = {x,y} of point to rotate, 
// o = {x, y} of rotation origin, 
// a = angle of rotation in degrees.
// returns {x, y} giving the new point.
function rotatePoint(pt, o, a){

  var angle = a * (Math.PI/180); // Convert to radians

  var rotatedX = Math.cos(angle) * (pt.x - o.x) - Math.sin(angle) * (pt.y - o.y) + o.x;

  var rotatedY = Math.sin(angle) * (pt.x - o.x) + Math.cos(angle) * (pt.y - o.y) + o.y;  

  return {x: rotatedX, y: rotatedY};

}

// This is just about drawing the circles at the corners.
function drawCorners(rect, angle){

  var rectPos = rect.position();
  
  var x = 0, y = 0;
  for (var i = 0; i < 4; i = i + 1){

  switch (i){
    
    case 0: 
      x = rectPos.x; y = rectPos.y;
      break;

    case 1: 
      x = rectPos.x + rect.width(); y = rectPos.y;
      break;

    case 2: 
      x = rectPos.x + rect.width(); y = rectPos.y + rect.height();
      break;

    case 3: 
      x = rectPos.x; y = rectPos.y + rect.height();
      break;

     }

    var pt = rotatePoint({x: x, y: y}, {x: rectPos.x, y: rectPos.y}, angle)
    circles[i].position(pt)

  }
 }


// rotate and redraw the rectangle
function rotateUnderMouse(){


  // Get the stage position of the mouse
  var mousePos = stage.getPointerPosition();

  // get the stage position of the mouse
  var shapePos = rect.position();

  // compute the vector for the difference
  var rel = {x: mousePos.x - shapePos.x, y: mousePos.y - shapePos.y} 

  // Now apply the rotation
  angle = angle + 90;

  circle.position({x: mousePos.x, y: mousePos.y});
  circle.show();
  
  // and reposition the shape to keep the same point in the shape under the mouse 
  var newPos = ({x: mousePos.x  + rel.y , y: mousePos.y - rel.x}) 

  rect.position(newPos);
  rect.rotation(angle);

  // re-calculate and draw the circle positions.
  drawCorners(rect, angle)

  stage.draw()
}





function setup() {

// Set up a stage and a shape
stage = new Konva.Stage({
  container: 'canvas-container',
  width: 650,
  height: 300
});


layer = new Konva.Layer();
stage.add(layer);

newPos = {x: 80, y: 100};
rect = new Konva.Rect({
   width: 140, height: 50, x: newPos.x, y: newPos.y, draggable: true, stroke: 'silver', fill: 'cyan'
  })

// not very dry, setting up the corner circles.
circle = new Konva.Circle({x: newPos.x, y: newPos.y, radius: 10, fill: 'magenta'}) 
circles[0] = circle.clone();
circles[0].fill('lime')
layer.add(circles[0]);
circles[1] = circle.clone();
circles[1].fill('gold')
layer.add(circles[1]);
circles[2] = circle.clone();
circles[2].fill('blue')
layer.add(circles[2]);
circles[3] = circle.clone();
circles[3].fill('darkviolet')

layer.add(circles[3]);

layer.add(rect);
layer.add(circle);
circle.hide()

drawCorners(rect, 0)

stage.draw()

rect.on('mousedown', function(){
  rotateUnderMouse()
})

}

var stage, layer, rect, circles = [], angle = 0;

setup()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/4.0.13/konva.js"></script>

<p>Click the rectangle - it will rotate 90 degrees clockwise under the mouse and coloured circles will be drawn consistently at the corners. These circles have their position calculated rather than derived from the visual rectangle corner positions. NB: No dragging !</p>

<div id="canvas-container"></div>
 类似资料:
  • 我正在尝试使用Surfaceview和canvas drawing在Android中创建自定义组件。这些组件可以通过触摸来调整大小和旋转。考虑创建一个图像视图,它的上、右、下和左边缘可通过触摸和拖动所需的边缘来缩放。我使用< code>RectF来保持组件的边界,对于旋转,我使用< code>canvas.rotate(angle,bounds.centerX()、bounds.centerY()

  • 我刚开始使用JavaFX,有一个问题。在我的项目中,我想使用旋转矩形。但矩形只围绕其中心旋转,我希望它围绕其左上角旋转。 就像这张照片(从这里开始): 下面是我的项目中的一些代码: 在这种情况下,如果按下箭头键,矩形会旋转。

  • 我正在做一个简单的模拟,并且在寻找一个旋转的、大小怪异的ImageView节点的X和Y坐标时遇到了很多麻烦。(蓝色的部分是前面) 目标是在旋转后找出相对于imageView指向的方向的XY坐标。我可以找到imageView相对于其起始位置的角度,但我不知道如何获得imageView相对于该角度的XY坐标。从那以后。setRotate(angle)方法不会更改imageView的X和Y位置,我应该如

  • 问题内容: 我到处搜索,但找不到答案。 如何在Java中旋转矩形? 这是我的一些代码: 我尝试了g2d.rotate(100D); 但它没有用。提前致谢。 这是我编辑的代码: 问题答案: 对于图像,必须将Graphics2D的drawImage方法与相对的AffineTransform一起使用。 对于形状,您可以旋转Graphics2D本身: 顺便说一句,您应该重写paintComponent方法

  • 问题内容: 我需要创建围绕其中心旋转的矩形(因此它们不必平行于坐标系的轴)。因此,基本上每个矩形都可以由 center-X , center-Y , width , height 和 angle定义 。然后,我要做的是对这些矩形中是否包含某些点进行计算(因此不会涉及任何绘图)。我想我不能使用该类,因为这些矩形将始终与坐标系的x和y轴平行。是通过编写自己的矩形类来获得此功能的唯一方法,还是可以使用任

  • 嗨,我想做一个自定义的视图,因为我正在加载位图,它有黑色的边框,右上方有关闭按钮 因此当用户按下关闭按钮时,该图像应被移除 我已经检查了下面的链接,但无法成功 利用矩阵得到旋转后坐标的新位置