绘制几乎直线

时间:2013-07-30 11:53:21

标签: python drawing geometry pixel

我得到的这些数组代表方形纸,或者你喜欢的像素。为了在该线程中保持一致,让“1”表示黑色单元格,“0”表示白色单元格。

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

所以这些应该如下:

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

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

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

随意想象这些草图更像方形,或者在一张方形纸上实际绘制草图!它可能会让事情变得清晰。

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


(A)解决方案

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

 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)。
  6. 所有积分:{(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&gt;绘画。 0(x-1,y-1)和(x,y)。如果m < 0,表示(x-1,y)和(x,y-1)

    感觉正确,这是我的想法。

    有什么想法?请评论!

    ~LDer~

2 个答案:

答案 0 :(得分:2)

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

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

这是一个矩形3x4

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

现在让我们将矩形内的所有整数xy传递给它们 在每一步,我们用坐标
来绘制黑色像素 [x; ceil(y(x)) - 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的原因)。唯一的问题是角落交叉点,它可以通过一个有条件的解决。

答案 1 :(得分: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和所有其他问题都是严格的正面或负面的。但它很容易处理。

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

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