Sebastion Lagueによるビデオは、Bridsonのアルゴリズムを非常によく説明しています。
単純化しすぎると、
radius / sqrt(2)の辺を持つセルグリッドを作成します。
最初のポイントを配置し、スポーンポイントとしてリストします。
ポイントをグリッドのセルに配置します。
スポーンポイントについては、半径と2 *半径の間のポイントをスポーンします。
新しい点のセルから2単位離れたセルを見てください。
他の点が含まれている場合は、距離を比較します。
半径よりも新しい点に近い点がある場合、新しい点は無効です。
新しいポイントが有効な場合、新しいポイントはスポーンポイントとしてリストされ、グリッドのセルに配置されます。
スポーンポイントがスポーンする無効なポイントが多すぎると、スポーンポイントが削除されてポイントに変わります。
スポーンポイントがなくなるまで繰り返します。
リターンポイント。
基本的にPython3.7.2とpygame1.7〜で同じことを書き留めましたが、タイトルで述べたように、再帰的な煉獄で立ち往生しています。
このアルゴリズムに1つのPoint()クラスを使用しました。これは、pygame.Vector2()が存在することを考えると冗長に見えるかもしれませんが、このクラスが機能する必要がある別のアルゴリズム(無限の頂点を持つDelaunay)にいくつかの要素が必要でした。
簡単にするために、Delaunay固有の要素をすべて切り取り、このアルゴリズムに必要なこのクラスの最低限の要素を示します。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def DistanceToSquared(self,other):
return (self.x-other.x)**2 + (self.y-other.y)**2
Bridsonのアルゴリズムに関連するコードは次のとおりです。
def PoissonDiskSampling(width, height, radius, startPos = None, spawnAttempts = 10):
if startPos == None:
startPos = [width//2,height//2]
cellSize = radius / math.sqrt(2)
cellNumberX = int(width // cellSize + 1) # Initialise a cells grid for optimisation
cellNumberY = int(height // cellSize + 1)
cellGrid = [[None for x in range(cellNumberX)] for y in range(cellNumberY)]
startingPoint = Point(startPos[0],startPos[1]) # Add an iniial point for spawning purposes
cellGrid[startingPoint.x//radius][startingPoint.y//radius] = startingPoint
points = [startingPoint] # Initialise 2 lists tracking all points and active points
spawnpoints = [startingPoint]
while len(spawnpoints) > 0:
spawnIndex = random.randint(0,len(spawnpoints)-1)
spawnpoint = spawnpoints[spawnIndex]
spawned = False
for i in range(spawnAttempts):
r = random.uniform(radius,2*radius)
radian = random.uniform(0,2*math.pi)
newPoint = Point(spawnpoint.x + r*math.cos(radian),
spawnpoint.y + r*math.sin(radian))
if 0 <= newPoint.x <= width and 0 <= newPoint.y <= height:
isValid = True
else:
continue
newPointIndex = [int(newPoint.x//cellSize), int(newPoint.y//cellSize)]
neighbours = FindNeighbours(cellNumberX,cellNumberY,newPointIndex,cellGrid)
for neighbour in neighbours:
if newPoint.DistanceToSquared(neighbour) < radius**2:
isValid = False
break
if isValid:
points.append(newPoint)
spawnpoints.append(newPoint)
spawned = True
break
else:
continue
if spawned == False:
spawnpoints.remove(spawnpoint)
return points
def FindNeighbours(cellNumberX, cellNumberY, index, cellGrid):
neighbours = []
for cellX in range(max(0,(index[0]-2)), min(cellNumberX,(index[1]+2))):
for cellY in range(max(0,(index[0]-2)), min(cellNumberY,(index[1]+2))):
if cellGrid[cellX][cellY] != None:
neighbours.append(cellGrid[cellX][cellY])
return neighbours
助けてください。
おそらく最も重要なステップがコードにありません。
- 新しいポイントが有効な場合、新しいポイントはスポーンポイントとしてリストされ、グリッドのセルに配置されます。
cellGrid
有効な場合は、ポイントを追加することをお勧めします。
if isValid:
cellGrid[newPointIndex[0]][newPointIndex[1]] = newPoint
points.append(newPoint)
spawnpoints.append(newPoint)
spawned = True
break
さらに、newPointIndex
ポイントを追加する前に、インデックスのあるセルがまだ占有されていないかどうかを確認する必要があります。
newPointIndex = [int(newPoint.x/cellSize), int(newPoint.y/cellSize)]
if cellGrid[newPointIndex[0]][newPointIndex[1]] != None:
continue
neighbours = FindNeighbours(cellNumberX,cellNumberY,newPointIndex,cellGrid)
最後に、関数に問題がありますFindNeighbours
。range(start, stop)
のxの範囲を作成しますstart <= x < stop
。
したがって、停止はでindex[0]+3
はなくする必要がありindex[0]+2
ます。
さらに2つのネストされた制御範囲for
ループは、両方から実行x-2
するy+2
よりもむしろからx-2
のx+2
それぞれからy-2
のy+2
:
for cellX in range(max(0,(index[0]-2)), min(cellNumberX,(index[1]+2))): for cellY in range(max(0,(index[0]-2)), min(cellNumberY,(index[1]+2)))
固定関数は次のとおりである必要があります。
def FindNeighbours(cellNumberX, cellNumberY, index, cellGrid):
neighbours = []
for cellX in range(max(0, index[0]-2), min(cellNumberX, index[0]+3)):
for cellY in range(max(0, index[1]-2), min(cellNumberY, index[1]+3)):
if cellGrid[cellX][cellY] != None:
neighbours.append(cellGrid[cellX][cellY])
return neighbours
サイズが300x 300、半径が15の場合は、結果を参照してください。
spawnpoints
ランダムな点ではなく、常に最初の点を使用すると、さらに良い結果が得られます。
# spawnIndex = random.randint(0,len(spawnpoints)-1)
spawnIndex = 0 # 0 rather than random
spawnpoint = spawnpoints[spawnIndex]
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加