Pygame画抗锯齿粗线
Pygame draw anti-aliased thick line
我曾经在 pygame 处画线(给定一些起点和终点),如下所示:pygame.draw.line(window, color_L1, X0, X1, 2)
,其中 2 定义线的粗细。
因为 .draw
不支持抗锯齿功能,所以我搬到了 .gfxdraw
和 pygame.gfxdraw.line(window, X0[0], X0[1], X1[0], X1[1], color_L1)
。
但是,这不允许我定义线的粗细。我怎样才能同时拥有厚度和抗锯齿?
我建议使用实心矩形,如下所示:https://www.pygame.org/docs/ref/gfxdraw.html#pygame.gfxdraw.rectangle。
您的代码将类似于:
thickLine = pygame.gfxdraw.rectangle(surface, rect, color)
然后记得填充表面。这是沿着:
thickLine.fill()
经过多次试验和错误,最佳方法如下:
首先,我们定义形状的中心点给定线的 X0_{x,y}
起点和 X1_{x,y}
终点:
center_L1 = (X0+X1) / 2.
然后求直线的斜率(角度):
length = 10 # Total length of line
thickness = 2
angle = math.atan2(X0[1] - X1[1], X0[0] - X1[0])
使用斜率和形状参数,您可以计算出方框末端的以下坐标:
UL = (center_L1[0] + (length/2.) * cos(angle) - (thickness/2.) * sin(angle),
center_L1[1] + (thickness/2.) * cos(angle) + (length/2.) * sin(angle))
UR = (center_L1[0] - (length/2.) * cos(angle) - (thickness/2.) * sin(angle),
center_L1[1] + (thickness/2.) * cos(angle) - (length/2.) * sin(angle))
BL = (center_L1[0] + (length/2.) * cos(angle) + (thickness/2.) * sin(angle),
center_L1[1] - (thickness/2.) * cos(angle) + (length/2.) * sin(angle))
BR = (center_L1[0] - (length/2.) * cos(angle) + (thickness/2.) * sin(angle),
center_L1[1] - (thickness/2.) * cos(angle) - (length/2.) * sin(angle))
使用计算出的坐标,我们绘制一个未填充的抗锯齿多边形(感谢@martineau),然后按照 pygame 的 documentation 中的建议填充它gfxdraw
用于绘制形状的模块。
pygame.gfxdraw.aapolygon(window, (UL, UR, BR, BL), color_L1)
pygame.gfxdraw.filled_polygon(window, (UL, UR, BR, BL), color_L1)
您还可以通过在原始线周围 +/- 1-N 像素处绘制线的副本来使用 pygame.draw.aalines()
函数做一些修改(是的,这不是非常有效,但是它在紧要关头起作用)。例如,假设我们有一个要绘制的线段列表 (self._segments
) 和宽度 (self._LINE_WIDTH
):
for segment in self._segments:
if len(segment) > 2:
for i in xrange(self._LINE_WIDTH):
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x,y+i) for x,y in segment))
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x,y-i) for x,y in segment))
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x+i,y) for x,y in segment))
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x-i,y) for x,y in segment))
您的回答可以完成工作,但我认为这是一种 better/more 可读的方式。这是借用你的答案,但你值得信赖。
from math import atan2, cos, degrees, radians, sin
def Move(rotation, steps, position):
"""Return coordinate position of an amount of steps in a direction."""
xPosition = cos(radians(rotation)) * steps + position[0]
yPosition = sin(radians(rotation)) * steps + position[1]
return (xPosition, yPosition)
def DrawThickLine(surface, point1, point2, thickness, color):
angle = degrees(atan2(point1[1] - point2[1], point1[0] - point2[0]))
vertices = list()
vertices.append(Move(angle-90, thickness, point1))
vertices.append(Move(angle+90, thickness, point1))
vertices.append(Move(angle+90, thickness, point2))
vertices.append(Move(angle-90, thickness, point2))
pygame.gfxdraw.aapolygon(surface, vertices, color)
pygame.gfxdraw.filled_polygon(surface, vertices, color)
请记住,这更多地将厚度视为半径而不是直径。如果你想让它更像直径,你可以将变量的每个实例除以 2。
所以无论如何,这会计算矩形的所有点并填充它。它通过转到每个点并通过旋转 90 度并向前移动来计算两个相邻点来完成此操作。
这是一段稍长的代码,但也许会对某些人有所帮助。
它使用矢量并在连接两点的直线的每一侧创建笔划。
def make_vector(pointA,pointB): #vector between two points
x1,y1,x2,y2 = pointA[0],pointA[1],pointB[0],pointB[1]
x,y = x2-x1,y2-y1
return x,y
def normalize_vector(vector): #sel explanatory
x, y = vector[0], vector[1]
u = math.sqrt(x ** 2 + y ** 2)
try:
return x / u, y / u
except:
return 0,0
def perp_vectorCL(vector): #creates a vector perpendicular to the first clockwise
x, y = vector[0], vector[1]
return y, -x
def perp_vectorCC(vector): #creates a vector perpendicular to the first counterclockwise
x, y = vector[0], vector[1]
return -y, x
def add_thickness(point,vector,thickness): #offsets a point by the vector
return point[0] + vector[0] * thickness, point[1] + vector[1] * thickness
def draw_line(surface,fill,thickness, start,end): #all draw instructions
x,y = make_vector(start,end)
x,y = normalize_vector((x,y))
sx1,sy1 = add_thickness(start,perp_vectorCC((x,y)),thickness//2)
ex1,ey1 = add_thickness(end,perp_vectorCC((x,y)),thickness//2)
pygame.gfxdraw.aapolygon(surface,(start,end,(ex1,ey1),(sx1,sy1)),fill)
pygame.gfxdraw.filled_polygon(surface, (start, end, (ex1, ey1), (sx1, sy1)), fill)
sx2, sy2 = add_thickness(start, perp_vectorCL((x, y)), thickness // 2)
ex2, ey2 = add_thickness(end, perp_vectorCL((x, y)), thickness//2)
pygame.gfxdraw.aapolygon(surface, (start, end, (ex2, ey2), (sx2, sy2)), fill)
pygame.gfxdraw.filled_polygon(surface, (start, end, (ex2, ey2), (sx2, sy2)), fill)
我曾经在 pygame 处画线(给定一些起点和终点),如下所示:pygame.draw.line(window, color_L1, X0, X1, 2)
,其中 2 定义线的粗细。
因为 .draw
不支持抗锯齿功能,所以我搬到了 .gfxdraw
和 pygame.gfxdraw.line(window, X0[0], X0[1], X1[0], X1[1], color_L1)
。
但是,这不允许我定义线的粗细。我怎样才能同时拥有厚度和抗锯齿?
我建议使用实心矩形,如下所示:https://www.pygame.org/docs/ref/gfxdraw.html#pygame.gfxdraw.rectangle。
您的代码将类似于:
thickLine = pygame.gfxdraw.rectangle(surface, rect, color)
然后记得填充表面。这是沿着:
thickLine.fill()
经过多次试验和错误,最佳方法如下:
首先,我们定义形状的中心点给定线的
X0_{x,y}
起点和X1_{x,y}
终点:center_L1 = (X0+X1) / 2.
然后求直线的斜率(角度):
length = 10 # Total length of line thickness = 2 angle = math.atan2(X0[1] - X1[1], X0[0] - X1[0])
使用斜率和形状参数,您可以计算出方框末端的以下坐标:
UL = (center_L1[0] + (length/2.) * cos(angle) - (thickness/2.) * sin(angle), center_L1[1] + (thickness/2.) * cos(angle) + (length/2.) * sin(angle)) UR = (center_L1[0] - (length/2.) * cos(angle) - (thickness/2.) * sin(angle), center_L1[1] + (thickness/2.) * cos(angle) - (length/2.) * sin(angle)) BL = (center_L1[0] + (length/2.) * cos(angle) + (thickness/2.) * sin(angle), center_L1[1] - (thickness/2.) * cos(angle) + (length/2.) * sin(angle)) BR = (center_L1[0] - (length/2.) * cos(angle) + (thickness/2.) * sin(angle), center_L1[1] - (thickness/2.) * cos(angle) - (length/2.) * sin(angle))
使用计算出的坐标,我们绘制一个未填充的抗锯齿多边形(感谢@martineau),然后按照 pygame 的 documentation 中的建议填充它
gfxdraw
用于绘制形状的模块。pygame.gfxdraw.aapolygon(window, (UL, UR, BR, BL), color_L1) pygame.gfxdraw.filled_polygon(window, (UL, UR, BR, BL), color_L1)
您还可以通过在原始线周围 +/- 1-N 像素处绘制线的副本来使用 pygame.draw.aalines()
函数做一些修改(是的,这不是非常有效,但是它在紧要关头起作用)。例如,假设我们有一个要绘制的线段列表 (self._segments
) 和宽度 (self._LINE_WIDTH
):
for segment in self._segments:
if len(segment) > 2:
for i in xrange(self._LINE_WIDTH):
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x,y+i) for x,y in segment))
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x,y-i) for x,y in segment))
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x+i,y) for x,y in segment))
pygame.draw.aalines(self._display, self._LINE_COLOR, False,
((x-i,y) for x,y in segment))
您的回答可以完成工作,但我认为这是一种 better/more 可读的方式。这是借用你的答案,但你值得信赖。
from math import atan2, cos, degrees, radians, sin
def Move(rotation, steps, position):
"""Return coordinate position of an amount of steps in a direction."""
xPosition = cos(radians(rotation)) * steps + position[0]
yPosition = sin(radians(rotation)) * steps + position[1]
return (xPosition, yPosition)
def DrawThickLine(surface, point1, point2, thickness, color):
angle = degrees(atan2(point1[1] - point2[1], point1[0] - point2[0]))
vertices = list()
vertices.append(Move(angle-90, thickness, point1))
vertices.append(Move(angle+90, thickness, point1))
vertices.append(Move(angle+90, thickness, point2))
vertices.append(Move(angle-90, thickness, point2))
pygame.gfxdraw.aapolygon(surface, vertices, color)
pygame.gfxdraw.filled_polygon(surface, vertices, color)
请记住,这更多地将厚度视为半径而不是直径。如果你想让它更像直径,你可以将变量的每个实例除以 2。
所以无论如何,这会计算矩形的所有点并填充它。它通过转到每个点并通过旋转 90 度并向前移动来计算两个相邻点来完成此操作。
这是一段稍长的代码,但也许会对某些人有所帮助。 它使用矢量并在连接两点的直线的每一侧创建笔划。
def make_vector(pointA,pointB): #vector between two points
x1,y1,x2,y2 = pointA[0],pointA[1],pointB[0],pointB[1]
x,y = x2-x1,y2-y1
return x,y
def normalize_vector(vector): #sel explanatory
x, y = vector[0], vector[1]
u = math.sqrt(x ** 2 + y ** 2)
try:
return x / u, y / u
except:
return 0,0
def perp_vectorCL(vector): #creates a vector perpendicular to the first clockwise
x, y = vector[0], vector[1]
return y, -x
def perp_vectorCC(vector): #creates a vector perpendicular to the first counterclockwise
x, y = vector[0], vector[1]
return -y, x
def add_thickness(point,vector,thickness): #offsets a point by the vector
return point[0] + vector[0] * thickness, point[1] + vector[1] * thickness
def draw_line(surface,fill,thickness, start,end): #all draw instructions
x,y = make_vector(start,end)
x,y = normalize_vector((x,y))
sx1,sy1 = add_thickness(start,perp_vectorCC((x,y)),thickness//2)
ex1,ey1 = add_thickness(end,perp_vectorCC((x,y)),thickness//2)
pygame.gfxdraw.aapolygon(surface,(start,end,(ex1,ey1),(sx1,sy1)),fill)
pygame.gfxdraw.filled_polygon(surface, (start, end, (ex1, ey1), (sx1, sy1)), fill)
sx2, sy2 = add_thickness(start, perp_vectorCL((x, y)), thickness // 2)
ex2, ey2 = add_thickness(end, perp_vectorCL((x, y)), thickness//2)
pygame.gfxdraw.aapolygon(surface, (start, end, (ex2, ey2), (sx2, sy2)), fill)
pygame.gfxdraw.filled_polygon(surface, (start, end, (ex2, ey2), (sx2, sy2)), fill)