在画布中如何在另一个旋转的矩形周围创建一个矩形?

huangapple go评论109阅读模式
英文:

How to create a rectangle around another rotated rectangle in canvas?

问题

在画布上绘制红色矩形在黑色矩形下方,使得旋转的黑色矩形的所有4个顶点接触红色矩形的4条边,可以使用以下代码:

// Rectangle properties
const redWidth = 60;
const redHeight = 220;
const redX = centerX - redWidth / 2;
const redY = centerY - redHeight / 2;

// Draw the red rectangle
ctx.fillStyle = 'red';
ctx.fillRect(redX, redY, redWidth, redHeight);

请将这段代码添加到您的现有代码中的合适位置。

英文:

How to draw the red rectangle below black rectangle on canvas such that all 4 vertices of the rotated black rectangle touch all 4 edges of the red rectangle? I am using the following code to add the black rectangle:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const canvas = document.getElementById(&#39;myCanvas1&#39;);
const ctx = canvas.getContext(&#39;2d&#39;);

// Rectangle properties
const width = 50;
const height = 200;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;

// Rotation angle in degrees
const degrees = -10; // Anti-clockwise rotation
const radians = (degrees * Math.PI) / 180;

// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);

// Save the canvas state
ctx.save();

// Translate to the center of the rectangle
ctx.translate(centerX, centerY);

// Rotate the canvas
ctx.rotate(radians);

// Draw the rotated rectangle
ctx.fillStyle = &#39;black&#39;;
ctx.fillRect(-width / 2, -height / 2, width, height);

// Restore the canvas state
ctx.restore();

<!-- language: lang-html -->

&lt;canvas id=&quot;myCanvas1&quot; width=&quot;600&quot; height=&quot;250&quot;&gt;&lt;/canvas&gt;

<!-- end snippet -->

在画布中如何在另一个旋转的矩形周围创建一个矩形?

答案1

得分: 1

Brute force

暴力方法计算了旋转矩形的每个角的位置。然后,为了获取边界框,获取最左上角的角。

由于矩形围绕其中心旋转,边界框的宽度和高度是从矩形中心到两倍的距离。

函数 drawRect 绘制了旋转矩形并返回表示边界框的对象。

requestAnimationFrame(animLoop);
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const width = Math.min(centerX, centerY) * 1.8;
const height = width * 0.25;
var rot = 0.0;

function drawRect(width, height, centerX, centerY, rotate) {

    // 计算 x 轴向量
    const xAx = Math.cos(rotate);
    const xAy = Math.sin(rotate);
    ctx.setTransform(xAx, xAy, -xAy, xAx, centerX, centerY);
    ctx.fillStyle = "#000";
    const hw = width * 0.5;               // 半宽和半高
    const hh = height * 0.5;
    ctx.fillRect(-hw, -hh, width, height);
    ctx.setTransform(1, 0, 0, 1, 0, 0);   // 恢复默认
    
    // 获取 4 个角
    const topLeft =  {x: -hw * xAx - -hh * xAy, y: -hw * xAy + -hh * xAx};
    const botLeft =  {x: -hw * xAx -  hh * xAy, y: -hw * xAy +  hh * xAx};
    const topRight = {x:  hw * xAx - -hh * xAy, y:  hw * xAy + -hh * xAx};
    const botRight = {x:  hw * xAx -  hh * xAy, y:  hw * xAy +  hh * xAx};
    
    // 获取最左上角的角
    const left = Math.min(topLeft.x, botLeft.x, topRight.x, botRight.x);
    const top =  Math.min(topLeft.y, botLeft.y, topRight.y, botRight.y);
    
    // 返回边界框
    return {
       left:    left + centerX,
       top:     top + centerY,
       width:  -left * 2,
       height: -top * 2,
    };
}

function animLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    rot += 0.01;
    const bounding = drawRect(width, height, centerX, centerY, rot);
    ctx.globalCompositeOperation = "destination-over";
    ctx.fillStyle = "#F00";
    ctx.fillRect(bounding.left, bounding.top, bounding.width, bounding.height);
    ctx.globalCompositeOperation = "source-over";
    requestAnimationFrame(animLoop);
}
<canvas id="canvas" width="400" height="180"></canvas>
英文:

Brute force

The brute force method calculates the position of each corner of the rotated rectangle. Then to get the bounding box get the left top most corner.

As the rectangle is rotated around its center the width and height of the bounding box is double the distance from the rectangle center.

The function drawRect draws the rotated rectangle and returns an object representing the bounding box

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

requestAnimationFrame(animLoop);
const ctx = canvas.getContext(&#39;2d&#39;);
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const width = Math.min(centerX, centerY) * 1.8;
const height = width * 0.25
var rot = 0.0;
function drawRect(width, height, centerX, centerY, rotate) {
// compute the x axis vector
const xAx = Math.cos(rotate);
const xAy = Math.sin(rotate);
ctx.setTransform(xAx, xAy, -xAy, xAx, centerX, centerY);
ctx.fillStyle = &quot;#000&quot;;
const hw = width * 0.5;               // half width and height
const hh = height * 0.5;
ctx.fillRect(-hw, -hh, width, height);
ctx.setTransform(1, 0, 0, 1, 0, 0);   // restore default
// Get 4 corners
const topLeft =  {x: -hw * xAx - -hh * xAy, y: -hw * xAy + -hh * xAx};
const botLeft =  {x: -hw * xAx -  hh * xAy, y: -hw * xAy +  hh * xAx};
const topRight = {x:  hw * xAx - -hh * xAy, y:  hw * xAy + -hh * xAx};
const botRight = {x:  hw * xAx -  hh * xAy, y:  hw * xAy +  hh * xAx};
// Get the left top most corner
const left = Math.min(topLeft.x, botLeft.x, topRight.x, botRight.x);
const top =  Math.min(topLeft.y, botLeft.y, topRight.y, botRight.y);
// Return the bounding box
return {
left:    left + centerX,
top:     top + centerY,
width:  -left * 2,
height: -top * 2,
};
}
function animLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
rot += 0.01;
const bounding = drawRect(width, height, centerX, centerY, rot);
ctx.globalCompositeOperation = &quot;destination-over&quot;;
ctx.fillStyle = &quot;#F00&quot;;
ctx.fillRect(bounding.left, bounding.top, bounding.width, bounding.height);
ctx.globalCompositeOperation = &quot;source-over&quot;;
requestAnimationFrame(animLoop);
}

<!-- language: lang-html -->

&lt;canvas id=&quot;canvas&quot; width=&quot;400&quot; height=&quot;180&quot;&gt;&lt;/canvas&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年8月11日 01:23:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76878011.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定