#!/usr/bin/env python # coding: utf-8 # # Things that are nice to look at and how to draw them # #
#
# We're going to be drawing things. So first, let's choose how we're going to represent points, lines and figures. # # #### Representing Points in Python # # 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. # # #### Representing Lines 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. # ## Dragon Curve # # 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 : #
# #
# # #### Recursive definition of the dragon curve # # 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. # # # In[ ]: 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. # In[ ]: 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. # In[62]: 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 : # # # ## Sierpinsky triangles # # # # #### Representing Triangles in Python # # 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. # # #### Exercice # # Here are examples of the Sierpinsky triangles : # # # # # # # #
# The triangles are equilateral. Write a recursive function `sierpinsky(p, q, r, n)` that takes three points `p, q, r` (the endpoints of an equilateral triangle), an integer `n` and returns the list of triangles that make up the n-th sierpinsky triangle. # # In[ ]: 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 Ethiopian-Orthodox Cross (Hard) # # #
#
# The Ethiopian-Orthodox cross can be approximated by a fractal. We're going to try drawing this : # # # # # 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 recursive definition : # # # 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 : # # # # # # # #

0-cross

1-cross

2-cross
# # You are provided with the functions : # ** The angles are in radians **
# Use these function to draw the ethiopian cross. (Use trial and error to figure out scaling and shifting parameters) # # In[64]: 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() # In[ ]: ### Write your function here def cross(scale, n): pass # In[ ]: