Conics from Circles (Animation)
This example demonstrates an animation illustrating
the construction of an ellipse using circles
in the Euclidean plane.
You can see the full code at
conics_from_circles.py.
Setup
We start off by importing the necessary libraries.
# Import necessary libraries and modules
import bpy
import numpy as np
import ddg
from ddg.geometry import euclidean_models
from ddg.geometry.subspaces import subspace_from_affine_points as sfap
from ddg.visualization import blender
We are also going to clear the whole scene and create the geometry we will be working in.
# Clear existing objects and materials in Blender scene
blender.object.clear()
blender.material.clear()
EUC2D = euclidean_models.ProjectiveModel(2)
Calculations
Now we are going to define the calculations necessary for this visualization. First we define a function calculates a smaller circle centered on the constructed ellipse and tangent to the larger circle.
# Function to calculate a smaller circle centered on the ellipse
def small_circle(theta, ellipse, F1):
"""Returns smaller circle with center on the ellipse and tangent to big circle.
Parameters
----------
theta : float
Plugged into a parametrization of the ellipse to find center of small circle.
2 pi - periodic.
ellipse : Quadric
The ellipse from the construction
F1 : Point
Returns
-------
ddg.geometry.spheres.SphereLike
Euclidean sphere
"""
sn = ddg.to_smooth_net(ellipse, affine=True)
c = sfap(sn(theta))
r = np.linalg.norm(c.affine_point - F1.affine_point)
return EUC2D.sphere(c, r)
Then we are going to define the larger circle with a specified center (F2) and radius, as well as a point F1.
# Define the properties of the big circle and the foci F1 and F2
big_circle = EUC2D.sphere(sfap([1, 1]), 2)
F2 = big_circle.center
big_r = big_circle.radius
F1 = sfap([2, 1.5])
# The fact that a=big_r/2 can be seen by considering a single circle with
# center on the line connecting F1 and F2.
ellipse = EUC2D.ellipse_from_foci(F1, F2, big_r / 2)
Visualization
Now we can begin with the visualization process. We start off by setting up the camera and configuring some render settings.
# Define visualization settings
SAMPLING = [0.1, 100, "c"]
SCENE = bpy.context.scene
WORLD = bpy.data.worlds["World"]
# Create and configure camera and rendering settings
camera = blender.camera.camera(
type_="ORTHO",
location=(F2.embed().affine_point + np.array([0.0, 0.0, 2.0])),
)
blender.camera.look_at_point(camera, F2.embed().affine_point)
# Change this if the radius of the big circle changes
camera.data.ortho_scale = 5.0
SCENE.camera = camera
SCENE.render.resolution_x = SCENE.render.resolution_y = 1024
# Make world background transparent
SCENE.render.film_transparent = True
# Set render engine to Eevee because it's orders of magnitude faster and
# suffices for this application
SCENE.render.engine = "BLENDER_EEVEE"
SCENE.view_settings.view_transform = "Raw"
# Set world color to pure white and (emission?) strength to 0.5
WORLD.node_tree.nodes["Background"].inputs[0].default_value = (1, 1, 1, 1)
WORLD.node_tree.nodes["Background"].inputs[1].default_value = 1
Next we create materials and colors.
# Create materials and define colors
COL_BIG_CIRCLE = np.array([168, 32, 26]) / 255
COL_SMALL_CIRCLE = np.array([236, 154, 41]) / 255
COL_ELLIPSE = np.array([15, 136, 141]) / 255
mat_small_circle = blender.material.material(
color=COL_SMALL_CIRCLE, name="Small circle"
)
mat_big_circle = blender.material.material(
color=COL_BIG_CIRCLE, name="Big circle", alpha=0.5
)
mat_ellipse = blender.material.material(color=COL_ELLIPSE, name="Ellipse")
And now we can visualze the objects in Blender.
# Render regular objects
ddg.to_blender_object_helper(
EUC2D.sphere_to_quadric(big_circle).embed(),
sampling=SAMPLING,
material=mat_big_circle,
)
ddg.to_blender_object_helper(F2.embed(), sphere_radius=0.04, material=mat_big_circle)
ddg.to_blender_object_helper(F1.embed(), sphere_radius=0.04, material=mat_ellipse)
ddg.to_blender_object_helper(ellipse.embed(), sampling=SAMPLING, material=mat_ellipse)
Animation
Finally, to get the animations we first define the following function.
# Function to generate small circles during animation
def small_circle_callback(theta):
sc = small_circle(theta, ellipse, F1)
return [
ddg.to_blender_object_helper(
EUC2D.sphere_to_quadric(sc).embed(),
sampling=SAMPLING,
link=False,
material=mat_small_circle,
curve_properties={"bevel_depth": 0.0125},
),
ddg.to_blender_object_helper(
sc.center.embed(), sphere_radius=0.04, material=mat_small_circle
),
]
And then set some animation settings.
# Add animation properties and keyframes
blender.props.add_props_with_callback(
blender.props.clear_callback("small circle", small_circle_callback), ["theta"], 0.0
)
FPS = 50
blender.animation.clear_animation_data(SCENE)
blender.animation.set_keyframe(SCENE, 0 * FPS, "theta", 0.0)
blender.animation.set_keyframe(SCENE, 3 * FPS, "theta", 2 * np.pi)
blender.animation.set_end_frame(3 * FPS)