繁体   English   中英

绘制几乎直线

[英]Drawing an almost straight line

我得到的这些数组代表方形纸,如果你愿意,也可能是像素。 为了在该线程中保持一致,让“1”表示黑色单元格,“0”表示白色单元格。

现在,我想绘制从A点到B点的(黑色)直线。我不能只使用香草http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm ,因为我需要将每个单元格变黑如果它是一张方形纸并且你从方形A的中心到方形B的中心画一条线就会被击中。

所以这些应该如下:

+—+—+—+    +—+—+—+
|A| | |    |█| | |
+—+—+—+    +—+—+—+
| | | |    |█|█| |
+—+—+—+    +—+—+—+
| | | | →  | |█|█|
+—+—+—+    +—+—+—+
| | |B|    | | |█|
+—+—+—+    +—+—+—+

+—+—+—+    +—+—+—+
|A| | |    |█| | |
+—+—+—+    +—+—+—+
| | | | →  | |█| |
+—+—+—+    +—+—+—+
| | |B|    | | |█|
+—+—+—+    +—+—+—+

+—+—+—+    +—+—+—+
|A| | | →  |█|█| |
+—+—+—+    +—+—+—+
| | |B|    | |█|█|
+—+—+—+    +—+—+—+

随意想象这些草图更像方形,或者在一张方形纸上实际绘制草图! 它可能会搞清楚。

和往常一样,随意发布可能有用的任何内容。 谢谢!


(一个解法

也使用这个例子。 并使用我的框架使用的索引,所以它看起来与答案中的索引略有不同。

 X 0 1 2      X 0 1 2
Y +—+—+—+ →  Y +—+—+—+
0 |A| | | →  0 |█| | |
  +—+—+—+ →    +—+—+—+
1 | | | | →  1 |█|█| |
  +—+—+—+ →    +—+—+—+
2 | | | | →  2 | |█|█|
  +—+—+—+ →    +—+—+—+
3 | | |B| →  3 | | |█|
  +—+—+—+ →    +—+—+—+

A(0,0)= :( a1,a2),B是(2,3)= :( b1,b2),因此预期的点集是{(0,0),(0,1), (1,1),(1,2),(2,2),(2,3)}

首先,我们将在实际纸张上绘制的直线形式化。

Therefore first define constant m which holds our slope:

    (b2 - a2)
m = —————————
    (b1 - a1)

For arbitrary (A, B), the straight is now defined by:
g: y = (x - a1) · m + a2

and inverted:
ǵ: x = (y - a2) / m + a1

Note that for m = 0, the whole thing does fail. But a straight-to-the-right line does not only sound like a straightforward thing.

在这个例子中,直道是

m = 3/2
g: y = x * 3/2
ǵ: x = y * 2/3

我们将在边界框内使用“线值”(恰好在2个整数x和x + 1之间,广泛称为“x和a halve”)来提供这些函数。 首先,我们将介于a1和b1之间(饲料g),然后介于a2和b2之间(饲料ǵ):

g(0.5) = 1/2 * 3/2 = 0.75 // 1 < g(0.5) + 0.5 < 2
g(1.5) = 3/2 * 3/2 = 2.25 // 2 < g(1.5) + 0.5 < 3

ǵ(0.5) = 1/2 * 2/3 = 0.33 // 0 < ǵ(0.5) + 0.5 < 1
ǵ(1.5) = 3/2 * 2/3 = 1    // 1 < ǵ(1.5) + 0.5 < 2
ǵ(2.5) = 5/2 * 2/3 = 1.66 // 2 < ǵ(2.5) + 0.5 < 3
  1. 首先是指直线穿过第一条水平线上方的第一条垂直线(如“下方”所示)。 获得黑色的点:(0,1),(1,1)。
  2. 第二意味着直线与第二水平线上方的第二垂直线交叉。 变黑的要点:(1,2),(2,2)。
  3. 第三个意味着直线与第0个垂直线之后的​​第一条水平线(显示为“右边”)相交。 要点变黑:(0,0),(0,1)。
  4. 第四意味着直线在第一垂直线之后与第二水平线交叉。 变黑的要点:(1,1),(1,2)。
  5. 第五个意味着直线在第二个垂直线之后穿过第三个水平线。 获得黑色的要点:(2,2),(2,3)。

所有点:{(0,1),(1,1),(1,2),(2,2),(0,0), (0,1)(1,1)(1,2) )(2,2) ,(2,3)}

没有重复 :{(0,0),(0,1),(1,1),(1,2),(2,2),(2,3)}(这与预期完全一样)

  • 因此,对于穿过第x个水平线上方的第y垂直线的线,我们绘制(x-1,y)和(x,y)黑色。
  • 对于在第y个垂直线之后穿过第x个水平线的线,我们绘制(x,y-1)和(x,y)。
  • (在这里永远不会这样)对于第y个垂直方向横穿第x个水平右侧的线,我们绘制m> 0(x-1,y-1)和(x,y)。 如果m <0,则表示(x-1,y)和(x,y-1)

感觉对,这是我的想法。

有什么想法吗? 请评论!

~LDer~

让我们假设我们正在使用这个例子:

+—+—+—+    +—+—+—+
|A| | |    |█| | |
+—+—+—+    +—+—+—+
| | | |    |█|█| |
+—+—+—+    +—+—+—+
| | | | →  | |█|█|
+—+—+—+    +—+—+—+
| | |B|    | | |█|
+—+—+—+    +—+—+—+

这是一个3x4的矩形。

我们需要定义两个函数:
y(x) = 4 * (1 - x/3)
x(y) = 3 * (1 - y/4)

现在让我们将矩形内的所有整数xy传递给它们。
在每一步我们用坐标绘制黑色像素
[x; ceil(y(x)) - 1] [x; ceil(y(x)) - 1][ceil(x(y)) - 1; y - 1] [ceil(x(y)) - 1; y - 1]

y(0) == 4      # paint 0;3
y(1) == 2.(6)  # paint 1;2
y(2) == 1.(3)  # paint 2;1

x(0) == 3      # paint 2;-1 (-1 is not a valid pixel coordinate, 
               # so we may just throw away this, as there are no pixels below y=0)
x(1) == 2.25   # paint 2;0
x(2) == 1.5    # paint 1;1
x(3) == 0.75   # paint 0;2

x(y)y(x)函数都给出了对角线上一个点的第二个坐标,当我们将整数值传递给它们时,我们找到了对角线与网格的交点。
y函数将为我们提供每个垂直线和x函数的所有像素 - 低于每个水平线(这就是y - 1的原因)。 唯一的问题是角落交叉点,它可以通过一个有条件的解决。

初始化给出“正方形”坐标(x,y)的顶点。 对于每个方格, v1是左上角, v2是右上角, v3是右下角, v4是左下角。 计算你的线的方程y = a*x + b

算法

For each square do
    for each vertex of the square do
        calculate valueOfVertex = y - a*x - b
    if two valueOfVertex have an opposite sign
    then cellColor == 1
    else cellcolor == 0

输出应该是您所期望的。 唯一的问题是,如果一个valueOfVertex = 0而所有其他的都是严格正面或负面的。 但它很容易处理。

说明如果线穿过正方形(或像素),则可以找到两个不在线的同一侧的顶点。 因此,一个位于正半平面中,另一个位于负半平面中。

改进一些简单的技巧将阻止您测试边界框的每个方块。 如果你发现一个完全在半平面上的正方形,你可以丢弃一些正方形。 在您的示例中,如果测试的方格在线上方,则可以丢弃上方和右方的所有方格。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM