我正在尝试将从Java生成Voronoi图的代码转换为Python。这是一个斗争,因为我不懂Javascript。我想我可以解决,但是我仍然遇到我不了解的问题。请帮助我找出我的代码有什么问题。
我编写的代码只是给了一个空白窗口。请帮助我生成一个Voronoi图。
按顺序,我有我的代码,然后是原始代码。
这是我在以下位置找到的网站的链接:
Procedural Generation Wiki
我的代码:
"""
Translated from javascript example at
http://pcg.wikidot.com/pcg-algorithm:voronoi-diagram
I have included the original comments.
My own comments are preceded by two hash-tags/pound-signs.
IE
# Original Javascript comments here
## My comments here
"""
import random
import pygame
from pygame import gfxdraw
# specify an empty points array
## I will use a list.
points = []
lines = []
# get a random number in range min, max -1
## No need for our own random number function.
## Just, import random, instead.
def definePoints(numPoints, mapSize):
# we want to take a group of points that will fit on our map at random
for typ in range(numPoints):
# here's the random points
x = random.randrange(0, mapSize)
y = random.randrange(0, mapSize)
# "type:" decides what point it is
# x, y: location
# citizens: the cells in our grid that belong to this point
## Can't use "type:" (without quotes) in python comments
## Since I don't know Javascript, I dunno what he's doing here.
## I'm just going to append lists inside points.
## order is: type, x, y, citizens
points.append([typ, x, y, []])
# brute force-y but it works
# for each cell in the grid
for x in range(mapSize):
for y in range(mapSize):
# find the nearest point
lowestDelta = (0, mapSize * mapSize)
for p in range(len(points)):
# for each point get the difference in distance
# between our point and the current cell
## I split the above comment into two so
## it would be less than 80 characters.
delta = abs(points[p][1] - x) + abs(points[p][2] - y)
# store the point nearest if it's closer than the last one
if delta < lowestDelta[1]:
lowestDelta = (p, delta)
# push the cell to the nearest point
## Okay, here's where I start getting confused.
## I dunno how to do whatever he's doing in Python.
for point in points:
if lowestDelta[0] == point[0]:
activePoint = point
dx = x - activePoint[1]
dy = y - activePoint[2]
# log delta in cell for drawing
## Again, not sure what he's doing here.
for point in points:
if activePoint == point:
point[3].append(dx)
point[3].append(dy)
return points
## all comments and code from here on are mine.
def main():
# Get points
points = definePoints(20, 400)
print("lines: ", lines)
# Setup pygame screens.
pygame.init()
size = (400, 400)
screen = pygame.display.set_mode(size)
white = (255, 255, 255)
done = False
# Control fps of window.
clock = pygame.time.Clock()
fps = 40
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
for point in points:
for p in point[3]:
# draw white wherever there's a point.
# pygame windows are black by default
gfxdraw.pixel(screen, point[1], point[2], white)
# controls FPS
clock.tick(fps)
if __name__ == "__main__":
main()
原始示例代码:
//specify an empty points array
var points = [];
//get a random number in range min, max - 1
function randRange(min, max) {
return Math.floor(Math.random() * ((max) - min) + min);
}
function definePoints(numPoints, mapSize) {
//we want to take a group of points that will fit on our map at random
for(var i = 0; i < numPoints; i++) {
//here's the random points
var x = randRange(0, mapSize);
var y = randRange(0, mapSize);
//type: decides which point it is
//x, y: location
//citizens: the cells in our grid that belong to this point
points.push({type: i, x: x, y: y, citizens: []});
}
//brute force-y but it works
//for each cell in the grid
for(var x = 0; x < mapSize; x++) {
for(var y = 0; y < mapSize; y++) {
//find the nearest point
var lowestDelta = {pointId: 0, delta: mapSize * mapSize};
for(var p = 0; p < points.length; p++) {
//for each point get the difference in distance between our point and the current cell
var delta = Math.abs(points[p].x - x) + Math.abs(points[p].y - y);
//store the point as nearest if it's closer than the last one
if(delta < lowestDelta.delta) {
lowestDelta = {pointId: p, delta: delta};
}
}
//push the cell to the nearest point
var activePoint = points[lowestDelta.pointId];
var dx = x - activePoint.x;
var dy = y - activePoint.y;
//log delta in cell for drawing
activePoint.citizens.push({
dx: dx,
dy: dy
});
}
}
}
definePoints(20, 40);
for(var point of points) {
for(var citizen of point.citizens) {
//set color of cell based on point
//draw cell at (point.x + citizen.dx) * cellSize, (point.y + citizen.dy) * cellSize
}
}
最佳答案
这是固定版本。作者对点和lowestDelta
使用字典/关联数组,但它也适用于列表和元组。我只更改了代码以“将单元格推到最近的点”,并在绘图循环中添加公民点的偏移量。顺便说一句,由于您只需要绘制一次点,因此可以在while循环之前执行,以使代码更高效。
import random
import pygame
from pygame import gfxdraw
def definePoints(numPoints, mapSize):
points = []
# we want to take a group of points that will fit on our map at random
for typ in range(numPoints):
# here's the random points
x = random.randrange(0, mapSize)
y = random.randrange(0, mapSize)
# "type:" decides what point it is
# x, y: location
# citizens: the cells in our grid that belong to this point
points.append([typ, x, y, []])
# brute force-y but it works
# for each cell in the grid
for x in range(mapSize):
for y in range(mapSize):
# find the nearest point
lowestDelta = (0, mapSize * mapSize)
for p in range(len(points)):
# for each point get the difference in distance
# between our point and the current cell
delta = abs(points[p][1] - x) + abs(points[p][2] - y)
# store the point nearest if it's closer than the last one
if delta < lowestDelta[1]:
lowestDelta = (p, delta)
# push the cell to the nearest point
activePoint = points[lowestDelta[0]]
dx = x - activePoint[1]
dy = y - activePoint[2]
activePoint[3].append((dx, dy))
return points
def main():
pygame.init()
size = (400, 400)
screen = pygame.display.set_mode(size)
white = pygame.Color('white')
done = False
clock = pygame.time.Clock()
fps = 40
points = definePoints(50, 400)
# Draw the points before the while loop starts. No need to draw them again.
for point in points:
# Use different random colors for the points.
color = (random.randrange(256), random.randrange(256),
random.randrange(256))
for p in point[3]:
# Draw the citizen points.
# Add the offset of the citizen to the positions of the points.
gfxdraw.pixel(screen, point[1]+p[0], point[2]+p[1], color)
# draw white wherever there's a point.
gfxdraw.pixel(screen, point[1], point[2], white)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
clock.tick(fps)
pygame.display.flip()
if __name__ == '__main__':
main()