在画布

时间:2016-09-09 13:43:44

标签: javascript canvas

我正在尝试制作渲染引擎,但我的计算有些困难。问题是我想获取图像的绘制边界框以检测此图像是否在画布限制内。

但它变得复杂,因为我有一个位置,一个枢轴位置(并不总是以图像为中心)和一个旋转。我搜索过,但没有找到任何关于这个问题的帖子,虽然这是一个非常有用的功能。

到目前为止,这是我的工作: https://jsfiddle.net/feo196nm/

function getBoundaryDraw(x, y, pivotX, pivotY, width, height, rotationRadian) {
  // getting the width and height
  var realWidth = Math.abs(Math.cos(rotationRadian)) * width + Math.abs(Math.sin(rotationRadian)) * height;
  var realHeight = Math.abs(Math.cos(rotationRadian)) * height + Math.abs(Math.sin(rotationRadian)) * width;

  // trying to get the position in canvas
  // I dont know what I'm doing **insert mad scientist dog here**
  var dx = pivotX - width / 2;
  var dy = pivotY - height / 2;
  var h = Math.sqrt(dx*dx+dy*dy);
  var da = rotationRadian + Math.asin(dx/h);
  var x = x + pivotX + width / 2 - realWidth / 2 - h * Math.cos(da);
  var y = y + pivotY + height / 2 - realHeight / 2 - h * Math.sin(da);

  // log result to have some debug
  console.log(dx, dy, h, da, x, y);

  // return random numbers
  return {
    x: x,
    y: y,
    width: realWidth,
    height: realHeight
  };
}

它不起作用......我几乎使用了所有的组合。请帮忙。 谢谢

1 个答案:

答案 0 :(得分:0)

以下是代码中的答案。计算x和y旋转的缩放轴,然后使用它们计算角落位置,然后找到所有角落的最小值和最大值以获得范围。

它适用于独立缩放的图像,包括负标度和零标度。图像原点可以在图像内部或外部,但不包括在范围内。

该演示显示了几个旋转的图像,其中包括刻度,原点设置为bothe轴及其边界框(范围)和所有图像的边界框。

希望这有帮助。

var canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 400;
var ctx = canvas.getContext("2d");
document.body.appendChild(canvas);

var image = new Image();
image.src = "https://i.stack.imgur.com/C7qq2.png?s=328&g=1";

// get the extent of an Image object with its
// origin at x,y (local origin cx,cy) scaled sx, sy
// and rotated ang.
// returns extent object.
// if you supply an extent will add to it if it is valid
function getImageBounds(img, x, y, cx, cy, sx, sy, ang, extent) {
    var xdx = Math.cos(ang) * sx; // x axis
    var xdy = Math.sin(ang) * sx;

    var ydx = -Math.sin(ang) * sy; // y axis
    var ydy = Math.cos(ang) * sy;

    if (extent === null || extent === undefined) { // create extent if does not exist
        extent = {
            top : Infinity,
            left : Infinity,
            right : -Infinity,
            bottom : -Infinity,
        };
    }
    var r = img.width - cx; // right coord
    var b = img.height - cy; // bottom
    var p = [// the 4 corner points [x,y,x,y...
        -cx * xdx + (-cy * ydx) + x,
        -cx * xdy + (-cy * ydy) + y,
        r * xdx + (-cy * ydx) + x,
        r * xdy + (-cy * ydy) + y,
        r * xdx + b * ydx + x,
        r * xdy + b * ydy + y,
         - cx * xdx + b * ydx + x,
         - cx * xdy + b * ydy + y,
    ];
    extent.left = Math.min(extent.left, p[0], p[2], p[4], p[6]);
    extent.top = Math.min(extent.top, p[1], p[3], p[5], p[7]);
    extent.right = Math.max(extent.right, p[0], p[2], p[4], p[6]);
    extent.bottom = Math.max(extent.bottom, p[1], p[3], p[5], p[7]);
    extent.width = extent.right - extent.left;
    extent.height = extent.bottom - extent.top;
    return extent;
}
function drawImage(img) { // draws image
    ctx.setTransform(1, 0, 0, 1, img.x, img.y)

    ctx.rotate(img.ang);
    ctx.scale(img.sx, img.sy);

    ctx.drawImage(image, -img.cx, -img.cy);
}

function createImg() { // image object factory
    return {
        x : 0,
        y : 0,
        cx : 0,
        cy : 0,
        sx : 1,
        sy : 1,
        ang : 0,
    };
}

var imgs = [createImg(), createImg(), createImg(), createImg(), createImg(), createImg(), createImg(), createImg()];
ctx.lineWidth = 2;

// primes 467, 479, 487, 491, 499,859, 863, 877, 881, 883,
function update(time) {
    ctx.fillStyle = "#888";
    ctx.fillRect(0, 0, 800, 400);
    if (image.complete) {
        time = time * 0.08;
        for (var i = 0; i < imgs.length; i += 1) { // move images properties semi random
            var g = imgs[i];
            var t1 = time / (467 + i * 877);
            var t2 = time / (863 + i * 499);
            g.x = Math.cos(t1) * 300 + 400;
            g.y = Math.sin(t2) * 150 + 200;
            t1 *= 5;
            t2 *= 5;
            g.sx = Math.cos(t1) * 0.32 * Math.cos(t2);
            g.sy = Math.sin(t2) * 0.32 * Math.cos(t1);
            t1 *= 5;
            t2 *= 5;
            g.cx = Math.cos(t1) * image.width * 0.5 + image.width * 0.5;
            g.cy = Math.sin(t2) * image.height * 0.5 + image.height * 0.5;
            g.ang += Math.sin(t2/6) * 0.1;
            t1 *= 5;
            t2 *= 5;
        }
        var extentAll = null; // to get extent all
        for (var i = 0; i < imgs.length; i += 1) { // draw image and get extent and show extent
            var g = imgs[i];
            drawImage(g);
            extentAll = getImageBounds(image, g.x, g.y, g.cx, g.cy, g.sx, g.sy, g.ang, extentAll);
            var extent = getImageBounds(image, g.x, g.y, g.cx, g.cy, g.sx, g.sy, g.ang);
            ctx.setTransform(1, 0, 0, 1, 0, 0); /// reset the transform
            ctx.strokeStyle = "red";
            ctx.strokeRect(extent.left, extent.top, extent.width, extent.height);
            ctx.fillStyle = "#FA0";
            ctx.fillRect(g.x - 5, g.y - 5, 10, 10);

        }
        ctx.strokeStyle = "blue";
        ctx.strokeRect(extentAll.left, extentAll.top, extentAll.width, extentAll.height);

    } else {
        ctx.font = "32px arial";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillText("Loading...", 400, 200);
    }

    // do it all again

    requestAnimationFrame(update);

}
requestAnimationFrame(update);