非常简单,给定一个点A(x,y)和另一个点B(m,n),我需要一个函数,它可以在任何可迭代对象中返回其间所有点的列表[k,z]。 / p>
我只对整数点感兴趣,所以不需要浮点数。
我需要最好的pythonic方式,因为这个“小”功能将会大量运行,并且是更大系统的关键支柱。
修改
@roippi,谢谢指出关于整数的问题。从下面的代码中,您可以看到我尝试跨越x轴并获得相应的y,然后对y执行相同的操作。我的一套点不会有任何非离散的坐标点,所以目前我可以忽略这个小缺陷
import itertools
#Vars
origin = {'x':0, 'y':0}
def slope(origin, target):
if target['x'] == origin['x']:
return 0
else:
m = (target['y'] - origin['y']) / (target['x'] - origin['x'])
return m
def line_eqn(origin, target):
x = origin['x']
y = origin['y']
c = -(slope(origin, target)*x - y)
c = y - (slope(origin, target)*x)
#return 'y = ' + str(slope(target)) + 'x + ' + str(c)
m = slope(origin, target)
return {'m':m, 'c':c}
def get_y(x, slope, c):
# y = mx + c
y = (slope*x) + c
return y
def get_x(y, slope, c):
#x = (y-c)/m
if slope == 0:
c = 0 #vertical lines never intersect with y-axis
if slope == 0:
slope = 1 #Do NOT divide by zero
x = (y - c)/slope
return x
def get_points(origin, target):
coord_list = []
#Step along x-axis
for i in range(origin['x'], target['x']+1):
eqn = line_eqn(origin, target)
y = get_y(i, eqn['m'], eqn['c'])
coord_list.append([i, y])
#Step along y-axis
for i in range(origin['y'], target['y']+1):
eqn = line_eqn(origin, target)
x = get_x(i, eqn['m'], eqn['c'])
coord_list.append([x, i])
#return unique list
return list(k for k,_ in itertools.groupby(sorted(coord_list)))
origin = {'x':1, 'y':3}
target = {'x':1, 'y':6}
print get_points(origin, target)
答案 0 :(得分:3)
def get_line(x1, y1, x2, y2):
points = []
issteep = abs(y2-y1) > abs(x2-x1)
if issteep:
x1, y1 = y1, x1
x2, y2 = y2, x2
rev = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
rev = True
deltax = x2 - x1
deltay = abs(y2-y1)
error = int(deltax / 2)
y = y1
ystep = None
if y1 < y2:
ystep = 1
else:
ystep = -1
for x in range(x1, x2 + 1):
if issteep:
points.append((y, x))
else:
points.append((x, y))
error -= deltay
if error < 0:
y += ystep
error += deltax
# Reverse the list if the coordinates were reversed
if rev:
points.reverse()
return points
答案 1 :(得分:0)
让我们假设您知道如何计算一条线的等式,所以你有
m
:你的渐变,
c
:你的常数
你还有2分:a
和b
,x值低于b的x值
for x in range(a[0], b[0]):
y = m*x + c
if isinstance(y, int) and (x,y) not in [a,b]:
print (x, y)
答案 2 :(得分:0)
def getLine(x1,y1,x2,y2):
if x1==x2: ## Perfectly horizontal line, can be solved easily
return [(x1,i) for i in range(y1,y2,int(abs(y2-y1)/(y2-y1)))]
else: ## More of a problem, ratios can be used instead
if x1>x2: ## If the line goes "backwards", flip the positions, to go "forwards" down it.
x=x1
x1=x2
x2=x
y=y1
y1=y2
y2=y
slope=(y2-y1)/(x2-x1) ## Calculate the slope of the line
line=[]
i=0
while x1+i < x2: ## Keep iterating until the end of the line is reached
i+=1
line.append((x1+i,y1+slope*i)) ## Add the next point on the line
return line ## Finally, return the line!
答案 3 :(得分:0)
对于任何有兴趣的人,这里的C ++相当于user1048839
的答案:
std::vector<std::tuple<int, int>> bresenhamsLineGeneration(int x1, int y1, int x2, int y2) {
std::vector<std::tuple<int, int>> points;
bool issteep = (abs(y2 - y1) > abs(x2 - x1));
if (issteep) {
std::swap(x1, y1);
std::swap(x2, y2);
}
bool rev = false;
if (x1 > x2) {
std::swap(x1, x2);
std::swap(y1, y2);
rev = true;
}
int deltax = x2 - x1;
int deltay = abs(y2 - y1);
int error = int(deltax / 2);
int y = y1;
int ystep;
if (y1 < y2) {
ystep = 1;
} else {
ystep = -1;
}
for (int x = x1; x < x2 + 1; ++x) {
if (issteep) {
std::tuple<int, int> pt = std::make_tuple(y, x);
points.emplace_back(pt);
} else {
std::tuple<int, int> pt = std::make_tuple(x, y);
points.emplace_back(pt);
}
error -= deltay;
if (error < 0) {
y += ystep;
error += deltax;
}
}
// Reverse the list if the coordinates were reversed
if (rev) {
std::reverse(points.begin(), points.end());
}
return points;
}
答案 4 :(得分:-1)
Bresenham线段或其变体与参数方程有关
X = X0 + t.Dx
Y = Y0 + t.Dy,
其中Dx = X1-X0且Dy = Y1-Y0,t是[0,1]中的参数。
事实证明,这个等式可以写成整数格,如
X = X0 + (T.Dx) \ D
Y = Y0 + (T.Dy) \ D,
其中\表示整数除法,D = Max(| Dx |,| Dy |),t是[0,D]范围内的整数。
正如您所看到的,根据Dx和Dy中的哪一个具有最大绝对值以及它具有什么符号,其中一个等式可以简化为X = X0 + T(现在我们假设Dx> = = Dy> = 0)。
要实现这一点,您有三个选择:
使用Y方程的浮点数,Y = Y0 + T.dy,其中dy = Dy / D,最好将结果四舍五入以获得更好的对称性;当你增加T时,用Y + = dy更新;
使用斜率的定点表示,选择2的幂进行缩放,设2 ^ B;设置Y&#39; = Y0&lt;&lt; B,Dy&#39; =(Dy <&lt; B)\ D;每次执行Y&#39; + = D&#39;时,检索Y = Y&#39; &GT;&GT;乙
使用纯整数运算。
在整数运算的情况下,通过计算Y0 +(T.Dy + D / 2)\ D而不是Y0 +(T.Dy \ D),可以轻松获得舍入效果。实际上,当你除以D时,这相当于Y0 + T.dy + 1/2。
分部是一个缓慢的操作。您可以通过一个简单的技巧进行交易以进行比较:每当T.Dy增加D时,Y增加1.您可以保持&#34;余数&#34;变量,等于(T.Dy)模D(或T.Dy + D / 2,用于舍入),并在每次超过D时将其减去D.
Y= Y0
R= 0
for X in range(X0, X1 + 1):
# Pixel(X, Y)
R+= Dy
if R >= D:
R-= D
Y+= 1
对于优化良好的版本,您应该分别考虑对应于Dx和Dy符号组合的九种情况( - ,0,+)。
答案 5 :(得分:-3)
我把这看作是一个学习c的项目。直线的整数值遵循此模式。主要数字水平,一个跨越一个重复n次,然后是次要数字水平一个跨越一个。次要号码是主要号码的一个或多个。主要数字实际上是渐变,次要数字纠正了舍入。