How to create a fractal spiral in python with turtle? - python

I'm trying to create a python program that draws a fractal spiral with user input.
I have looked at other questions very similar to mine but it doesn't quite give me what I would like, and I keep getting error messages.
This is what I have tried:
a = int(input("Size? "))
b = int(input("Angle? "))
c = int(input("How many times do you want to repeat? "))
from turtle import *
def fractalSpiral(size, angle, amount):
for i in range(amount):
forward(size)
left(angle)
forward(size + 50)
left(angle + 10)
fractalSpiral(a, b, c)
Witch the inputs a = 50, b = 60, and c = 9, I get the shape in the attachment, which does not look like a fractal spiral.
Can I have some help please?

From what I see in the second picture, you want a shape that is constructed of triangles where every triangle is a little bigger than the previous one and also set to a little different angle. I thought I would go with an Egyptian 3:4:5 triangle and came up with this:
def spiral(step, angle, max):
for i in range(0, max, step):
turtle.forward(i*3)
turtle.left(126.87)
turtle.forward(i*5)
turtle.left(143.2)
turtle.forward(i*4)
turtle.left(90 + angle)
You can now play with the parameters to get a result that would please you. If you want a different triangle, you would need to recalculate its angles using trigonometry. Remember that to get angle alpha, you need to turn you turtle 180 - alpha.

Related

Packing hard spheres in a box

I am trying to pack hard-spheres in a unit cubical box, such that these spheres cannot overlap on each other. This is being done in Python.
I am given some packing fraction f, and the number of spheres in the system is N.
So, I say that the diameter of each sphere will be
d = (p*6/(math.pi*N)**)1/3).
My box has periodic boundary conditions - which means that there is a recurring image of my box in all direction. If there is a particle who is at the edge of the box and has a portion of it going beyond the wall, it will stick out at the other side.
My attempt:
Create a numpy N-by-3 array box which holds the position vector of each particle [x,y,z]
The first particle is fine as it is.
The next particle in the array is checked with all the previous particles. If the distance between them is more than d, move on to the next particle. If they overlap, randomly change the position vector of the particle in question. If the new position does not overlap with the previous atoms, accept it.
Repeat steps 2-3 for the next particle.
I am trying to populate my box with these hard spheres, in the following manner:
for i in range(1,N):
mybool=True
print("particles in box: " + str(i))
while (mybool): #the deal with this while loop is that if we place a bad particle, we need to change its position, and restart the process of checking
for j in range(0,i):
displacement=box[j,:]-box[i,:]
for k in range(3):
if abs(displacement[k])>L/2:
displacement[k] -= L*np.sign(displacement[k])
distance = np.linalg.norm(displacement,2) #check distance between ith particle and the trailing j particles
if distance<diameter:
box[i,:] = np.random.uniform(0,1,(1,3)) #change the position of the ith particle randomly, restart the process
break
if j==i-1 and distance>diameter:
mybool = False
break
The problem with this code is that if p=0.45, it is taking a really, really long time to converge. Is there a better method to solve this problem, more efficiently?
I think what you are looking for is either the hexagonal closed-packed (HCP or sometime called face-centered cubic, FCC) lattice or the cubic closed-packed one (CCP). See e.g. Wikipedia on Close-packing of equal spheres.
Since your space has periodic conditions, I believe it doesn't matter which one you chose (hcp or ccp), and they both achieve the same density of ~74.04%, which was proved by Gauss to be the highest density by lattice packing.
Update:
For the follow-up question on how to generate efficiently one such lattice, let's take as an example the HCP lattice. First, let's create a bunch of (i, j, k) indices [(0,0,0), (1,0,0), (2,0,0), ..., (0,1,0), ...]. Then, get xyz coordinates from those indices and return a DataFrame with them:
def hcp(n):
dim = 3
k, j, i = [v.flatten()
for v in np.meshgrid(*([range(n)] * dim), indexing='ij')]
df = pd.DataFrame({
'x': 2 * i + (j + k) % 2,
'y': np.sqrt(3) * (j + 1/3 * (k % 2)),
'z': 2 * np.sqrt(6) / 3 * k,
})
return df
We can plot the result as scatter3d using plotly for interactive exploration:
import plotly.graph_objects as go
df = hcp(12)
fig = go.Figure(data=go.Scatter3d(
x=df.x, y=df.y, z=df.z, mode='markers',
marker=dict(size=df.x*0 + 30, symbol="circle", color=-df.z, opacity=1),
))
fig.show()
Note: plotly's scatter3d is not a very good rendering of spheres: the marker sizes are constant (so when you zoom in and out, the "spheres" will appear to change relative size), and there is no shading, limited z-ordering faithfulness, etc., but it's convenient to interact with the plot.
Resize and clip to the unit box:
Here, a strict clipping (each sphere needs to be completely inside the unit box). Your "periodic boundary condition" is something you will need to address separately (see further below for ideas).
def hcp_unitbox(r):
n = int(np.ceil(1 / (np.sqrt(3) * r)))
df = hcp(n) * r
df += r
df = df[(df <= 1 - r).all(axis=1)]
return df
With this, you find that a radius of 0.06 gives you 608 fully enclosed spheres:
hcp_unitbox(.06).shape # (608, 3)
Where you would go next:
You may dig deeper into the effect of your so-called "periodic boundary conditions", and perhaps play with some rotations (and small translations).
To do so, you may try to generate an HCP-lattice that is large enough that any rotation will still fully enclose your unit cube. For example:
r = 0.2 # example
n = int(np.ceil(2 / r))
df = hcp(n) * r - 1
Then rotate it (by any amount) and translate it (by up to 1 radius in any direction) as you wish for your research, and clip. The "periodic boundary conditions", as you call them, present a bit of extra challenge, as the clipping becomes trickier. First, clip any sphere whose center is outside your box. Then select spheres close enough to the boundaries, or even partition the regions of interest into overlapping regions along the walls of your cube, then check for collisions among the spheres (as per your periodic boundary conditions) that fall in each such region.

Hyperbolic Spirals (first time learning with ThinkPython)

I'm learning Python (for fun) through the book ThinkPython. So far I'm really enjoying this new hobby. One of the recent exercise was crafting a Archimedes spiral.In order to test my skills I've been working on making a hyperbolic spiral but have been stumped!
according to the equation r=a+b*theta^(1/c)
when c=1 we see a Archimedes spiral
when c=-1 we should see a hyperbolic spiral
I'm using the following code and would appreciate any help towards the right direction.
Extra points to whoever can help me in the right direction without directly giving away the answer. Unless it's simply a formatting issue.
No points if the answer suggested involves using (x,y) coordinates to draw.
import turtle
import math
def draw_spiral(t, n, length=3, a=0.1, b=0.0002):
"""Draws an Archimedian spiral starting at the origin.
Args:
n: how many line segments to draw
length: how long each segment is
a: how loose the initial spiral starts out (larger is looser)
b: how loosly coiled the spiral is (larger is looser)
http://en.wikipedia.org/wiki/Spiral
"""
theta = 0.1
for i in range(n):
t.fd(length)
dtheta = 1/((a + b * (theta**(1/-1))))
t.lt(dtheta)
theta += dtheta
# create the world and bob
bob = turtle.Turtle()
draw_spiral(bob, n=1000)
turtle.mainloop()
"""Source code from ThinkPython # http://greenteapress.com/thinkpython2/code/spiral.py
edited to attempt a hyperbolic spiral"""
many thanks!
Simply adjusting the constants passed to draw_spiral() as arguments:
def draw_spiral(t, n, length=1, a=0.01, b=60):
I was able to generate a spiral along the lines you describe:
However, it draws from the outside in, not the inside out. So, may not be what you're looking for.
As mentioned in the answer of #cdlane, it is just a matter of the arguments. I'll extend the answer.
For the Archimedean spiral add the argument c to the function draw_spiral:
def draw_spiral(t, n, length=3, a=0.1, b=0.0002, c=-1):
theta = 0.1
for i in range(n):
t.fd(length)
dtheta = 1/((a + b * (theta**(1/c))))
t.lt(dtheta)
theta += dtheta
And use the following arguments, for instance:
draw_spiral(bob, n=1000, length=1, a=0.01, b=0.001, c=1)

ThinkPython - Ex 4.5 - Write a program that draws an Archimedes spiral (or one of the other kinds)

Is it just me or everyone who is facing so many problems in attempting this question from exercise of Think Python.
I am trying to solve exercises of Chapter 4 but facing so many problem.
Exercise 4.5 says Write a program that draws an Archimedes spiral.
I have this code but its not working in Python.
I need an easy possible solution for this.
Kindly help.
from TurtleWorld import *
world = TurtleWorld()
bob = Turtle()
def polygon(t, length, n):
t = Turtle()
for i in range(n):
fd(t, length)
lt(t, 300 / n)
polygon(bob, 5, 8)
[In the following discussion, I'm using the turtle library that comes with Python, not TurtleWorld, so adjust accordingly.] From the online ThinkPython PDF:
Exercise 4.5. Read about spirals at http://en.wikipedia.org/wiki/Spiral ;
then write a program that draws an Archimedian [sic] spiral (or one
of the other kinds). Solution: http://thinkpython.com/code/spiral.py
If we follow the Wikipedia link from Spiral to Archimedean spiral, we end up with with the formula r = a + b * theta which naturally wants to be computed in polar coordinates and plotted in cartesian coordinates:
def spiral(turtle, rotations=6, a=0.0, b=5):
theta = 0.0
while theta < rotations * 2 * pi:
radius = a + b * theta
x, y = radius * cos(theta), radius * sin(theta)
turtle.goto(x, y)
theta += 0.1
Where a controls the initial angle of the spiral, and b controls the distance between turnings:
But the solution that ThinkPython offers is different:
To get rid of pi, sin() and cos() from math.py, it pictures the turtle on the spiral and what each move along that spiral looks like. It introduces n which is how many line segments to draw, and length the length of those segments. The b variable still means roughly the same thing, though on a different scale, and a represents how tight the initial spiral starts out. Again, we start with:
theta = 0.0
But instead of looping over the number of complete rotations, we loop up to n, the number of segments to draw. So n should be large, e.g. 1000 instead of 5 in your code. Each iteration we move forward length pixels and then calculate a new delta angle to turn based on a, b, and theta:
delta = 1 / (a + b * theta)
We turn by this small amount and also add this amount to theta just before we loop again. In this approach, a and b are typically less than 1 but non-zero:
You can see by the turtle's orientation in the two images that the first is just plotting points so the turtle's orientation isn't significant but in the second we're moving along the spiral so the turtle is always pointing in the direction of the growing spiral. I hope this discussion of the two approaches helps you.

Zoom function in python? (2.7.9)

I'm currently working with the turtle library of python.
I'm working on my midterm project for my coding class and my project is to draw cos, sin, and tangent curves using turtle as well as their inverse functions.
My problem is that when I'm coding inverse sin, the graph shows up way too small and is impossible to be seen by the user. I was wondering if there was a zoom function or a way to stretch the graph to make it bigger?
Here is my code for arcsin:
def drawarcsincurve(amplitude, period, horShift, verShift):
turtle.speed(0)
startPoint = -1
turtle.goto(startPoint, math.asin(startPoint))
turtle.pendown()
for angles in range(-1,1):
y = math.asin(angles)
turtle.goto(angles,y)
Your main problem here, I think, is the range over which your are iterating your angles variable. The line
for angles in range(-1,1):
will execute the loop only twice, with angle == 1 and angle == 0 - i.e. it is equivalent to using
for angles in [-1,0]:
Type range(-1,1) in a Python interpreter window to see what I mean.
You might be getting confused over names as well. You call your loop variable angles, but it's actually representing a ratio (the sine value whose inverse you are calculating).
What you probably want really is something that iterates over the range -1 to 1 in fairly small steps. Lets choose 0.01 as our step (that's arbitrary)
I've altered your code directly rather than doing my own implementation.
I've put in a scale factor (plot_scale) which is equivalent to the zoom that I think you want in your original question.
I've left your original function arguments in, although I don't use them. I thought you might want to play with them later.
def drawarcsincurve(amplitude, period, horShift, verShift):
plot_scale = 100 # Arbitrary value - up to you - similar to "zoom"
turtle.speed(1)
turtle.penup()
startPoint = -1
turtle.goto(plot_scale*startPoint, plot_scale*math.asin(startPoint))
turtle.pendown()
for angles in range(-100,100):
sinval = 1.0 * angles / 100 # this will run -1 to 1 in 0.01 steps
y = math.asin(sinval)
turtle.goto(plot_scale*sinval,plot_scale*y)
This outputs:

Drawing polygon with n number of sides in Python 3.2

I have to write a program in Python that reads the value n and draws a polygon of n sides on the screen. I can use either the turtle graphics module or graphics.py module.
I know how to draw a polygon when n = the number of points you input and then click n times on the screen, but I'm having some trouble getting an idea on how to transform a number of sides into a polygon.
Here's the code I have for the polygon with n number of points:
def newPolygon(self,cmd):
p = eval(input("how many points"))
print("click",p,"times")
num = []
for i in range(p):
vertices = self.win.getMouse()
num.append(vertices)
poly = Polygon(num)
poly.setFill(self.color)
poly.draw(self.win)
self.figs.append(poly)
This isn't the whole code to the program(which is 384 lines). This is just the part of the program where the draw polygon function is where self.figs = [ ] , a list of drawn figures.
I'm assuming what you would like is a way of generating equal sided polygon coordinates which you can feed to your drawing program. I'm not sure which library you are using, so I'm going to stick to lists of pairs of values:
import math
def polygon(sides, radius=1, rotation=0, translation=None):
one_segment = math.pi * 2 / sides
points = [
(math.sin(one_segment * i + rotation) * radius,
math.cos(one_segment * i + rotation) * radius)
for i in range(sides)]
if translation:
points = [[sum(pair) for pair in zip(point, translation)]
for point in points]
return points
There's a fair bit going on in there, so I'll talk through it. The basic approach is to sweep out a circle, and put n equally spaced points on it. These will be the points of our polygon, starting at the 12 'o' clock position.
The first thing to do is work out the angle (in radians) of each wedge from the center outwards. The total number of radians in a circle is 2 pi, so our value is 2 pi / n per segment.
After that a bit of basic trig gives us our points (https://en.wikipedia.org/wiki/Trigonometry#Extending_the_definitions). At this point we scale by our desired radius, and have the opportunity to offset the rotation by a fixed amount too.
After that we translate the values by a certain amount, because you probably want your polygon in the center of the screen, not in the corner.
A few examples
print polygon(5) # A unit pentagon
# [(0.0, 1.0), (0.9510565162951535, 0.30901699437494745), (0.5877852522924732, -0.8090169943749473), (-0.587785252292473, -0.8090169943749476), (-0.9510565162951536, 0.30901699437494723)]
print polygon(4, 100) # A square, point up, 100 from the center to the points
# [(0.0, 100.0), (100.0, 6.123233995736766e-15), (1.2246467991473532e-14, -100.0), (-100.0, -1.8369701987210297e-14)]
print polygon(4, 2, math.pi / 4, [10, 10]) # A flat square centered on 10, 10
# [[11.414213562373096, 11.414213562373096], [11.414213562373096, 8.585786437626904], [8.585786437626904, 8.585786437626904], [8.585786437626904, 11.414213562373094]]
As you can see, these are all floats, so you may need to squish these to integers before you can use them.
I don't know if this will help but to define a polygon using number of sides and length then I would use my code:
import turtle as t
def polygon(n,l):
f = (n - 2) * 180/n
for i in range(n):
t.forward(l)
t.right(180 - f)
polygon()
In this case, n would be number of sides and l would be length of sides.
This took me quite a while as I am only 13 and am not advanced but this was a fun project!

Categories

Resources