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

画布:你会如何使用Bresenham的线算法在两点之间正确插值?

南门棋
2023-03-14

我正在制作一个简单的HTML5画布绘图应用程序,每次鼠标移动时,都会在x和y位置放置一个圆圈。(非常常见但尚未解决的)问题是:当鼠标移动得非常快(比如比鼠标移动事件触发得更快)时,圆圈之间就有了空间。

我使用了Bresenham的直线算法,在一定程度上成功地在间隙之间画出了圆圈。然而,我遇到了另一个问题:当颜色是半透明的时候,我会无意中淡出到更深的效果。

这里有一个例子:

我不明白为什么会这样。如何使用Bresenham的直线算法在两点之间正确插值?还是其他算法?

这是我的代码:http://jsfiddle.net/E5NBs/

var x = null;
var y = null;
var prevX = null;
var prevY = null;
var spacing = 3;
var drawing = false;
var size = 5;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');

function createFlow(x1, y1, x2, y2, callback) {
    var dx = x2 - x1;
    var sx = 1;
    var dy = y2 - y1;
    var sy = 1;
    var space = 0;

    if (dx < 0) {
        sx = -1;
        dx = -dx;
    }

    if (dy < 0) {
        sy = -1;
        dy = -dy;
    }

    dx = dx << 1;
    dy = dy << 1;

    if (dy < dx) {
        var fraction = dy - (dx >> 1);

        while (x1 != x2) {
            if (fraction >= 0) {
                y1 += sy;
                fraction -= dx;
            }

            fraction += dy;
            x1 += sx;

            if (space == spacing) {
                callback(x1, y1);
                space = 0;
            } else {
                space += 1;
            }
        }
    } else {
        var fraction = dx - (dy >> 1);

        while (y1 != y2) {
            if (fraction >= 0) {
                x1 += sx;
                fraction -= dy;
            }

            fraction += dx;
            y1 += sy;

            if (space == spacing) {
                callback(x1, y1);
                space = 0;
            } else {
                space += 1;
            }
        }
    }

    callback(x1, y1);
}

context.fillStyle = '#FFFFFF';
context.fillRect(0, 0, 500, 400);

canvas.onmousemove = function(event) {
    x = parseInt(this.offsetLeft);
    y = parseInt(this.offsetTop);

    if (this.offsetParent != null) {
        x += parseInt(this.offsetParent.offsetLeft);
        y += parseInt(this.offsetParent.offsetTop);
    }

    if (navigator.appVersion.indexOf('MSIE') != -1) {
        x = (event.clientX + document.body.scrollLeft) - x;
        y = (event.clientY + document.body.scrollTop) - y;
    } else {
        x = event.pageX - x;
        y = event.pageY - y;
    }

    context.beginPath();
    if (drawing == true) {
        if (((x - prevX) >= spacing || (y - prevY) >= spacing) || (prevX - x) >= spacing || (prevY - y) >= spacing) {
            createFlow(x, y, prevX, prevY, function(x, y) {
                context.fillStyle = 'rgba(0, 0, 0, 0.1)';
                context.arc(x, y, size, 0, 2 * Math.PI, false);
                context.fill();
            });

            prevX = x, prevY = y;
        }
    } else {
        prevX = x, prevY = y;
    }
};

canvas.onmousedown = function() {
    drawing = true;
};

canvas.onmouseup = function() {
    drawing = false;
};

共有3个答案

庄经国
2023-03-14

我已经想通了。

"context.beginPath();"需要在createFlow回调函数中,如下所示:

createFlow(x, y, prevX, prevY, function(x, y) {
    context.beginPath();
    context.fillStyle = 'rgba(0, 0, 0, 0.1)';
    context.arc(x, y, size, 0, 2 * Math.PI, false);
    context.fill();
});
公西英叡
2023-03-14

如果我理解得很好,你希望每个点上都有rgba(0, 0, 0, 0.1)。如果是这样,那么你可以在绘制新点之前清除该点。

// this is bad way to clear the point, just I don't know canvas so well
context.fillStyle = 'rgba(255, 255, 255, 1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();

context.fillStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
空正豪
2023-03-14

HTML画布支持分数/浮点坐标,因此使用基于整数坐标的像素画布算法是不必要的,甚至可能被认为是适得其反的。

一个简单、通用的解决方案应该是这样的:

    when mouse_down:
      x = mouse_x
      y = mouse_y
      draw_circle(x, y)
      while mouse_down:
        when mouse_moved:
          xp = mouse_x
          yp = mouse_y
          if (x != xp or y != yp):
            dir = atan2(yp - y, xp - x)
            dist = sqrt(pow(xp - x, 2) + pow(yp - y, 2))
            while (dist > 0):
              x = x + cos(dir)
              y = y + sin(dir)
              draw_circle(x, y)
              dist = dist - 1

也就是说,每当鼠标移动到与最后绘制的圆的位置不同的位置时,都要用距离为1的步向新位置走去。

 类似资料:
  • 我开始认为我只是无法看到显而易见的事情。 给定下面的代码,我想从坐标[x1,y1]到[x2,y2]画一条线。 从图中我可以看到这条线从锚点[x1,y1]开始,但是我必须输入宽度和高度,而不是目标点的坐标。但是目标坐标的y分量小于起始坐标的y分量,所以我尝试将高度设置为负值,这导致PowerPoint试图打开生成的PPTX文档时出错(“PowerPoint发现out.pptx文件中的内容有问题”);

  • 问题内容: 我正在用Matplotlib绘制两个子图,基本上如下: 我可以在这两个子图之间画线吗?我该怎么办? 问题答案: 在许多情况下,其他答案的解决方案不是最优的(因为它们只有在计算出点数后未对图进行任何更改的情况下才会起作用)。 更好的解决方案将使用特别设计的:

  • 问题内容: 我正在做一些Java加密,无法找到正确使用PBEWithHmacSHA512AndAES_256算法的方法。 加密似乎可以正常工作,但是我无法正确初始化解密密码。 下面是演示该问题的简短程序。特别是,请参见“问题”注释。 注意:我已经看到了这个非常有用的答案,并且可以使用该方案使事情正常进行,但是我很想知道我在这里做错了什么。 问题答案: // PROBLEM: If I pass “

  • 当使用Bresenham line drawing algorithm绘制直线时,如果该直线可能不在要写入的位图的边界内,则可以剪裁结果,使其适合要写入的图像的轴对齐边界。 虽然可以先将线剪裁到矩形上,然后画线。这并不理想,因为它通常会给线一个稍微不同的斜度(假设正在使用int协弦)。 既然这是一个如此原始的操作,是否有既定的方法来剪裁线条,同时保持相同的形状? 如果有帮助的话,这里是算法的参考实

  • 问题内容: 我需要创建一个类来计算两点之间的距离。我被困住了,我是一个完全的初学者。这是我的课程: 第二课。 我不确定如何在两个定义的点之间获取点对象(中间点)。 我可以创建点对象,但不确定如何通过位于这两个点对象之间的方法返回点对象。 问题答案: 平面上的两个点(x1,y1)和(x2,y2)之间的距离为: 但是,如果您想要的只是两个点的中点,则应将中点函数更改为: 这将返回一个全新的点对象,其点

  • 我正在基于谷歌的hello_ar_java示例应用程序,围绕这个Agora ARcore演示构建我的应用程序。 此应用程序将捕获用户的点击,并检查是否在场景中找到任何平面。如果是,请在该点创建一个锚点。 我想在各种锚之间画一条线。 我在网上找到的所有东西都使用场景窗体和片段。 目前,我已经设法实现了没有arFraium但行不显示,可能是因为这种方法,我不知道如何取代没有arFrature: 要在我