Koch Snowflake in Python won't work - python
I'm having a problem with this Python program. It's supposed to draw a Koch-Snowflake with n iterations. The code does compile but it won't draw a snowflake and I can't find my mistake.
I'd be very thankful if anyone could help me out with this!
from math import sqrt
from matplotlib import pyplot as plt
class vector:
def __init__(self,one,two):
self.x = one
self.y = two
def printV(self):
s = "(" + str(self.x) + "," + str(self.y) + ")"
print s
def __len__(self):
l = sqrt(self.x**2 + self.y**2)
return l
def kochSnowflakeImpl(p1,p2):
u = vector(p1.x + p2.x - p1.x, p1.y + p2.y - p1.y)
array = []
#calculate n1
n1 = vector(p1.x + 1.0/3.0 * u.x, p1.y + (1.0/3.0) * u.y)
#calculate n2
n2 = vector(p1.x + 2.0/3.0 * u.x,p1.y + 2.0/3.0 * u.y)
v = vector(n1.y + n2.y - n1.y, -(n1.x + n2.x - n1.x)) #is an orthogonal vector to u
#calculate n3
n3 = vector(n1.x + 0.5*u.x + sqrt(3.0)/2.0 * v.x, p1.y + 0.5*u.y + sqrt(3.0)/2.0* v.y)
array.append([n1.x,n1.y])
array.append([n2.x,n2.y])
array.append([n3.x,n3.y])
return n1,n2,n3,array
def kochSnowflake(level):
p1 = vector(0,0) #format: p = (x,y)
p2 = vector(1,0)
p3 = vector(0.5,sqrt(3)/2)
array = [[p1.x,p1.y],[p2.x,p2.y],[p3.x,p3.y],[p1.x,p1.y]]
while level > 0:
if level == 1:
n1,n2,n3,array1 = kochSnowflakeImpl(p1,p2)
n4,n5,n6,array2 = kochSnowflakeImpl(p2,p3)
n7,n8,n9,array3 = kochSnowflakeImpl(p3,p2)
for i in array1:
array.append(i)
for j in array2:
array.append(j)
for k in array3:
array.append(k)
else:
n1,n2,n3,array1 = kochSnowflakeImpl(p1,p2)
n11,n21,n31,array11 = kochSnowflakeImpl(n1,n3)
n12,n22,n32,array12 = kochSnowflakeImpl(n3,n2)
n4,n5,n6,array2 = kochSnowflakeImpl(p2,p3)
n41,n52,n61,array21 = kochSnowflakeImpl(n4,n6)
n42,n52,n62,array22 = kochSnowflakeImpl(n6,n5)
n7,n8,n9,array3 = kochSnowflakeImpl(p1,p3)
n71,n81,n91,array31 = kochSnowflakeImpl(n7,n9)
n72,n82,n92,array32 = kochSnowflakeImpl(n9,n8)
for i in array1:
array.append(i)
for i in array11:
array.append(i)
for i in array12:
array.append(i)
for j in array2:
array.append(j)
for j in array21:
array.append(j)
for j in array22:
array.append(j)
for k in array3:
array.append(k)
for k in array31:
array.append(k)
for k in array32:
array.append(k)
level -= 1
return array
if __name__=='__main__':
points = kochSnowflake(5)
x,y = zip(*points)
plt.plot(x, y)
plt.show()
I decided it was time to turn the output of this code from a bad piece of string art from the '70s that didn't age well in the closet into a Koch snowflake.
One problem is the OP added new points to the array in kochSnowflakeImpl() but forgot to add the original start and end points. The next problem was the n3 calculation as the two terms that summed to make each coordinate were from the same coordinate whereas one term should have been from the other coordinate. And the level logic in kochSnowflake() was hopeless.
To simplify the code, I tossed the OP's vector class (which was reasonable) and substituted the more complete Vec2D class from Python turtle:
from turtle import Vec2D
from matplotlib import pyplot as plt
SQRT_3 = 3.0 ** 0.5
def kochSnowflakeImpl(p1, p2):
u = p2 - p1
v = Vec2D(-u[1], u[0])
n1 = p1 + u * (1.0 / 3.0)
n2 = n1 + u * (1.0 / 6.0) + v * (SQRT_3 / 6.0)
n3 = p1 + u * (2.0 / 3.0)
return [p1, n1, n2, n3, p2]
def kochSnowflake(level):
p1 = Vec2D(0.0, 0.0)
p2 = Vec2D(0.5, SQRT_3 / 2.0)
p3 = Vec2D(1.0, 0.0)
array = [p1, p2, p3, p1]
for _ in range(level):
new_array = []
for (p1, p2) in zip(array, array[1:]):
new_array.extend(kochSnowflakeImpl(p1, p2))
array = new_array
return array
if __name__ == '__main__':
points = kochSnowflake(4)
x, y = zip(*points)
plt.plot(x, y)
plt.show()
I don't think this code is quite correct as the snowflake looks a bit squat, but I believe it achieves the goal of the original code and is clean enough to build upon.
Related
How to simulate a heat diffusion on a rectangular ring with FiPy?
I am new to solving a PDE and experimenting with a heat diffusion on a copper body of a rectangular ring shape using FiPy. And this is a plot of simulation result at some times. I am using the Grid2D() for a mesh and the CellVariable.constrain() to specify boundary conditions. The green dots are centers of exterior faces where T = 273.15 + 25 (K), and blue dots are centers of interior faces where T = 273.15 + 30 (K). Obviously, I am doing something wrong, because the temperature goes down to 0K. How should I specify boundary conditions correctly? These are the code. import numpy as np import matplotlib.pyplot as plt import fipy def get_mask_of_rect(mesh, x, y, w, h): def left_id(i, j): return mesh.numberOfHorizontalFaces + i*mesh.numberOfVerticalColumns + j def right_id(i, j): return mesh.numberOfHorizontalFaces + i*mesh.numberOfVerticalColumns + j + 1 def bottom_id(i, j): return i*mesh.nx + j def top_id(i, j): return (i+1)*mesh.nx + j j0, i0 = np.floor(np.array([x, y]) / [mesh.dx, mesh.dy]).astype(int) n, m = np.round(np.array([w, h]) / [mesh.dx, mesh.dy]).astype(int) mask = np.zeros_like(mesh.exteriorFaces, dtype=bool) for i in range(i0, i0 + n): mask[left_id(i, j0)] = mask[right_id(i, j0 + m-1)] = True for j in range(j0, j0 + m): mask[bottom_id(i0, j)] = mask[top_id(i0 + n-1, j)] = True return mask mesh = fipy.Grid2D(Lx = 1, Ly = 1, nx = 20, ny = 20) # Grid of size 1m x 1m k_over_c_rho = 3.98E2 / (3.85E2 * 8.96E3) # The thermal conductivity, specific heat capacity, and density of Copper in MKS dt = 0.1 * (mesh.dx**2 + mesh.dy**2) / (4*k_over_c_rho) T0 = 273.15 # 0 degree Celsius in Kelvin T = fipy.CellVariable(mesh, name='T', value=T0+25) mask_e = mesh.exteriorFaces T.constrain(T0+25., mask_e) mask_i = get_mask_of_rect(mesh, 0.25, 0.25, 0.5, 0.5) T.constrain(T0+30, mask_i) eq = fipy.TransientTerm() == fipy.DiffusionTerm(coeff=k_over_c_rho) viewer = fipy.MatplotlibViewer(vars=[T], datamin=0, datamax=400) plt.ioff() viewer._plot() plt.plot(*mesh.faceCenters[:, mask_e], '.g') plt.plot(*mesh.faceCenters[:, mask_i], '.b') def update(): for _ in range(10): eq.solve(var=T, dt=dt) viewer._plot() plt.draw() timer = plt.gcf().canvas.new_timer(interval=50) timer.add_callback(update) timer.start() plt.show()
.constrain() does not work for internal faces (see the warning at the end of Applying internal “boundary” conditions). You can achieve an internal fixed value condition using sources, however. As a first cut, try mask_i = get_mask_of_rect(mesh, 0.25, 0.25, 0.5, 0.5) mask_i_cell = fipy.CellVariable(mesh, value=False) mask_i_cell[mesh.faceCellIDs[..., mask_i]] = True largeValue = 1e6 eq = (fipy.TransientTerm() == fipy.DiffusionTerm(coeff=k_over_c_rho) - fipy.ImplicitSourceTerm(mask_i_cell * largeValue) + mask_i_cell * largeValue * (T0 + 30)) This constrains the cells on either side of the faces identified by mask_i to be at T0+30.
I am posting my own answer for future readers. For boundary conditions for internal faces, you should use the implicit and explicit source terms on the equation, as in the jeguyer's answer. By using source terms, you don't need to calculate a mask for faces, like this.(The get_mask_of_rect() in my question isn't required.) T = fipy.CellVariable(mesh, name = 'T', value = T0 + 25) mask_e = mesh.exteriorFaces T.constrain(T0 + 25., mask_e) mask_i_cell = ( (0.25 < mesh.x) & (mesh.x < 0.25 + 0.5) & (0.25 < mesh.y) & (mesh.y < 0.25 + 0.5) ) large_value = 1E6 eq = fipy.TransientTerm() == ( fipy.DiffusionTerm(coeff = k_over_c_rho) - fipy.ImplicitSourceTerm(mask_i_cell * large_value) + mask_i_cell * (large_value * (T0 + 30) # explicit source )) viewer = fipy.MatplotlibViewer(vars = [T], datamin = T0, datamax = T0+50)
Compute Fourier Series for a discrete set of points
I'm trying to compute the continuous function hidden behind the points, but it shows a graph that looks like it actually coutns the points in-between as zeros. Here's the plot that shows up (100 vectors, red dots - data set, blue plot - my Fourier series): Here's the python code: import matplotlib.pyplot as plt import numpy as np import math step = (np.pi * 2) / 5 start = -np.pi xDiscrete = [start, start + step, start + 2 * step, start + 3 * step, start + 4 * step, np.pi] yDiscrete = [2.88, 2.98, 3.24, 3.42, 3.57, 3.79] ak = [] bk = [] a0 = 0 precisionSize = 0.001 n = 100 avgError = 0 def getAN(k): sum = 0 for ind in range(1, len(yDiscrete)): sum += yDiscrete[ind] * math.cos(k * xDiscrete[ind]) an = (2.0 / n) * sum print('a' + str(k) + ' = ' + str(an)) return an def getBN(k): sum = 0 for ind in range(1, len(yDiscrete)): sum += yDiscrete[ind] * math.sin(k * xDiscrete[ind]) bn = (2.0 / n) * sum print('b' + str(k) + ' = ' + str(bn)) return bn def getA0(): sum = 0 for ind in range(1, len(yDiscrete)): sum += yDiscrete[ind] a0 = (2.0 / n) * sum print('a0 = ' + str(a0)) return a0 def getFourierOneSum(x, i): return ak[i - 1] * math.cos(i * x) + bk[i - 1] * math.sin(i * x) def getFourierAtPoint(x): sum = a0 / 2 for i in range(1, n + 1): sum += getFourierOneSum(x, i) return sum for i in range(1, n + 1): ak.append(getAN(i)) bk.append(getBN(i)) a0 = getA0() x2 = np.arange(-np.pi, np.pi, precisionSize) y2 = [] for coor in x2: y2.append(getFourierAtPoint(coor)) plt.plot(xDiscrete, yDiscrete, 'ro', alpha=0.6) plt.plot(x2, y2) plt.grid() plt.title('Approximation') plt.show() I've checked where is the problem, and I'm pretty sure it's with the coefficients (functions getAN, getBN, getA0), but I'm not sure how to fix it.
How to increase FPS in ursina python
I want to create survival games with infinite block terrain(like Minecraft). So i using ursina python game engine, you can see it here So i using perlin noise to create the terrain with build-in ursina block model. I test for first 25 block and it work pretty good with above 100 FPS, so i start increase to 250 block and more because I want a infinite terrain. But i ran to some problem, when i increase to 100 block or more, my FPS start to decrease below 30 FPS (With i create just one layer). Here is my code: #-------------------------------Noise.py(I got on the github)------------------------- # Copyright (c) 2008, Casey Duncan (casey dot duncan at gmail dot com) # see LICENSE.txt for details """Perlin noise -- pure python implementation""" __version__ = '$Id: perlin.py 521 2008-12-15 03:03:52Z casey.duncan $' from math import floor, fmod, sqrt from random import randint # 3D Gradient vectors _GRAD3 = ((1,1,0),(-1,1,0),(1,-1,0),(-1,-1,0), (1,0,1),(-1,0,1),(1,0,-1),(-1,0,-1), (0,1,1),(0,-1,1),(0,1,-1),(0,-1,-1), (1,1,0),(0,-1,1),(-1,1,0),(0,-1,-1), ) # 4D Gradient vectors _GRAD4 = ((0,1,1,1), (0,1,1,-1), (0,1,-1,1), (0,1,-1,-1), (0,-1,1,1), (0,-1,1,-1), (0,-1,-1,1), (0,-1,-1,-1), (1,0,1,1), (1,0,1,-1), (1,0,-1,1), (1,0,-1,-1), (-1,0,1,1), (-1,0,1,-1), (-1,0,-1,1), (-1,0,-1,-1), (1,1,0,1), (1,1,0,-1), (1,-1,0,1), (1,-1,0,-1), (-1,1,0,1), (-1,1,0,-1), (-1,-1,0,1), (-1,-1,0,-1), (1,1,1,0), (1,1,-1,0), (1,-1,1,0), (1,-1,-1,0), (-1,1,1,0), (-1,1,-1,0), (-1,-1,1,0), (-1,-1,-1,0)) # A lookup table to traverse the simplex around a given point in 4D. # Details can be found where this table is used, in the 4D noise method. _SIMPLEX = ( (0,1,2,3),(0,1,3,2),(0,0,0,0),(0,2,3,1),(0,0,0,0),(0,0,0,0),(0,0,0,0),(1,2,3,0), (0,2,1,3),(0,0,0,0),(0,3,1,2),(0,3,2,1),(0,0,0,0),(0,0,0,0),(0,0,0,0),(1,3,2,0), (0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0), (1,2,0,3),(0,0,0,0),(1,3,0,2),(0,0,0,0),(0,0,0,0),(0,0,0,0),(2,3,0,1),(2,3,1,0), (1,0,2,3),(1,0,3,2),(0,0,0,0),(0,0,0,0),(0,0,0,0),(2,0,3,1),(0,0,0,0),(2,1,3,0), (0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0), (2,0,1,3),(0,0,0,0),(0,0,0,0),(0,0,0,0),(3,0,1,2),(3,0,2,1),(0,0,0,0),(3,1,2,0), (2,1,0,3),(0,0,0,0),(0,0,0,0),(0,0,0,0),(3,1,0,2),(0,0,0,0),(3,2,0,1),(3,2,1,0)) # Simplex skew constants _F2 = 0.5 * (sqrt(3.0) - 1.0) _G2 = (3.0 - sqrt(3.0)) / 6.0 _F3 = 1.0 / 3.0 _G3 = 1.0 / 6.0 class BaseNoise: """Noise abstract base class""" permutation = (151,160,137,91,90,15, 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166, 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196, 135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9, 129,22,39,253,9,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254, 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180) period = len(permutation) # Double permutation array so we don't need to wrap permutation = permutation * 2 randint_function = randint def __init__(self, period=None, permutation_table=None, randint_function=None): """Initialize the noise generator. With no arguments, the default period and permutation table are used (256). The default permutation table generates the exact same noise pattern each time. An integer period can be specified, to generate a random permutation table with period elements. The period determines the (integer) interval that the noise repeats, which is useful for creating tiled textures. period should be a power-of-two, though this is not enforced. Note that the speed of the noise algorithm is indpendent of the period size, though larger periods mean a larger table, which consume more memory. A permutation table consisting of an iterable sequence of whole numbers can be specified directly. This should have a power-of-two length. Typical permutation tables are a sequnce of unique integers in the range [0,period) in random order, though other arrangements could prove useful, they will not be "pure" simplex noise. The largest element in the sequence must be no larger than period-1. period and permutation_table may not be specified together. A substitute for the method random.randint(a, b) can be chosen. The method must take two integer parameters a and b and return an integer N such that a <= N <= b. """ if randint_function is not None: # do this before calling randomize() if not hasattr(randint_function, '__call__'): raise TypeError( 'randint_function has to be a function') self.randint_function = randint_function if period is None: period = self.period # enforce actually calling randomize() if period is not None and permutation_table is not None: raise ValueError( 'Can specify either period or permutation_table, not both') if period is not None: self.randomize(period) elif permutation_table is not None: self.permutation = tuple(permutation_table) * 2 self.period = len(permutation_table) def randomize(self, period=None): """Randomize the permutation table used by the noise functions. This makes them generate a different noise pattern for the same inputs. """ if period is not None: self.period = period perm = list(range(self.period)) perm_right = self.period - 1 for i in list(perm): j = self.randint_function(0, perm_right) perm[i], perm[j] = perm[j], perm[i] self.permutation = tuple(perm) * 2 class SimplexNoise(BaseNoise): """Perlin simplex noise generator Adapted from Stefan Gustavson's Java implementation described here: http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf To summarize: "In 2001, Ken Perlin presented 'simplex noise', a replacement for his classic noise algorithm. Classic 'Perlin noise' won him an academy award and has become an ubiquitous procedural primitive for computer graphics over the years, but in hindsight it has quite a few limitations. Ken Perlin himself designed simplex noise specifically to overcome those limitations, and he spent a lot of good thinking on it. Therefore, it is a better idea than his original algorithm. A few of the more prominent advantages are: * Simplex noise has a lower computational complexity and requires fewer multiplications. * Simplex noise scales to higher dimensions (4D, 5D and up) with much less computational cost, the complexity is O(N) for N dimensions instead of the O(2^N) of classic Noise. * Simplex noise has no noticeable directional artifacts. Simplex noise has a well-defined and continuous gradient everywhere that can be computed quite cheaply. * Simplex noise is easy to implement in hardware." """ def noise2(self, x, y): """2D Perlin simplex noise. Return a floating point value from -1 to 1 for the given x, y coordinate. The same value is always returned for a given x, y pair unless the permutation table changes (see randomize above). """ # Skew input space to determine which simplex (triangle) we are in s = (x + y) * _F2 i = floor(x + s) j = floor(y + s) t = (i + j) * _G2 x0 = x - (i - t) # "Unskewed" distances from cell origin y0 = y - (j - t) if x0 > y0: i1 = 1; j1 = 0 # Lower triangle, XY order: (0,0)->(1,0)->(1,1) else: i1 = 0; j1 = 1 # Upper triangle, YX order: (0,0)->(0,1)->(1,1) x1 = x0 - i1 + _G2 # Offsets for middle corner in (x,y) unskewed coords y1 = y0 - j1 + _G2 x2 = x0 + _G2 * 2.0 - 1.0 # Offsets for last corner in (x,y) unskewed coords y2 = y0 + _G2 * 2.0 - 1.0 # Determine hashed gradient indices of the three simplex corners perm = self.permutation ii = int(i) % self.period jj = int(j) % self.period gi0 = perm[ii + perm[jj]] % 12 gi1 = perm[ii + i1 + perm[jj + j1]] % 12 gi2 = perm[ii + 1 + perm[jj + 1]] % 12 # Calculate the contribution from the three corners tt = 0.5 - x0**2 - y0**2 if tt > 0: g = _GRAD3[gi0] noise = tt**4 * (g[0] * x0 + g[1] * y0) else: noise = 0.0 tt = 0.5 - x1**2 - y1**2 if tt > 0: g = _GRAD3[gi1] noise += tt**4 * (g[0] * x1 + g[1] * y1) tt = 0.5 - x2**2 - y2**2 if tt > 0: g = _GRAD3[gi2] noise += tt**4 * (g[0] * x2 + g[1] * y2) return noise * 70.0 # scale noise to [-1, 1] def noise3(self, x, y, z): """3D Perlin simplex noise. Return a floating point value from -1 to 1 for the given x, y, z coordinate. The same value is always returned for a given x, y, z pair unless the permutation table changes (see randomize above). """ # Skew the input space to determine which simplex cell we're in s = (x + y + z) * _F3 i = floor(x + s) j = floor(y + s) k = floor(z + s) t = (i + j + k) * _G3 x0 = x - (i - t) # "Unskewed" distances from cell origin y0 = y - (j - t) z0 = z - (k - t) # For the 3D case, the simplex shape is a slightly irregular tetrahedron. # Determine which simplex we are in. if x0 >= y0: if y0 >= z0: i1 = 1; j1 = 0; k1 = 0 i2 = 1; j2 = 1; k2 = 0 elif x0 >= z0: i1 = 1; j1 = 0; k1 = 0 i2 = 1; j2 = 0; k2 = 1 else: i1 = 0; j1 = 0; k1 = 1 i2 = 1; j2 = 0; k2 = 1 else: # x0 < y0 if y0 < z0: i1 = 0; j1 = 0; k1 = 1 i2 = 0; j2 = 1; k2 = 1 elif x0 < z0: i1 = 0; j1 = 1; k1 = 0 i2 = 0; j2 = 1; k2 = 1 else: i1 = 0; j1 = 1; k1 = 0 i2 = 1; j2 = 1; k2 = 0 # Offsets for remaining corners x1 = x0 - i1 + _G3 y1 = y0 - j1 + _G3 z1 = z0 - k1 + _G3 x2 = x0 - i2 + 2.0 * _G3 y2 = y0 - j2 + 2.0 * _G3 z2 = z0 - k2 + 2.0 * _G3 x3 = x0 - 1.0 + 3.0 * _G3 y3 = y0 - 1.0 + 3.0 * _G3 z3 = z0 - 1.0 + 3.0 * _G3 # Calculate the hashed gradient indices of the four simplex corners perm = self.permutation ii = int(i) % self.period jj = int(j) % self.period kk = int(k) % self.period gi0 = perm[ii + perm[jj + perm[kk]]] % 12 gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12 gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12 gi3 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12 # Calculate the contribution from the four corners noise = 0.0 tt = 0.6 - x0**2 - y0**2 - z0**2 if tt > 0: g = _GRAD3[gi0] noise = tt**4 * (g[0] * x0 + g[1] * y0 + g[2] * z0) else: noise = 0.0 tt = 0.6 - x1**2 - y1**2 - z1**2 if tt > 0: g = _GRAD3[gi1] noise += tt**4 * (g[0] * x1 + g[1] * y1 + g[2] * z1) tt = 0.6 - x2**2 - y2**2 - z2**2 if tt > 0: g = _GRAD3[gi2] noise += tt**4 * (g[0] * x2 + g[1] * y2 + g[2] * z2) tt = 0.6 - x3**2 - y3**2 - z3**2 if tt > 0: g = _GRAD3[gi3] noise += tt**4 * (g[0] * x3 + g[1] * y3 + g[2] * z3) return noise * 32.0 def lerp(t, a, b): return a + t * (b - a) def grad3(hash, x, y, z): g = _GRAD3[hash % 16] return x*g[0] + y*g[1] + z*g[2] class TileableNoise(BaseNoise): """Tileable implemention of Perlin "improved" noise. This is based on the reference implementation published here: http://mrl.nyu.edu/~perlin/noise/ """ def noise3(self, x, y, z, repeat, base=0.0): """Tileable 3D noise. repeat specifies the integer interval in each dimension when the noise pattern repeats. base allows a different texture to be generated for the same repeat interval. """ i = int(fmod(floor(x), repeat)) j = int(fmod(floor(y), repeat)) k = int(fmod(floor(z), repeat)) ii = (i + 1) % repeat jj = (j + 1) % repeat kk = (k + 1) % repeat if base: i += base; j += base; k += base ii += base; jj += base; kk += base x -= floor(x); y -= floor(y); z -= floor(z) fx = x**3 * (x * (x * 6 - 15) + 10) fy = y**3 * (y * (y * 6 - 15) + 10) fz = z**3 * (z * (z * 6 - 15) + 10) perm = self.permutation A = perm[i] AA = perm[A + j] AB = perm[A + jj] B = perm[ii] BA = perm[B + j] BB = perm[B + jj] return lerp(fz, lerp(fy, lerp(fx, grad3(perm[AA + k], x, y, z), grad3(perm[BA + k], x - 1, y, z)), lerp(fx, grad3(perm[AB + k], x, y - 1, z), grad3(perm[BB + k], x - 1, y - 1, z))), lerp(fy, lerp(fx, grad3(perm[AA + kk], x, y, z - 1), grad3(perm[BA + kk], x - 1, y, z - 1)), lerp(fx, grad3(perm[AB + kk], x, y - 1, z - 1), grad3(perm[BB + kk], x - 1, y - 1, z - 1)))) #--------------------------Math.py(For InverseLefp)-------------------------------- def Clamp(t: float, minimum: float, maximum: float): """Float result between a min and max values.""" value = t if t < minimum: value = minimum elif t > maximum: value = maximum return value def InverseLefp(a: float, b: float, value: float): if a != b: return Clamp((value - a) / (b - a), 0, 1) return 0 #-----------------------------Game.py(Main code)---------------------- from ursina import * from ursina.prefabs import * from ursina.prefabs.first_person_controller import * from Math import InverseLefp import Noise app = Ursina() #The maximum height of the terrain maxHeight = 10 #Control the width and height of the map mapWidth = 10 mapHeight = 10 #A class that create a block class Voxel(Button): def __init__(self, position=(0,0,0)): super().__init__( parent = scene, position = position, model = 'cube', origin_y = .5, texture = 'white_cube', color = color.color(0, 0, random.uniform(.9, 1.0)), highlight_color = color.lime, ) #Detect user key input def input(self, key): if self.hovered: if key == 'right mouse down': #Place block if user right click voxel = Voxel(position=self.position + mouse.normal) if key == 'left mouse down': #Break block if user left click destroy(self) if key == 'escape': #Exit the game if user press the esc key app.userExit() #Return perlin noise value between 0 and 1 with x, y position with scale = noiseScale def GeneratedNoiseMap(y: int, x: int, noiseScale: float): #Check if the noise scale was invalid or not if noiseScale <= 0: noiseScale = 0.001 sampleX = x / noiseScale sampleY = y / noiseScale #The Noise.SimplexNoise().noise2 will return the value between -1 and 1 perlinValue = Noise.SimplexNoise().noise2(sampleX, sampleY) #The InverseLefp will make the value scale to between 0 and 1 perlinValue = InverseLefp(-1, 1, perlinValue) return perlinValue for z in range(mapHeight): for x in range(mapWidth): #Calculating the height of the block and round it to integer height = round(GeneratedNoiseMap(z, x, 20) * maxHeight) #Place the block and make it always below the player block = Voxel(position=(x, height - maxHeight - 1, z)) #Set the collider of the block block.collider = 'mesh' #Character movement player = FirstPersonController() #Run the game app.run() All file in same folder. It was working fine but the FPS is very low, so can anyone help?
I'm not able to test this code at the moment but this should serve as a starting point: level_parent = Entity(model=Mesh(vertices=[], uvs=[])) for z in range(mapHeight): for x in range(mapWidth): height = round(GeneratedNoiseMap(z, x, 20) * maxHeight) block = Voxel(position=(x, height - maxHeight - 1, z)) level_parent.model.vertices.extend(block.model.vertices) level_parent.collider = 'mesh' # call this only once after all vertices are set up For texturing, you might have to add the block.uvs from each block to level_parent.model.uvs as well. Alternatively, call level_parent.model.project_uvs() after setting up the vertices.
On my version of ursina engine (5.0.0) only this code: ` level_parent = Entity(model=Mesh(vertices=[], uvs=[])) for z in range(mapHeight): for x in range(mapWidth): height = round(GeneratedNoiseMap(z, x, 20) * maxHeight) block = Voxel(position=(x, height - maxHeight - 1, z)) #level_parent.model.vertices.extend(block.model.vertices) level_parent.combine().vertices.extend(block.combine().vertices) level_parent.collider = 'mesh' ` is working.
How to change Function by without Changing its Parameters
I am new to python and in learning stages. I wanted to implement Particle Swarm Optimization(PSO) algorithm which I did by taking help from on-line materials and python tutorials. In PSO, a simple calculus problem is inferred i-e 100 * ((y - (x2))2) + ((1 - (x2))2). This problem is defined in a fitness function. def fitness(x, y): return 100 * ((y - (x**2))**2) + ((1 - (x**2))**2) Now, I want to replace this simple calculus problem by simple first order Ordinary Differential Equation(ODE) by without changing existing function parameters (x,y) and want to return the value of dy_dx,y0 and t for further process. # Define a function which calculates the derivative def dy_dx(y, x): return x - y t = np.linspace(0,5,100) y0 = 1.0 # the initial condition ys = odeint(dy_dx, y0, t)` In python odeint function is used for ODE which requires three essential parameters i-e func/model, y0( Initial condition on y (can be a vector) and t(A sequence of time points for which to solve for y) Example of odeint parameters. I don't want to change its parameters because it will be difficult for me to make changes in algorithm. For simplicity I pasted the full code below and my question is open to anyone if wants to modify the code with further parameters in General Best, Personal Best and r[i]. import numpy as np from scipy.integrate import odeint import random as rand from scipy.integrate import odeint from numpy import array import matplotlib.pyplot as plt def main(): #Variables n = 40 num_variables = 2 a = np.empty((num_variables, n)) v = np.empty((num_variables, n)) Pbest = np.empty((num_variables, n)) Gbest = np.empty((1, 2)) r = np.empty((n)) for i in range(0, num_variables): for j in range(0, n): Pbest[i][j] = rand.randint(-20, 20) a[i][j] = Pbest[i][j] v[i][j] = 0 for i in range(0, n): r[i] = fitness(a[0][i], a[1][i]) #Sort elements of Pbest Order(Pbest, r, n) Gbest[0][0] = Pbest[0][0] Gbest[0][1] = Pbest[1][0] generation = 0 plt.ion() fig = plt.figure() ax = fig.add_subplot(111) ax.grid(True) while(generation < 1000): for i in range(n): #Get Personal Best if(fitness(a[0][i], a[1][i]) < fitness(Pbest[0][i], Pbest[1][i])): Pbest[0][i] = a[0][i] Pbest[1][i] = a[1][i] #Get General Best if(fitness(Pbest[0][i], Pbest[1][i]) < fitness(Gbest[0][0], Gbest[0][1])): Gbest[0][0] = Pbest[0][i] Gbest[0][1] = Pbest[1][i] #Calculate Velocity Vector_Velocidad(n, a, Pbest, Gbest, v) generation = generation + 1 print 'Generacion: ' + str(generation) + ' - - - Gbest: ' +str(Gbest) line1 = ax.plot(a[0], a[1], 'r+') line2 = ax.plot(Gbest[0][0], Gbest[0][1], 'g*') ax.set_xlim(-10, 10) ax.set_ylim(-10, 10) fig.canvas.draw() ax.clear() ax.grid(True) print 'Gbest: ' print Gbest def Vector_Velocidad(n, a, Pbest, Gbest, v): for i in range(n): #Velocity in X v[0][i] = 0.7 * v[0][i] + (Pbest[0][i] - a[0][i]) * rand.random() * 1.47 + (Gbest[0][0] - a[0][i]) * rand.random() * 1.47 a[0][i] = a[0][i] + v[0][i] v[1][i] = 0.7 * v[1][i] + (Pbest[1][i] - a[1][i]) * rand.random() * 1.47 + (Gbest[0][1] - a[1][i]) * rand.random() * 1.47 a[1][i] = a[1][i] + v[1][i] def fitness(x, y): return 100 * ((y - (x**2))**2) + ((1 - (x**2))**2) def Order(Pbest, r, n): for i in range(1, n): for j in range(0, n - 1): if r[j] > r[j + 1]: #Order the fitness tempRes = r[j] r[j] = r[j + 1] r[j + 1] = tempRes #Order las X, Y tempX = Pbest[0][j] Pbest[0][j] = Pbest[0][j + 1] Pbest[0][j + 1] = tempX tempY = Pbest[1][j] Pbest[1][j] = Pbest[1][j + 1] Pbest[1][j + 1] = tempY if '__main__' == main(): main()
Lotka-Volterra equations(predator prey) using Runge-Kutta in Python
I am trying to write a program using the Lotka-Volterra equations for predator-prey interactions. Solve Using ODE's: dx/dt = a*x - B*x*y dy/dt = g*x*y - s*y Using 4th order Runge-Kutta method I need to plot a graph showing both x and y as a function of time from t = 0 to t=30. a = alpha = 1 b = beta = 0.5 g = gamma = 0.5 s = sigma = 2 initial conditions x = y = 2 Here is my code so far but not display anything on the graph. Some help would be nice. #!/usr/bin/env python from __future__ import division, print_function import matplotlib.pyplot as plt import numpy as np def rk4(f, r, t, h): """ Runge-Kutta 4 method """ k1 = h*f(r, t) k2 = h*f(r+0.5*k1, t+0.5*h) k3 = h*f(r+0.5*k2, t+0.5*h) k4 = h*f(r+k3, t+h) return (k1 + 2*k2 + 2*k3 + k4)/6 def f(r, t): alpha = 1.0 beta = 0.5 gamma = 0.5 sigma = 2.0 x, y = r[2], r[2] fxd = x*(alpha - beta*y) fyd = -y*(gamma - sigma*x) return np.array([fxd, fyd], float) tpoints = np.linspace(0, 30, 0.1) xpoints = [] ypoints = [] r = np.array([2, 2], float) for t in tpoints: xpoints += [r[2]] ypoints += [r[2]] r += rk4(f, r, t, h) plt.plot(tpoints, xpoints) plt.plot(tpoints, ypoints) plt.xlabel("Time") plt.ylabel("Population") plt.title("Lotka-Volterra Model") plt.savefig("Lotka_Volterra.png") plt.show()
A simple check of your variable tpoints after running your script shows it's empty: In [7]: run test.py In [8]: tpoints Out[8]: array([], dtype=float64) This is because you're using np.linspace incorrectly. The third argument is the number of elements desired in the output. You've requested an array of length 0.1. Take a look at np.linspace's docstring. You won't have a problem figuring out how to adjust your code.
1) define 'h' variable. 2) use tpoints = np.arange(30) #array([0, 1, 2, ..., 30]) not np.linspace() and don't forget to set time step size equal to h: h=0.1 tpoints = np.arange(0, 30, h) 3) be careful with indexes: def f(r,t): ... x, y=r[0], r[1] ... for t in tpoints: xpoints += [r[0]] ypoints += [r[1]] ... and better use .append(x): for t in tpoints: xpoints.append(r[0]) ypoints.append(r[1]) ... Here's tested code for python 3.7 (I've set h=0.001 for more presize) import matplotlib.pyplot as plt import numpy as np def rk4(r, t, h): #edited; no need for input f """ Runge-Kutta 4 method """ k1 = h*f(r, t) k2 = h*f(r+0.5*k1, t+0.5*h) k3 = h*f(r+0.5*k2, t+0.5*h) k4 = h*f(r+k3, t+h) return (k1 + 2*k2 + 2*k3 + k4)/6 def f(r, t): alpha = 1.0 beta = 0.5 gamma = 0.5 sigma = 2.0 x, y = r[0], r[1] fxd = x*(alpha - beta*y) fyd = -y*(gamma - sigma*x) return np.array([fxd, fyd], float) h=0.001 #edited tpoints = np.arange(0, 30, h) #edited xpoints, ypoints = [], [] r = np.array([2, 2], float) for t in tpoints: xpoints.append(r[0]) #edited ypoints.append(r[1]) #edited r += rk4(r, t, h) #edited; no need for input f plt.plot(tpoints, xpoints) plt.plot(tpoints, ypoints) plt.xlabel("Time") plt.ylabel("Population") plt.title("Lotka-Volterra Model") plt.savefig("Lotka_Volterra.png") plt.show() You can also try to plot "cycles": plt.xlabel("Prey") plt.ylabel("Predator") plt.plot(xpoints, ypoints) plt.show() https://i.stack.imgur.com/NB9lc.png