We choose to represent a point in the plane as a list [x, y]
containing the x and y coordinates of the point. For example the point A = (3, 4) in the plane will be represented by the list [3,4]
in python.
We choose to represent a line as a list of two points [p, q]
containing the endpoints of the line. So for example the segment AB between points A = (0,0) and B = (1,1) would be represented in python as the list [[0,0], [1,1]]
.
In the following exercice, you'll be asked to return a list of lines.
The dragon curve is a figure that appeared on the chapter covers of Jurassic Parc. It looks like this :
The 0-dragon curve between two points P and Q is a simple line between the points:
The 1-dragon curve between two points P and Q looks like this :
To build the n-dragon curve between points P and Q, you need to define an intermediary point R. Here is how you get R.
You build a circle with diameter PQ. If you pick any point A on that circle, the triangle PAQ will be a right triangle.
There are two points on that circle that will not only give you a right triangle, but also an isoscele triangle. Pick one of those points call it R and write a function gimmeR(P, Q)
that returns the point R. Look at the figure below to better understand.
def gimmeR(P, Q):
pass
gimmeR([0,0], [1, 1]) # should return [1, 0]
gimmeR([0,0], [0,1]) # should return [0.5, 0.5]
The n-dragon curve between the points P and Q is defined as the concatenation of the (n-1)-dragon curve between P and R and the (n-1)-dragon curve between Q and R. Using gimmeR
, write a recusive function dragon(n, P, Q)
that returns the list of segments in the n-dragon curve between P and Q.
def dragon(n, P, Q):
pass
The function draw(L)
takes a list of lines and draws it. Check that your function works by calling it.
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Polygon
from matplotlib.collections import PatchCollection, LineCollection
def draw(L):
plt.style.use('ggplot')
f, ax = plt.subplots()
lc = LineCollection(L)
ax.add_collection(lc)
ax.autoscale()
ax.set_aspect('equal')
plt.axis('off')
plt.show()
Dragon curves start looking nice and pretty after 10. Here is what a 13-dragon curve looks like :
We choose to represent a triangle as a list of three points [p, q, r]
. The following exercice asks you to return a list of triangles, you should return a list containing lists of three points.
Here are examples of the Sierpinsky triangles :
import numpy as np
import matplotlib.pyplot as plt
def sierpin(p, q, r, n):
pass
### p, q and r below are the endpoints of an equilateral triangle, use them to test your code
p = np.array([0,0])
q = np.array([2,0])
r = np.array([1, 3**0.5])
L = sierpin(p, q, r, 4)
def drawTriangles(L):
triangles = []
for a, b, c in L:
triangles += [Polygon([a, b, c], True)]
f, ax = plt.subplots()
ax.add_collection(PatchCollection(triangles))
ax.autoscale()
ax.set_aspect('equal')
plt.axis('off')
plt.show()
drawTriangles(L)
The base figure for the cross looks like this :
You are provided with a function that gives the set of lines that make up this figure. base_figure(scale)
returns the base figure centered at the origin (0,0) and scaled by a factor of scale
.
The n-cross is composed of 8 (n-1)-crosses. Look at the figures below and try finding how you should combine the 8 crosses :
You are provided with the functions :
import numpy as np
import matplotlib.pyplot as plt
def rot(angle, x):
O = np.array([[np.cos(angle), -1*np.sin(angle)], [np.sin(angle), np.cos(angle)]])
return np.dot(O, x)
def shift(angle, dist, x):
vect = dist * np.array([np.cos(angle), np.sin(angle)])
return np.array(x) + vect
def rotfigure(figure, angle):
return [[rot(angle, p[0]), rot(angle, p[1])] for p in figure]
def shiftfigure(figure, angle, dist):
return [[shift(angle, dist, p[0]), shift(angle, dist, p[1])] for p in figure]
def rescale(figure, factor):
return [[factor*np.array(p[0]), factor*np.array(p[1])] for p in figure]
def base_figure(scale):
origin = np.array([0,0])
pi = np.pi
r = 4
v_id = np.array([1,1])
up = np.array([0,1])
right = np.array([1,0])
lst = []
lst.append([origin, origin+scale*v_id])
lst.append([origin+scale*v_id, origin+scale*v_id + r*scale*right])
lst.append([origin+scale*v_id + r*scale*right, origin+scale*v_id + r*scale*right + scale*rot(-pi/2, v_id)])
lst.append([origin+scale*v_id + r*scale*right, origin+scale*v_id + r*scale*right + r*scale*up])
lst.append([origin+scale*v_id + r*scale*right + r*scale*up, origin+scale*v_id + r*scale*right + r*scale*up + scale*v_id])
lst.append([origin+scale*v_id , origin+scale*v_id + r*scale*up])
lst.append([origin+scale*v_id + r*scale*up, origin+scale*v_id + r*scale*up + r*scale*right])
lst.append([origin+scale*v_id + r*scale*up, origin+scale*v_id + r*scale*up + scale*rot(pi/2, v_id)])
#center
center = scale*(1+r/2)*np.array([1,1])
lst = [ [p[0] - center , p[1] - center ] for p in lst ]
return [[rot(pi/4, p[0]), rot(pi/4, p[1])] for p in lst]
def ethiodraw(L):
for pair in L:
a, b = pair
line = plt.Line2D([a[0], b[0]], [a[1], b[1]], lw=2.5, color='k')
plt.gca().add_line(line)
plt.axis('scaled')
plt.axis('off')
#plt.savefig('et0.png', format='png', dpi=300)
plt.show()
### Write your function here
def cross(scale, n):
pass