首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Konva:获得旋转矩形的角坐标

Konva:获得旋转矩形的角坐标
EN

Stack Overflow用户
提问于 2019-11-29 03:25:35
回答 2查看 2.4K关注 0票数 1

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

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

绕另一个点旋转(2D)

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

https://gamedev.stackexchange.com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilted-rectangle

这是密码

代码语言:javascript
运行
复制
// 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)。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-03 21:06:09

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

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

代码语言:javascript
运行
复制
// 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()
代码语言:javascript
运行
复制
<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>

票数 3
EN

Stack Overflow用户

发布于 2021-01-09 16:59:37

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

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

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

这意味着我们可以这样做..。

代码语言:javascript
运行
复制
// 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.

重要说明

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

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

如果我们在决定未旋转的角点时不否定移动点,那么它们似乎经历了2倍的移动变换。

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

下面是一个使用getAbsoluteTransform()方法的工作片段。

代码语言:javascript
运行
复制
// 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()
代码语言:javascript
运行
复制
<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>

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59098408

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档