.. _stereographic_projection: Möbius Pencil of Circles ======================== .. image:: rendered_planar_pencil.png :width: 800px :align: center In this tutorial, our aim is to visualize pencils of Möbius circles. This is explained below, expecting a bit of basic knowledge of geometry. If you are not that interested, or do not completely understand the mathematical background - that is okay too. You can still go on with the tutorial. The nice thing about visualization is, it helps us understand what is happening. .. image:: mob_pencil_1_and_2.png :width: 800px :align: center In the following, we explain how to create this python script: :download:`Möbius Pencil of Circles Script <../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py>`, and use it to visualize the objects in Blender. .. contents:: Table of contents :local: :backlinks: none Mathematical Background ----------------------- What is a **Möbius pencil of circles**? Möbius geometry in :math:`\widehat{\mathbb{R}^2} = \mathbb{R}^{2} \cup \{\infty\}` corresponds to geometry on the unit sphere :math:`S^2` via stereographic projection. Thus, circles in two-dimensional Möbius geometry correspond to circles on :math:`S^2`, which are intersections of :math:`S^2` with planes. By polarity, a plane intersecting :math:`S^2` corresponds to a point outside :math:`S^2`. If we now consider a line in :math:`\mathbb{R}^3`, by polarity its points define a one-parameter-family of planes in :math:`\mathbb{R}^3` and therefore a one-parameter-family of spherical circles, and hence - via stereographic projection - a so called Möbius pencil of circles in :math:`\widehat{\mathbb{R}^2}`. The one-parameter-family of planes all intersect in a common line, the polar line of the given line, which again represents a Möbius pencil of circles. In :math:`\widehat{\mathbb{R}^2}` this polar pencil represents a family of circles where each circle intersects all circles in the first pencil orthogonally. Setup ----- Start Blender from the terminal, so you can read error-messages. More on how to start and setup Blender, you find here: :ref:`Getting Started with Blender`. In the Blender GUI, create a new script, add the following imports to your new script, and execute with "Alt"+"P". .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [imports] :end-before: [imports] In this script, our aim is to produce a lot of Blender objects, and e.g. display them independently from one another. For this, we will use **Blender collections**. To start with a clean Blender file we clear everything in there using a mechanism that removes all the collections and clears all the objects within. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [clear] :end-before: [clear] For more on the clear module, see :ref:`here `. New collections can be created with the library as follows: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [collection setup] :end-before: [collection setup] You can pass a list of `children` to the function :py:meth:`~ddg.visualization.blender.collection.collection`. If an entry of the list is a string, it will create a child with corresponding name. If an entry of the list is a list of strings, the first string determines the name of the child collection, the others will create grandchildren, i.e children of the childs collection. If the parent collection already exists, it greps the one with this name, and returns this collection object. We are ready to create some objects. Sphere and Line --------------- **Sphere** First, we want to **create the sphere** as a :py:class:`~ddg.geometry.quadrics.Quadric`. Add the following to your script. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [create sphere as quadric] :end-before: [create sphere as quadric] A :py:class:`~ddg.geometry.quadrics.Quadric` is created by its symmetric matrix. More information on Quadrics, you can find :ref:`here `. To display the sphere in Blender, we have to **convert it to a Blender object**. This is easily done with the **helper function** :py:meth:`~ddg.conversion.blender.to_blender_object_helper`! .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [display sphere] :end-before: [display sphere] As for any smooth object, for the quadric to be displayed in Blender, it needs to be discretized using a **sampling**. The sampling options, as explained :ref:`here `, are given as an argument. Internally the quadric is converted to a :py:class:`~ddg.datastructures.nets.net.SmoothNet` and then, by a sampling, converted to a :py:class:`~ddg.datastructures.nets.net.DisreteNet`. Have a look at the :ref:`nets ` user's guide. The given name determines the name of the object in Blender. .. image:: sphere0.png :width: 600px :align: center **Line** Next, we want to create and display a **line**. For that, we use :py:class:`~ddg.geometry.subspaces.Subspace`, which is a class for projective subspaces. Here we give two examples one line that intersects the sphere and another line that is tangential to the sphere. With these two you can generate the configurations of the images at the top. So let's choose .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [create line as subspace] :end-before: [create line as subspace] A subspace can be simply defined by the vectors that span it. Note, that we want a line in 3D projective space, which corresponds to a 2D vector subspace of :math:`\mathbb{R}^4`. That's why we have two 4D vectors. More on subspaces, you can find :ref:`here `. Next, we create a :py:class:`~ddg.datastructures.nets.net.SmoothNet` out of the subspace, to obtain an affine image of the projective subspace, that is a **line in 3D space**. Before we do so, we orthonormalize and center the subspace. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [line to smooth net] :end-before: [line to smooth net] The argument `affine` is given to obtain an affine image of the projective line. The `convex=True` argument means, that the net function of the resulting SmoothNet is the convex combination of the vectors spanning the subspace. By setting the domain of the SmoothNet to `domain=[[-4,4]]`, we obtain a line segment symmetrical around the center of the line. And finally, we convert it to a Blender object by: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [line to blender object] :end-before: [line to blender object] The given `domain` is interpreted as domain of the net function and determines the length of the line. We add the line to the `collection` we created. The last argument, given in this form of a dictionary, determines the thickness of the line. Feel free to play with it. .. image:: sphere1.png :width: 600px :align: center Spherical and Planar Circles ---------------------------- Next, we will see how a point on the line l corresponds to a circle on s2, and how the spheric circle corresponds to a planar circle. **Spherical Circles** For a given point, we want to calculate its **polar plane** with respect to s2, as well as the **intersection** of the plane with s2. These intersection should then be converted to **blender objects**, so that we can see them. And this gives us our spherical circles. We choose a point on our line l. When given a point of its domain as an argument, a :py:class:`~ddg.datastructures.nets.net.SmoothNet` returns its value at this point: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [get a point] :end-before: [get a point] Now, we want to display the sampled point in Blender, as a little sphere. The sampled point is just an affine image of a point on l. We homogenize it, .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [homogenize point] :end-before: [homogenize point] and convert it to a :py:class:`~ddg.geometry.subspaces.Subspace`. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [convert point to subspace] :end-before: [convert point to subspace] We give the radius for the size of the sphere that visualizes the point. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [display point] :end-before: [display point] Now, we can make use of the methods for Subspaces and calculate the polar plane .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [calculate polar plane] :end-before: [calculate polar plane] and calculate the intersection of it with the sphere. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [calculate intersection circle] :end-before: [calculate intersection circle] Trying to convert an empty intersection to a blender object yields an error, so first, we check if the intersection is empty by checking its dimension. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [check for empty intersection] :end-before: [check for empty intersection] This gives us: .. image:: sphere2.png :width: 600px :align: center **Planar Circles** Next, we want to stereographically project the spherical circle onto the plane. For this we create a plane to project on as a subspace and stereographically project the circle: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [stereographic project and display circle] :end-before: [stereographic project and display circle] In general the function :py:func:`~ddg.geometry.projections.stereographic_project` takes the point to project from and the plane to project to as arguments. In our case the projection point, the north pole, is precisely the default argument of the function. And we get: .. image:: sphere3.png :width: 600px :align: center We can also obtain the planar circles in a different way, using a Blender light and looking at its shadow. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [stereographic project with a light] :end-before: [stereographic project with a light] Here you may want to move the plane `euc_plane` a little bit lower so it does not intersect s2 so you can see the shadow of all circles. If you want to see the shadow in Blender you have to select the `Rendered Viewport Shading`. .. image:: rendered_viewport.png :width: 600px :align: center Möbius Pencil of Circles ------------------------ If we now consider the corresponding circles for all points on a line, that is called a **Möbius pencil of circles**. To visualize this pencil, we need to choose some points on the line, and then for each point proceed as above. **Circles Function for a Point** First, we write a function that takes a point and creates the corresponding spherical and planar circle. This function does the job: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :pyobject: circles_from_point **Wrapper Function for Points on a Line** We want to apply the above funtion to multiple points on a line. For that, we write a function that takes a line and a parameter as input, and calls the spheric_and_planar_circles function to create the corresponding circles: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :pyobject: circles_from_line_and_value Get the corresponding circles for a point on l by: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [get circles for a point] :end-before: [get circles for a point] **Adding a Slider for a Varying Point on Line** Next, we will add a slider to the blender GUI, with which we can regulate certain parameters in the creation of our objects. This is explained in more detail in :ref:`this ` docs entry. In our case, we want to vary the parameter which determines the point on the line l. The following code will add such a slider: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [add slider] :end-before: [add slider] To find the slider in the blender GUI, go to the viewport, press "N" to open the side menu, and go to the "DDG" tab. There it is. .. image:: find_slider.png :width: 600px :align: center Change the parameter t, to see how the point and the circles change! But **be careful** sliders don't work (well) with collections as they modify collections themselves. Its better not to work with collections when using sliders. **Visualize some Circles in Pencil** To get a nice image of the pencil, we can sample points on the corresponding line, and then plot the circles for each of the points. First, we need a sampling of the domain of the line. That is, a list with numbers. Let's use linear sampling here (equidistant points). Of course you could try something else at home. It's also fun to play with the number of samples. .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [sample domain of line] :end-before: [sample domain of line] In the sampling, the first two arguments correspond to the domain of the lines, and the third is the number of samples. Now, we can easily create some circles in the pencil: .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [visualize pencil] :end-before: [visualize pencil] It is very useful, to pass collections here, so we can hide and show the different groups of objects as we wish. For example, hiding the collections with the points gives us: .. image:: visualize_pencil.png :width: 600px :align: center Nice! Orthogonal Pencil ----------------- Consider the Möbius pencil of circles for the **polar line** of l. All circles of this pencil intersect all circles in the pencil corresponding to l orthogonally. With pyddg, we can easily polarize the :py:class:`~ddg.geometry.subspaces.Subspace` l with respect to the :py:class:`~ddg.geometry.quadrics.Quadric` s2 to obtain the polar line as a :py:class:`~ddg.geometry.subspaces.Subspace`. We then proceed as before, to create the corresponding orthogonal pencil! .. literalinclude:: ../../../../examples/blender/docs/tutorials_and_examples/moebius_pencil_of_circles.py :language: python :start-after: [orthogonal pencil] :end-before: [orthogonal pencil] And we get: .. image:: visualize_orth_pencil.png :width: 600px :align: center Render an Image --------------- Before we render an image, we need to add a camera and light to the Blender scene and create materials for our objects. How to create a **setup and render** an image is explained here: :ref:`Render a Picture of a Geometric Object`. **Materials** can be created and assigned to objects in the blender GUI. If you have a lot of objects, it's convenient to assign materials via script! Basic materials can also be created in the script, as explained here: :ref:`Creating and Setting Materials`. By **hiding** and **showing** different collections in the blend file we created, we can then render beautiful images, like: .. image:: rendered_planar_pencil.png :width: 800px :align: center