I wrote an algorithm, that produces 2D Worley Noise in python. But it takes several seconds for a resolution with 400x400 Pixels. I tried to subdivide the space like here, but I am not able to implement it in Python. I also tried a different method to calculate the nearest point, but it did not work faster... How can I make it work faster?
class Point2D:
def __init__(self, x, y):
self.p = [x,y]
def x(self):
return(self.p[0])
def y(self):
return(self.p[1])
def distance(point1, point2):
import math
return(math.sqrt((point1.x()-point2.x())**2 + (point1.y()-point2.y())**2))
def getDistances(origin, li : list):
distances = []
for ll in li:
distances.append(Point2D.distance(origin, Point2D(ll[0], ll[1])))
return(distances)
class WorleyNoise:
def __init__(self, height, width, density):
self.height = height
self.width = width
self.density = density
def auto(self, option):
self.generatePoints()
self.calculateNoise(option)
self.showNoise()
def generatePoints(self):
import numpy as np
self.points = []
for _ in range(self.density):
self.points.append([np.random.randint(0, self.width,1)[0], np.random.randint(0, self.height,1)[0]])
def showPoints(self):
import matplotlib.pyplot as plt
plt.scatter([self.points[i][0] for i in range(len(self.points))], [self.points[l][1] for l in range(len(self.points))])
plt.show()
def calculateNoise(self, option):
import time
self.data = [[0] * self.width for _ in range(self.height)]
for h in range(self.height):
start = time.time()
for w in range(self.width):
self.distances = Point2D.getDistances(Point2D(w, h), self.points)
self.distances.sort()
self.data[h][w] = self.distances[option]
print(round(h/(self.height)*100), "%", f" {(time.time()-start) * (self.height - h)} Seconds")
def showNoise(self):
import matplotlib.pyplot as plt
plt.imshow(self.data, cmap = "gray")
plt.show()
w = WorleyNoise(height = 200, width = 200, density = 40)
w.auto(0)
Edit:
That‘s the fastest solution I have found until now:
def worleynoise(width, height, density):
from numpy import random, mgrid, dstack, empty
from scipy.spatial import cKDTree
points = [[random.randint(0, height), random.randint(0, width)] for _ in range(density)] # Generates Points(y, x)
coord = dstack(mgrid[0:height, 0:width]) # Makes array with coordinates as values
tree = cKDTree(points) # Build Tree
distances = tree.query(coord, workers=-1)[0] # Calculate distances (workers=-1: Uses all CPU Cores)
return distances
if __name__ == "__main__":
from matplotlib.pyplot import imshow, show
import time
start = time.time()
w = worleynoise(1000, 1000, 225)
print(time.time() - start)
imshow(w)
show()
The difference to brute force becomes more apparent with a higher amount of points.