简体   繁体   English

绘制几乎直线

[英]Drawing an almost straight line

I got these arrays representing squared paper, or maybe pixels if you like. 我得到的这些数组代表方形纸,如果你愿意,也可能是像素。 For consistency in this thread, let "1" represent a black cell, "0" represent a white cell. 为了在该线程中保持一致,让“1”表示黑色单元格,“0”表示白色单元格。

Now, I want to draw a (black) straight line from point A to point B. I can't just use a vanilla http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm , because I need to blacken every cell that would be hit if it were a sheet of squared paper and you drew a line from the center of square A to the center of square B. 现在,我想绘制从A点到B点的(黑色)直线。我不能只使用香草http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm ,因为我需要将每个单元格变黑如果它是一张方形纸并且你从方形A的中心到方形B的中心画一条线就会被击中。

So these should work out as follows: 所以这些应该如下:

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

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

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

Feel free to imagine these sketches to be more square-like, or to actually sketch that on a sheet of squared paper! 随意想象这些草图更像方形,或者在一张方形纸上实际绘制草图! It might clear things up. 它可能会搞清楚。

And like always, feel free to post anything that might help. 和往常一样,随意发布可能有用的任何内容。 Thanks! 谢谢!


(A) Solution (一个解法

Also using this example. 也使用这个例子。 And using the indices as they're used by my framework, so it looks a little different than the one in the answers. 并使用我的框架使用的索引,所以它看起来与答案中的索引略有不同。

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

A being (0,0) =: (a1,a2), B being (2,3) =: (b1,b2), so the expected set of points is {(0,0), (0,1), (1,1), (1,2), (2,2), (2,3)} A(0,0)= :( a1,a2),B是(2,3)= :( b1,b2),因此预期的点集是{(0,0),(0,1), (1,1),(1,2),(2,2),(2,3)}

First, we formalize the straight which would be drawn on actual paper. 首先,我们将在实际纸张上绘制的直线形式化。

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.

in this example, the straights are 在这个例子中,直道是

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

We'll feed these functions with the "line values" (exactly between 2 integers x and x+1, widely known as "x and a halve") within our bounding box. 我们将在边界框内使用“线值”(恰好在2个整数x和x + 1之间,广泛称为“x和a halve”)来提供这些函数。 So first we'll go between a1 and b1 (feed g), then between a2 and b2 (feed ǵ): 首先,我们将介于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. First means the straight crosses the first vertical line above (shown as "below") the first horizontal line. 首先是指直线穿过第一条水平线上方的第一条垂直线(如“下方”所示)。 Points to get black: (0,1), (1,1). 获得黑色的点:(0,1),(1,1)。
  2. Second means the straight crosses the second vertical line above the second horizontal line. 第二意味着直线与第二水平线上方的第二垂直线交叉。 Points to get black: (1,2), (2,2). 变黑的要点:(1,2),(2,2)。
  3. Third means the straight crosses the first horizontal line after (shown as "right of") the 0th vertical line. 第三个意味着直线与第0个垂直线之后的​​第一条水平线(显示为“右边”)相交。 Points to get black: (0,0), (0,1). 要点变黑:(0,0),(0,1)。
  4. Fourth means the straight crosses the second horizontal line after the first vertical line. 第四意味着直线在第一垂直线之后与第二水平线交叉。 Points to get black: (1,1), (1,2). 变黑的要点:(1,1),(1,2)。
  5. Fifth means the straight crosses the third horizontal line after the second vertical line. 第五个意味着直线在第二个垂直线之后穿过第三个水平线。 Points to get black: (2,2), (2,3). 获得黑色的要点:(2,2),(2,3)。

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

Without duplicates : {(0,0), (0,1), (1,1), (1,2), (2,2), (2,3)} (which is exactly as expected) 没有重复 :{(0,0),(0,1),(1,1),(1,2),(2,2),(2,3)}(这与预期完全一样)

  • So for a line that crosses the y'th vertical line above the x'th horizontal one, we paint (x-1,y) and (x,y) black. 因此,对于穿过第x个水平线上方的第y垂直线的线,我们绘制(x-1,y)和(x,y)黑色。
  • While for a line that crosses the x'th horizontal line after the y'th vertical one, we paint (x,y-1) and (x,y). 对于在第y个垂直线之后穿过第x个水平线的线,我们绘制(x,y-1)和(x,y)。
  • (never true here) And for a line that crosses the x'th horizontal right on the y'th vertical one, we paint for m > 0 (x-1,y-1) and (x,y). (在这里永远不会这样)对于第y个垂直方向横穿第x个水平右侧的线,我们绘制m> 0(x-1,y-1)和(x,y)。 If m < 0, that'd make for (x-1,y) and (x,y-1) 如果m <0,则表示(x-1,y)和(x,y-1)

Feels about right, that's my idea. 感觉对,这是我的想法。

Any thoughts? 有什么想法吗? Please comment! 请评论!

~ LDer ~ ~LDer~

Let's assume that we're working with this example: 让我们假设我们正在使用这个例子:

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

It's a rectangle 3x4 . 这是一个3x4的矩形。

We need to define two functions: 我们需要定义两个函数:
y(x) = 4 * (1 - x/3)
x(y) = 3 * (1 - y/4) . x(y) = 3 * (1 - y/4)

Now let's pass to them all integer x and y inside our rectangle. 现在让我们将矩形内的所有整数xy传递给它们。
On each step we are painting black pixel with coordinates 在每一步我们用坐标绘制黑色像素
[x; ceil(y(x)) - 1] [x; ceil(y(x)) - 1] and [ceil(x(y)) - 1; y - 1] [x; ceil(y(x)) - 1][ceil(x(y)) - 1; y - 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

Both x(y) and y(x) functions are giving you second coordinate of a point on the diagonal, and when we're passing integer values to them, we're finding intersections of our diagonal with the grid. x(y)y(x)函数都给出了对角线上一个点的第二个坐标,当我们将整数值传递给它们时,我们找到了对角线与网格的交点。
The y -function would give us all pixels that are right to every vertical line and the x -function - that are below every horizontal (that's why y - 1 ). y函数将为我们提供每个垂直线和x函数的所有像素 - 低于每个水平线(这就是y - 1的原因)。 The only issue will be with corner intersections, it can be solved by one more conditional. 唯一的问题是角落交叉点,它可以通过一个有条件的解决。

Initialisation Give the vertices of your "squares" coordinates (x,y) . 初始化给出“正方形”坐标(x,y)的顶点。 For each square, v1 is top left, v2 top right, v3 bottom right and v4 bottom left. 对于每个方格, v1是左上角, v2是右上角, v3是右下角, v4是左下角。 Calculate the equation of your line y = a*x + b . 计算你的线的方程y = a*x + b

Algorithm 算法

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

The output should be what you expect. 输出应该是您所期望的。 The only problem maybe if one valueOfVertex = 0 and all the others are stricly positive or negative. 唯一的问题是,如果一个valueOfVertex = 0而所有其他的都是严格正面或负面的。 But it's easy to handle. 但它很容易处理。

Explanation If the line crosses the square (or pixel), you can find two vertice which aren't on the same side of the line. 说明如果线穿过正方形(或像素),则可以找到两个不在线的同一侧的顶点。 So one lies in the positive half plane, the other in the negative half plane. 因此,一个位于正半平面中,另一个位于负半平面中。

Improvement Some simple tricks will prevent you from testing every square of the bounding box. 改进一些简单的技巧将阻止您测试边界框的每个方块。 If you find a square that is entirely in a half plane, you can discard some squares. 如果你发现一个完全在半平面上的正方形,你可以丢弃一些正方形。 In your examples, if the square tested is above the line, you can discard all the squares that are above and to the right. 在您的示例中,如果测试的方格在线上方,则可以丢弃上方和右方的所有方格。

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

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