我试图将生成Voronoi图的代码从Javascript转换为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
}
}
答案 0 :(得分:1)
好的,我仍然不确定原始javascript代码到底在做什么。然而,我设法根据我通过它学到的东西制作我自己的Voronoi Diagram生成器。这里是。谢谢大家的帮助。
"""
Working Voronoi Diagram Generator
"""
import random as r
import math as m
import pygame as pg
from pygame import gfxdraw
def makeMap(numPoints, mapSize):
# Generate random colors so I can see what's happened.
colors = []
for color in range(numPoints):
red = r.randint(0, 255)
grn = r.randint(0, 255)
blu = r.randint(0, 255)
colors.append((red, grn, blu))
# Generate the base points.
ct = 0
basePoints = []
for point in range(numPoints):
x = r.randint(0, mapSize)
y = r.randint(0, mapSize)
basePoints.append((x, y, colors[ct]))
ct += 1
# Generate all the other points on the map.
points = []
for x in range(mapSize):
for y in range(mapSize):
distance = mapSize * 2
for bp in basePoints:
newDistance = m.sqrt(((x - bp[0]) ** 2) + ((y - bp[1]) ** 2))
if newDistance < distance:
distance = newDistance
color = bp[2]
points.append([x, y, color])
return points
def colorer(surf, points):
for p in points:
gfxdraw.pixel(surf, p[0], p[1], p[2])
def main():
# Get points.
points = makeMap(20, 400)
print("points: ", points)
# Setup pygame screens.
pg.init()
size = (400, 400)
surf = pg.display.set_mode(size)
done = False
# Control fps of window.
clock = pg.time.Clock()
fps = 40
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
colorer(surf, points)
pg.display.flip()
# Control FPS.
clock.tick(fps)
if __name__ == "__main__":
main()
答案 1 :(得分:1)
这是固定版本。作者对点和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()