generated from mwc/project_drawing
	ellipse file to include
This commit is contained in:
		
							
								
								
									
										112
									
								
								ellipse.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								ellipse.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					from math import pi, sqrt, sin, cos, atan
 | 
				
			||||||
 | 
					from turtle import penup, pendown, forward, left, radians, degrees
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					π = pi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def ellipse(rx, ry, num_points, points_to_draw=None):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Draws an ellipse with x-radius rx and y-radius ry, 
 | 
				
			||||||
 | 
					    with num_points control points. Optionally specify
 | 
				
			||||||
 | 
					    points_to_draw if you want only a partial ellipse.
 | 
				
			||||||
 | 
					    Assumes the turtle starts at the center, pointed in 
 | 
				
			||||||
 | 
					    the +x direction, and ends in the same position and heading.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    radians()
 | 
				
			||||||
 | 
					    φstart = get_angle(rx, ry, num_points, 0) / 2
 | 
				
			||||||
 | 
					    fly(rx)
 | 
				
			||||||
 | 
					    left(π/2 - φstart) 
 | 
				
			||||||
 | 
					    for i in range(points_to_draw or num_points):
 | 
				
			||||||
 | 
					        φi = get_angle(rx, ry, num_points, i)
 | 
				
			||||||
 | 
					        di = get_distance(rx, ry, num_points, i)
 | 
				
			||||||
 | 
					        print(i, φi, di)
 | 
				
			||||||
 | 
					        left(φi)
 | 
				
			||||||
 | 
					        forward(di)
 | 
				
			||||||
 | 
					    left(-π/2 + φstart)
 | 
				
			||||||
 | 
					    fly(-rx)
 | 
				
			||||||
 | 
					    degrees()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def fly(distance):
 | 
				
			||||||
 | 
					    """Like forward, but with the pen up.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    penup()
 | 
				
			||||||
 | 
					    forward(distance)
 | 
				
			||||||
 | 
					    pendown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_angle(rx, ry, n, i):
 | 
				
			||||||
 | 
					    """Returns the angle φi, or how far left the turtle should
 | 
				
			||||||
 | 
					    turn at point i of n. 
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    coords_prev = get_coordinates(rx, ry, n, i - 1)
 | 
				
			||||||
 | 
					    coords      = get_coordinates(rx, ry, n, i)
 | 
				
			||||||
 | 
					    coords_next = get_coordinates(rx, ry, n, i + 1)
 | 
				
			||||||
 | 
					    vec_prev = get_vector(coords_prev, coords)
 | 
				
			||||||
 | 
					    vec_next = get_vector(coords, coords_next)
 | 
				
			||||||
 | 
					    vec_parallel, vec_perpendicular = project_onto_basis(vec_next, vec_prev)
 | 
				
			||||||
 | 
					    φi = atan(mag(vec_perpendicular) / mag(vec_parallel))
 | 
				
			||||||
 | 
					    return φi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_distance(rx, ry, n, i):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Returns the distance from point i to point i + 1.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    coords      = get_coordinates(rx, ry, n, i)
 | 
				
			||||||
 | 
					    coords_next = get_coordinates(rx, ry, n, i + 1)
 | 
				
			||||||
 | 
					    vec_next = get_vector(coords, coords_next)
 | 
				
			||||||
 | 
					    return mag(vec_next)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_coordinates(rx, ry, n, i):
 | 
				
			||||||
 | 
					    """Returns the (x, y) coordinates of point i for the ellipse
 | 
				
			||||||
 | 
					    specified by rx, ry, and n.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Normally, we can get the coordinates of a point on the circle
 | 
				
			||||||
 | 
					    at angle θ as (r * cos(θ), r * sin(θ)). An ellipse is a circle
 | 
				
			||||||
 | 
					    scaled differently along the x- and y- axes, so we need to
 | 
				
			||||||
 | 
					    apply different scaling factors rx and ry. 
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    θi = 2*π*i/n
 | 
				
			||||||
 | 
					    xi = rx * cos(θi)
 | 
				
			||||||
 | 
					    yi = ry * sin(θi)
 | 
				
			||||||
 | 
					    return xi, yi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_vector(start, end):
 | 
				
			||||||
 | 
					    """Returns a vector from the start point to the end point. 
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    x0, y0 = start
 | 
				
			||||||
 | 
					    x1, y1 = end
 | 
				
			||||||
 | 
					    return (x1 - x0, y1 - y0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def project_onto_basis(vec, basis):
 | 
				
			||||||
 | 
					    """Projects a vector onto a basis vector, returning two vectors:
 | 
				
			||||||
 | 
					    the component which is parallel to basis (vec_a) and the component which 
 | 
				
			||||||
 | 
					    is perpendicular (vec_b). 
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    v0, v1 = vec
 | 
				
			||||||
 | 
					    unit_basis = normalize(basis)
 | 
				
			||||||
 | 
					    b0, b1 = unit_basis
 | 
				
			||||||
 | 
					    len_a = dot(vec, unit_basis)
 | 
				
			||||||
 | 
					    vec_a = (len_a * b0, len_a * b1)
 | 
				
			||||||
 | 
					    vec_b = get_vector(vec_a, vec)
 | 
				
			||||||
 | 
					    return vec_a, vec_b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def dot(vec0, vec1):
 | 
				
			||||||
 | 
					    """Computes the dot product of vec0 and vec1. 
 | 
				
			||||||
 | 
					    The result is the magnitude of vec0 projected onto vec1.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    x0, y0 = vec0
 | 
				
			||||||
 | 
					    x1, y1 = vec1
 | 
				
			||||||
 | 
					    return x0 * x1 + y0 * y1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def normalize(vec):
 | 
				
			||||||
 | 
					    """Scales vec to magnitude 1.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    x, y = vec
 | 
				
			||||||
 | 
					    len_vec = mag(vec)
 | 
				
			||||||
 | 
					    return x / len_vec, y / len_vec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def mag(vec):
 | 
				
			||||||
 | 
					    """Returns the magnitude, or length, of a vector.
 | 
				
			||||||
 | 
					    We can simplify the familiar formula sqrt(x*x + y*y)
 | 
				
			||||||
 | 
					    using the dot product. 
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    return sqrt(dot(vec, vec))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user