def position_endpoints_on(self, start, end): curr_vect = self.points[-1] - self.points[0] if np.all(curr_vect == 0): raise Exception("Cannot position endpoints of closed loop") target_vect = end - start self.scale(get_norm(target_vect) / get_norm(curr_vect)) self.rotate(angle_of_vector(target_vect) - angle_of_vector(curr_vect)) self.shift(start - self.points[0]) return self
def apply_transposed_matrix(self, transposed_matrix, **kwargs): func = self.get_transposed_matrix_transformation(transposed_matrix) if "path_arc" not in kwargs: net_rotation = np.mean([ angle_of_vector(func(RIGHT)), angle_of_vector(func(UP)) - np.pi / 2 ]) kwargs["path_arc"] = net_rotation self.apply_function(func, **kwargs)
def rotate(self, angle, axis=OUT, **kwargs): curr_rot_T = self.get_inverse_camera_rotation_matrix() added_rot_T = rotation_matrix_transpose(angle, axis) new_rot_T = np.dot(curr_rot_T, added_rot_T) Fz = new_rot_T[2] phi = np.arccos(Fz[2]) theta = angle_of_vector(Fz[:2]) + PI / 2 partial_rot_T = np.dot( rotation_matrix_transpose(phi, RIGHT), rotation_matrix_transpose(theta, OUT), ) gamma = angle_of_vector(np.dot(partial_rot_T, new_rot_T.T)[:, 0]) self.set_euler_angles(theta, phi, gamma) return self
def put_start_and_end_on(self, start, end): curr_start, curr_end = self.get_start_and_end() curr_vect = curr_end - curr_start if np.all(curr_vect == 0): raise Exception("Cannot position endpoints of closed loop") target_vect = end - start self.scale( get_norm(target_vect) / get_norm(curr_vect), about_point=curr_start, ) self.rotate(angle_of_vector(target_vect) - angle_of_vector(curr_vect), about_point=curr_start) self.shift(start - curr_start) return self
def point_at_angle(self, angle): start_angle = angle_of_vector( self.points[0] - self.get_center() ) return self.point_from_proportion( (angle - start_angle) / TAU )
def angle_of_tangent(self, x: float, graph: ParametricCurve, dx: float = EPSILON) -> float: p0 = self.input_to_graph_point(x, graph) p1 = self.input_to_graph_point(x + dx, graph) return angle_of_vector(p1 - p0)
def angle_of_tangent(self, x, graph, dx=0.01): """ Returns the angle to the x axis of the tangent to the plotted curve at a particular x-value. Parameters ---------- x (Union[int, float]) The x value at which the tangent must touch the curve. graph ParametricFunction The ParametricFunction for which to calculate the tangent. dx (Union(float, int =0.01)) The small change in x with which a small change in y will be compared in order to obtain the tangent. Returns ------- float The angle of the tangent with the x axis. """ vect = self.input_to_graph_point( x + dx, graph) - self.input_to_graph_point(x, graph) return angle_of_vector(vect)
def __init__(self, x_range=None, y_range=None, z_range=None, **kwargs): x_range = self.minmax_to_range("x_min", "x_max", "x_step", x_range, kwargs) y_range = self.minmax_to_range("y_min", "y_max", "y_step", y_range, kwargs) z_range = self.minmax_to_range("z_min", "z_max", "z_step", z_range, kwargs) Axes.__init__(self, x_range, y_range, **kwargs) self.init_vars() if z_range is not None: self.z_range[:len(z_range)] = z_range z_axis = self.create_axis( self.z_range, self.z_axis_config, self.depth, ) z_axis.rotate(-PI / 2, UP, about_point=ORIGIN) #z_axis = self.z_axis = self.create_axis(self.z_min, self.z_max, self.z_axis_config) #z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN) z_axis.rotate(angle_of_vector(self.z_normal), OUT, about_point=ORIGIN) z_axis.shift(self.x_axis.n2p(0)) self.axes.add(z_axis) self.add(z_axis) self.z_axis = z_axis for axis in self.axes: axis.insert_n_curves(self.num_axis_pieces - 1) self.add_3d_pieces() self.set_axis_shading()
def set_points_by_ends(self, start, end, buff=0, path_arc=0): # Find the right tip length and thickness vect = end - start length = max(get_norm(vect), 1e-8) thickness = self.thickness w_ratio = fdiv(self.max_width_to_length_ratio, fdiv(thickness, length)) if w_ratio < 1: thickness *= w_ratio tip_width = self.tip_width_ratio * thickness tip_length = tip_width / (2 * np.tan(self.tip_angle / 2)) t_ratio = fdiv(self.max_tip_length_to_length_ratio, fdiv(tip_length, length)) if t_ratio < 1: tip_length *= t_ratio tip_width *= t_ratio # Find points for the stem if path_arc == 0: points1 = (length - tip_length) * np.array( [RIGHT, 0.5 * RIGHT, ORIGIN]) points1 += thickness * UP / 2 points2 = points1[::-1] + thickness * DOWN else: # Solve for radius so that the tip-to-tail length matches |end - start| a = 2 * (1 - np.cos(path_arc)) b = -2 * tip_length * np.sin(path_arc) c = tip_length**2 - length**2 R = (-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a) # Find arc points points1 = Arc.create_quadratic_bezier_points(path_arc) points2 = np.array(points1[::-1]) points1 *= (R + thickness / 2) points2 *= (R - thickness / 2) if path_arc < 0: tip_length *= -1 rot_T = rotation_matrix_transpose(PI / 2 - path_arc, OUT) for points in points1, points2: points[:] = np.dot(points, rot_T) points += R * DOWN self.set_points(points1) # Tip self.add_line_to(tip_width * UP / 2) self.add_line_to(tip_length * LEFT) self.tip_index = len(self.get_points()) - 1 self.add_line_to(tip_width * DOWN / 2) self.add_line_to(points2[0]) # Close it out self.append_points(points2) self.add_line_to(points1[0]) if length > 0: # Final correction super().scale(length / self.get_length()) self.rotate(angle_of_vector(vect) - self.get_angle()) self.shift(start - self.get_start()) self.refresh_triangulation()
def set_points_by_ends(self, start, end, buff=0, path_arc=0): vect = end - start dist = get_norm(vect) if np.isclose(dist, 0): self.set_points_as_corners([start, end]) return self if path_arc: neg = path_arc < 0 if neg: path_arc = -path_arc start, end = end, start radius = (dist / 2) / math.sin(path_arc / 2) alpha = (PI - path_arc) / 2 center = start + radius * normalize( rotate_vector(end - start, alpha)) raw_arc_points = Arc.create_quadratic_bezier_points( angle=path_arc - 2 * buff / radius, start_angle=angle_of_vector(start - center) + buff / radius, ) if neg: raw_arc_points = raw_arc_points[::-1] self.set_points(center + radius * raw_arc_points) else: if buff > 0 and dist > 0: start = start + vect * (buff / dist) end = end - vect * (buff / dist) self.set_points_as_corners([start, end]) return self
def put_start_and_end_on(self, start, end): curr_start, curr_end = self.get_start_and_end() curr_vect = curr_end - curr_start if np.all(curr_vect == 0): raise Exception("Cannot position endpoints of closed loop") target_vect = end - start self.scale( get_norm(target_vect) / get_norm(curr_vect), about_point=curr_start, ) self.rotate( angle_of_vector(target_vect) - angle_of_vector(curr_vect), about_point=curr_start ) self.shift(start - curr_start) return self
def __init__(self, v1=None, v2=None, start=0, **kwargs): VMobject.__init__(self, **kwargs) self.set_points_as_corners([RIGHT, ORIGIN, self.get_point(v1, v2)]) self.set_width(self.width, about_point=ORIGIN) if start is None and v2 is not None: self.rotate(angle_of_vector(v1), about_point=ORIGIN) elif start!=0: self.rotate(start, about_point=ORIGIN)
def get_point(self, v1, v2): if v1 is not None and v2 is None: if isinstance(v1, (int, float)): self.theta = v1 elif isinstance(v1, (list)): self.theta = angle_of_vector(v1) elif v1 is not None and v2 is not None: self.theta = spaceangle_between(v1, v2) return [np.cos(self.theta), np.sin(self.theta), 0]
def __init__(self, **kwargs): Axes.__init__(self, **kwargs) z_axis = self.z_axis = self.get_axis(self.z_min, self.z_max, self.z_axis_config) z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN) z_axis.rotate(angle_of_vector(self.z_normal), OUT, about_point=ORIGIN) self.add(z_axis) self.add_3d_pieces() self.set_axis_shading()
def get_angle(self): """ Get angle taking the horizontal as a reference Returns ------- Angle : Float """ start, end = self.get_start_and_end() return angle_of_vector(end - start)
def put_start_and_end_on(self, start, end): curr_start, curr_end = self.get_start_and_end() if np.all(curr_start == curr_end): # TODO, any problems with resetting # these attrs? self.start = start self.end = end self.generate_points() curr_vect = curr_end - curr_start if np.all(curr_vect == 0): raise Exception("Cannot position endpoints of closed loop") target_vect = end - start self.scale( get_norm(target_vect) / get_norm(curr_vect), about_point=curr_start, ) self.rotate(angle_of_vector(target_vect) - angle_of_vector(curr_vect), about_point=curr_start) self.shift(start - curr_start) return self
def get_point_from_angle(self, angle): """ Get point from angle Returns ------- Point of angle : 3D array """ start_angle = angle_of_vector(self.points[0] - self.get_center()) return self.point_from_proportion((angle - start_angle) / TAU)
def __init__(self, start_angle=0, angle=TAU/4, arc_center=None, ccw=1, color=GRAY, tip_length=0.1, tip_start=True, tip_end=True, reverse=False, reverse2=False, stroke_width=4, *args, **kwargs): # arc_center=ORIGIN Arc.__init__(self, **kwargs) tip = ArrowTip(length=tip_length,stroke_color=color) if angle != 0: ratio = tip_length/(self.radius*(angle)) else: ratio = tip_length/(self.radius*(start_angle)) if tip_start: tips = tip.copy().move_to(self.point_from_proportion(0) ).shift([tip.get_width()/2, 0, 0]) angle = angle_of_vector(self.point_from_proportion( ratio)-self.point_from_proportion(0)) self.add(tips.rotate(angle, about_point=self.point_from_proportion(0))) if tip_end: tips = tip.copy().move_to(self.point_from_proportion(1) ).shift([tip.get_width()/2, 0, 0]) angle = angle_of_vector(self.point_from_proportion( 1-ratio)-self.point_from_proportion(1)) self.add(tips.rotate(angle, about_point=self.point_from_proportion(1)))
def apply_transposed_matrix(self, transposed_matrix, **kwargs): """ Applies the transformation represented by the given transposed matrix to the number plane, and each vector/similar mobject on it. Parameters ---------- matrix (Union[np.ndarray, list, tuple]) The matrix. **kwargs Any valid keyword argument of self.apply_function() """ func = self.get_transposed_matrix_transformation(transposed_matrix) if "path_arc" not in kwargs: net_rotation = np.mean([ angle_of_vector(func(RIGHT)), angle_of_vector(func(UP)) - np.pi / 2 ]) kwargs["path_arc"] = net_rotation self.apply_function(func, **kwargs)
def position_tip(self, tip, at_start=False): # Last two control points, defining both # the end, and the tangency direction if at_start: anchor = self.get_start() handle = self.get_first_handle() else: handle = self.get_last_handle() anchor = self.get_end() tip.rotate( angle_of_vector(handle - anchor) - PI - tip.get_angle() ) angle = angle_of_vector(handle - anchor) + PI/2 a = np.array((np.cos(angle),np.sin(angle),0)) tip.rotate(-phi_of_vector(handle - anchor),a) tip.shift(anchor - tip.get_tip_point()) return tip
def position_tip(self, tip: ArrowTip, at_start: bool = False) -> ArrowTip: # Last two control points, defining both # the end, and the tangency direction if at_start: anchor = self.get_start() handle = self.get_first_handle() else: handle = self.get_last_handle() anchor = self.get_end() tip.rotate(angle_of_vector(handle - anchor) - PI - tip.get_angle()) tip.shift(anchor - tip.get_tip_point()) return tip
def __init__(self, start_angle=0, angle=TAU/4, arc_center=None, radius=None, color=None,tip_length=None, tip_start=True, tip_end=True, quad=1, ccw=1, **kwargs): digest_config(self, kwargs) GeomArc.__init__(self, start_angle=start_angle, angle=angle, arc_center=arc_center, radius=radius or self.radius,tip_length=tip_length, tip_start=tip_start, tip_end= tip_end, quad=quad, ccw=ccw,**kwargs) arc_length=self.radius*self.angle tip_length=tip_length or min(0.1,max(0.06,0.1*arc_length)) tip = GeomArrowTip(length=tip_length,width=self.stroke_width/100*3) if self.angle != 0: ratio = tip_length/arc_length else: ratio = tip_length/(radius*(self.start_angle)) if tip_start: tips = tip.copy().move_to(self.point_from_proportion(0) ).shift([tip.get_width()/2, 0, 0]) angle = angle_of_vector(self.point_from_proportion( ratio)-self.point_from_proportion(0)) self.add(tips.rotate(angle, about_point=self.point_from_proportion(0))) if tip_end: tips = tip.copy().move_to(self.point_from_proportion(1) ).shift([tip.get_width()/2, 0, 0]) angle = angle_of_vector(self.point_from_proportion( 1-ratio)-self.point_from_proportion(1)) self.add(tips.rotate(angle, about_point=self.point_from_proportion(1))) self.set_color(color or self.color)
def display_image_mobject(self, image_mobject, pixel_array): corner_coords = self.points_to_pixel_coords( image_mobject, image_mobject.points ) ul_coords, ur_coords, dl_coords = corner_coords right_vect = ur_coords - ul_coords down_vect = dl_coords - ul_coords center_coords = ul_coords + (right_vect + down_vect) / 2 sub_image = Image.fromarray( image_mobject.get_pixel_array(), mode="RGBA" ) # Reshape pixel_width = max(int(pdist([ul_coords, ur_coords])), 1) pixel_height = max(int(pdist([ul_coords, dl_coords])), 1) sub_image = sub_image.resize( (pixel_width, pixel_height), resample=Image.BICUBIC ) # Rotate angle = angle_of_vector(right_vect) adjusted_angle = -int(360 * angle / TAU) if adjusted_angle != 0: sub_image = sub_image.rotate( adjusted_angle, resample=Image.BICUBIC, expand=1 ) # TODO, there is no accounting for a shear... # Paste into an image as large as the camear's pixel array full_image = Image.fromarray( np.zeros((self.get_pixel_height(), self.get_pixel_width())), mode="RGBA" ) new_ul_coords = center_coords - np.array(sub_image.size) / 2 new_ul_coords = new_ul_coords.astype(int) full_image.paste( sub_image, box=( new_ul_coords[0], new_ul_coords[1], new_ul_coords[0] + sub_image.size[0], new_ul_coords[1] + sub_image.size[1], ) ) # Paint on top of existing pixel array self.overlay_PIL_image(pixel_array, full_image)
def position_tip(self, tip, at_start=False): # Last two control points, defining both # the end, and the tangency direction if at_start: anchor = self.get_start() handle = self.get_first_handle() else: handle = self.get_last_handle() anchor = self.get_end() tip.rotate( angle_of_vector(handle - anchor) - PI - tip.get_angle() ) tip.shift(anchor - tip.get_tip_point()) return tip
def add_label_xyzStr(self): texVGroup = [TexMobject(str_xyz) for str_xyz in ("x", "y", "z")] texVGroup[0].next_to(self.x_axis, DR, buff=SMALL_BUFF / 100) self.x_axis.add(texVGroup[0]) texVGroup[1].rotate(90 * DEGREES, about_point=ORIGIN) texVGroup[1].next_to(self.y_axis, UR, buff=SMALL_BUFF / 100) self.y_axis.add(texVGroup[1]) texVGroup[2].rotate(-np.pi / 2, UP, about_point=ORIGIN) texVGroup[2].rotate(angle_of_vector(self.z_normal), OUT, about_point=ORIGIN) texVGroup[2].next_to(self.z_axis, OUT + LEFT, buff=SMALL_BUFF / 100) self.z_axis.add(texVGroup[2])
def __init__(self, x_range=None, y_range=None, z_range=None, **kwargs): Axes.__init__(self, x_range, y_range, **kwargs) z_axis = self.create_axis( z_range or self.z_range, self.z_axis_config, self.depth, ) z_axis.rotate(-PI / 2, UP, about_point=ORIGIN) z_axis.rotate(angle_of_vector(self.z_normal), OUT, about_point=ORIGIN) z_axis.shift(self.x_axis.n2p(0)) self.axes.add(z_axis) self.add(z_axis) self.z_axis = z_axis for axis in self.axes: axis.insert_n_curves(self.num_axis_pieces - 1)
def __init__(self, **kwargs): #### EULERTOUR_INIT_START #### if not hasattr(self, "args"): self.args = serialize_args([]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) #### EULERTOUR_INIT_START #### Axes.__init__(self, **kwargs) z_axis = self.z_axis = self.create_axis( self.z_min, self.z_max, self.z_axis_config ) z_axis.rotate(-np.pi / 2, UP, about_point=ORIGIN) z_axis.rotate( angle_of_vector(self.z_normal), OUT, about_point=ORIGIN ) self.axes.add(z_axis) self.add(z_axis) self.add_3d_pieces() self.set_axis_shading()
def stop_angle(self): return angle_of_vector(self.points[-1] - self.get_arc_center()) % TAU
def angle_of_tangent(self, x, graph, dx=EPSILON): p0 = self.input_to_graph_point(x, graph) p1 = self.input_to_graph_point(x + dx, graph) return angle_of_vector(p1 - p0)
def get_angle(self): start, end = self.get_start_and_end() return angle_of_vector(end - start)
def angle_of_tangent(self, x, graph, dx=0.01): vect = self.input_to_graph_point( x + dx, graph) - self.input_to_graph_point(x, graph) return angle_of_vector(vect)
def get_needle_angle(self): return angle_of_vector( self.get_needle_tip() - self.get_center() )
def get_angle(self): return angle_of_vector(self.get_vector())
def stop_angle(self): return angle_of_vector( self.points[-1] - self.get_arc_center() ) % TAU