所以我想通过使用其中的行进方块算法在pygame中绘制隐式的心方程。我实现了游行广场的算法,但它不起作用?谁能帮我解决为什么吗?
import pygame
w = 500
h = 500
grid = []
for i in range(-h//2, h//2):
tempo = []
for j in range(-w//2, w//2):
tempo.append((i**2 + j**2 - 1)**3 - i**2 * j**3)
grid.append(tempo)
print(i)
def Bisection_Method(a, b, t, state, thresh = 0.001):
if state:
a -= w/2
b -= w/2
else:
a -= h/2
b -= h/2
mid = (a + b)/2
while abs(b - a) >= thresh:
a1 = 0
k1 = 0
if state:
i = a
r = mid
j = t
a1 = (i**2 + j**2 - 1)**3 - i**2 * j**3
k1 = (r**2 + j**2 - 1)**3 - r**2 * j**3
else:
i = t
r = mid
j = a
a1 = (i**2 + j**2 - 1)**3 - i**2 * j**3
k1 = (i**2 + r**2 - 1)**3 - i**2 * r**3)
if(k1 == 0):
return mid
mid = (a + b)/2
if(a1 * k1 < 0):
b = mid
else:
a = mid
if state:
mid += w/2
else:
mid += h/2
return mid
def MarchingSquares(i1, j1, i2, j2, i3, j3, i4, j4, plane):
finalP1 = pygame.math.Vector2(float('inf'), float('inf'))
finalP2 = pygame.math.Vector2(float('inf'), float('inf'))
finalP3 = pygame.math.Vector2(float('inf'), float('inf'))
finalP4 = pygame.math.Vector2(float('inf'), float('inf'))
if((plane[i1][j1] < 0 and plane[i2][j2] > 0 and plane[i3][j3] > 0 and plane[i4][j4] > 0) or (plane[i1][j1] > 0 and plane[i2][j2] < 0 and plane[i3][j3] < 0 and plane[i4][j4] < 0)):
finalP1 = pygame.math.Vector2(Bisection_Method(j1, j2, i1, True), i1)
finalP2 = pygame.math.Vector2(j1, Bisection_Method(i1, i3, j1, False))
elif((plane[i1][j1] > 0 and plane[i2][j2] < 0 and plane[i3][j3] > 0 and plane[i4][j4] > 0) or (plane[i1][j1] < 0 and plane[i2][j2] > 0 and plane[i3][j3] < 0 and plane[i4][j4] < 0)):
finalP1 = pygame.math.Vector2(Bisection_Method(j1, j2, i1, True), i1)
finalP2 = pygame.math.Vector2(j2, Bisection_Method(i4, i2, j2, False))
elif((plane[i1][j1] > 0 and plane[i2][j2] > 0 and plane[i3][j3] < 0 and plane[i4][j4] > 0) or (plane[i1][j1] < 0 and plane[i2][j2] < 0 and plane[i3][j3] > 0 and plane[i4][j4] < 0)):
finalP1 = pygame.math.Vector2(Bisection_Method(j3, j4, i3, True), i3)
finalP2 = pygame.math.Vector2(j3, Bisection_Method(i1, i3, j3, False))
elif((plane[i1][j1] > 0 and plane[i2][j2] > 0 and plane[i3][j3] > 0 and plane[i4][j4] < 0) or (plane[i1][j1] < 0 and plane[i2][j2] < 0 and plane[i3][j3] < 0 and plane[i4][j4] > 0)):
finalP1 = pygame.math.Vector2(Bisection_Method(j3, j4, i4, True), i4)
finalP2 = pygame.math.Vector2(j4, Bisection_Method(i4, i2, j4, False))
elif((plane[i1][j1] > 0 and plane[i2][j2] > 0 and plane[i3][j3] < 0 and plane[i4][j4] < 0) or (plane[i1][j1] < 0 and plane[i2][j2] < 0 and plane[i3][j3] > 0 and plane[i4][j4] > 0)):
finalP1 = pygame.math.Vector2(j1, Bisection_Method(i1, i3, j1, False))
finalP2 = pygame.math.Vector2(j2, Bisection_Method(i4, i2, j2, False))
elif((plane[i1][j1] > 0 and plane[i2][j2] > 0 and plane[i3][j3] > 0 and plane[i4][j4] < 0) or (plane[i1][j1] < 0 and plane[i2][j2] > 0 and plane[i3][j3] < 0 and plane[i4][j4] > 0)):
finalP1 = pygame.math.Vector2(Bisection_Method(j1, j2, i1, True), i1)
finalP2 = pygame.math.Vector2(Bisection_Method(j3, j4, i3, True), i3)
elif((plane[i1][j1] < 0 and plane[i2][j2] > 0 and plane[i3][j3] > 0 and plane[i4][j4] < 0) or (plane[i1][j1] > 0 and plane[i2][j2] < 0 and plane[i3][j3] < 0 and plane[i4][j4] > 0)):
i = (i1 + i3 - h)/2
j = (j1 + j3 - w)/2
state = (i**2 + j**2 - 1)**3 - i**2 * j**3
if((state < 0 and plane[i1][j1] < 0) or (state > 0 and plane[i1][j1] > 0)):
finalP1 = pygame.math.Vector2(j1, Bisection_Method(i1, i3, j1, False))
finalP2 = pygame.math.Vector2(Bisection_Method(j3, j4, i3, True), i3)
finalP3 = pygame.math.Vector2(Bisection_Method(j1, j2, i1, True), i1)
finalP4 = pygame.math.Vector2(j4, Bisection_Method(i2, i4, j4, False))
else:
finalP2 = pygame.math.Vector2(j1, Bisection_Method(i1, i3, j1, False))
finalP3 = pygame.math.Vector2(Bisection_Method(j3, j4, i3, True), i3)
finalP1 = pygame.math.Vector2(Bisection_Method(j1, j2, i1, True), i1)
finalP4 = pygame.math.Vector2(j4, Bisection_Method(i2, i4, j4, False))
return finalP1, finalP2, finalP3, finalP4
t = []
for i in range(h - 1):
for j in range(w - 1):
P1, P2, P3, P4 = MarchingSquares(i, j, i, j + 1, i + 1, j, i + 1, j + 1, grid)
t.append([P1, P2, P3, P4])
print("marching {i}")
# pygame setup
pygame.init()
screen = pygame.display.set_mode((w, h))
clock = pygame.time.Clock()
running = True
dt = 0
while running:
# poll for events
# pygame.QUIT event means the user clicked X to close your window
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# fill the screen with a color to wipe away anything from last frame
screen.fill("white")
for x in t:
pygame.draw.line(screen, "purple", x[0], x[1])
if(x[2].x != float('inf')):
pygame.draw.line(screen, "purple", x[2], x[3])
# flip() the display to put your work on screen
pygame.display.flip()
# limits FPS to 60
# dt is delta time in seconds since last frame, used for framerate-
# independent physics.
dt = clock.tick(60) / 1000
pygame.quit()
现在首先解释我的代码,我在整个屏幕上生成网格。之后,我通过 if else 语句检查 16 个案例来编写行进平方算法,并使用二分法作为求根算法。我给它一个状态参数,它决定我应该从 a 和 b 中提取什么值,True => 我正在 X 轴上进行操作,False => 我正在 Y 轴上进行操作。
这是结果:
import pygame
import numpy as np
pygame.init()
W, H = 500, 500
THRESHOLD = 0.001
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("Heart Curve")
def heart_function(x, y):
x, y = (x - 0.5) * 2.8, -(y - 0.45) * 2.8
return (x**2 + y**2 - 1)**3 - x**2 * y**3
def marching_squares(x, y, size):
corners = [
(x, y), (x + size, y),
(x, y + size), (x + size, y + size)
]
values = [heart_function(cx/W, cy/H) for cx, cy in corners]
case = sum([1 << i for i, v in enumerate(values) if v < 0])
lines = []
if case in (1, 14):
lines.append((x, y + size * values[0] / (values[0] - values[2])))
lines.append((x + size * values[0] / (values[0] - values[1]), y))
elif case in (2, 13):
lines.append((x + size, y + size * values[1] / (values[1] - values[3])))
lines.append((x + size * values[0] / (values[0] - values[1]), y))
elif case in (4, 11):
lines.append((x, y + size * values[0] / (values[0] - values[2])))
lines.append((x + size * values[2] / (values[2] - values[3]), y + size))
elif case in (7, 8):
lines.append((x + size, y + size * values[1] / (values[1] - values[3])))
lines.append((x + size * values[2] / (values[2] - values[3]), y + size))
elif case in (3, 12):
lines.append((x + size * values[0] / (values[0] - values[1]), y))
lines.append((x + size * values[2] / (values[2] - values[3]), y + size))
elif case in (5, 10):
lines.append((x, y + size * values[0] / (values[0] - values[2])))
lines.append((x + size, y + size * values[1] / (values[1] - values[3])))
elif case in (6, 9):
mid_x, mid_y = x/W + size/(2*W), y/H + size/(2*H)
if heart_function(mid_x, mid_y) < 0:
lines.append((x, y + size * values[0] / (values[0] - values[2])))
lines.append((x + size * values[2] / (values[2] - values[3]), y + size))
lines.append((x + size, y + size * values[1] / (values[1] - values[3])))
lines.append((x + size * values[0] / (values[0] - values[1]), y))
else:
lines.append((x, y + size * values[0] / (values[0] - values[2])))
lines.append((x + size * values[0] / (values[0] - values[1]), y))
lines.append((x + size, y + size * values[1] / (values[1] - values[3])))
lines.append((x + size * values[2] / (values[2] - values[3]), y + size))
return lines
def draw_heart():
screen.fill((255, 255, 255))
cell_size = 5
for x in range(0, W, cell_size):
for y in range(0, H, cell_size):
lines = marching_squares(x, y, cell_size)
for start, end in zip(lines[::2], lines[1::2]):
pygame.draw.line(screen, (255, 0, 0), start, end, 2)
if x % 50 == 0:
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
return True
def main():
clock = pygame.time.Clock()
running = True
heart_drawn = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if not heart_drawn:
heart_drawn = draw_heart()
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main()