-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbresenham.py
83 lines (73 loc) · 2.21 KB
/
bresenham.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import numpy as np
from numba import jit
# Reference: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
@jit(nopython=True, nogil=True, cache=True, fastmath=True)
def _make_line_low(x0: int, y0: int, x1: int, y1: int):
dx = x1 - x0
dy = y1 - y0
my = max(y0, y1)
yi = 1
if dy < 0:
yi = -1
dy = -dy
D = 2 * dy - dx
y = y0
n = dx + 1
line = np.zeros((n, 2), dtype=np.int32)
for idx, x in enumerate(range(x0, x1)):
line[idx] = [y, x]
if D > 0:
y += yi
if y > my:
y = my
D += 2 * (dy - dx)
else:
D += 2 * dy
line[-1] = [y1, x1]
return line
@jit(nopython=True, nogil=True, cache=True, fastmath=True)
def _make_line_high(x0: int, y0: int, x1: int, y1: int):
dx = x1 - x0
dy = y1 - y0
mx = max(x0, x1)
xi = 1
if dx < 0:
xi = -1
dx = -dx
D = 2 * dx - dy
x = x0
n = dy + 1
line = np.zeros((n, 2), dtype=np.int32)
for idx, y in enumerate(range(y0, y1)):
line[idx] = [y, x]
if D > 0:
x += xi
if x > mx:
x = mx
D += 2 * (dx - dy)
else:
D += 2 * dx
line[-1] = [y1, x1]
return line
@jit(nopython=True, nogil=True, cache=True, fastmath=True)
def make_line(x0: int, y0: int, x1: int, y1: int) -> np.array:
"""
Return a rasterised line between pairs of coordinates on a 2d integer grid according to the Bresenham algorithm.
Includes both start and end coordinates. Guaranteed to stay within the bounds set by endpoints.
Returns a numpy array of (y,x) line coordinates with shape (n, 2) where n is the number of points in the line.
:param x0: start x coordinate
:param y0: start y coordinate
:param x1: end x coordinate
:param y1: end y coordinate
:return: numpy array of (y,x) line coordinates
"""
if abs(y1 - y0) < abs(x1 - x0):
if x0 > x1:
return _make_line_low(x1, y1, x0, y0)
else:
return _make_line_low(x0, y0, x1, y1)
else:
if y0 > y1:
return _make_line_high(x1, y1, x0, y0)
else:
return _make_line_high(x0, y0, x1, y1)