Message Boards Message Boards


[GIF] Caught (Voronoi cells of stereographically projected pattern)

Posted 1 year ago
4 Replies
6 Total Likes

Voronoi cells of stereographically projected pattern


Continuing with the stereographic projection theme. This time, I generated a bunch of points arranged in spirals on the sphere, like so:

Points on the sphere

Then I stereographically project the points to the plane and compute the Voronoi diagram of the resulting points. Throw in a rotation of the sphere and you get the above animation.

As for the code, first of all we need the stereographic projection map:

Stereo[p_] := p[[;; -2]]/(1 - p[[-1]])

Next, we need to define the points. It turned out that without throwing in some noise in the definition of the points, VoronoiMesh[] would occasionally fail, which is why I put in the RandomVariate[] business in both cylindrical coordinates:

pts = With[{n = 20},
    CoordinateTransformData["Cylindrical" -> "Cartesian", "Mapping"]
     [{Sqrt[1 - (z + #)^2], θ + RandomVariate[UniformDistribution[{-.00001, .00001}]] 
         + (z + # + 2)/2 * π/2, z + #}
       &[RandomVariate[UniformDistribution[{-.00001, .00001}]]]
    {z, -.9, .9, 2/n}, {θ, 0, 2 π - 2 π/n, 2 π/n}]

Finally, then, here's the animation:

With[{cols = RGBColor /@ {"#F5841A", "#03002C"}},
   Stereo[RotationMatrix[θ, {1., 0, 0}].#] & /@ Flatten[pts, 1],
   {{-4.1, 4.1}, {-4.1, 4.1}}, PlotTheme -> "Lines", PlotRange -> 4, 
   MeshCellStyle -> {{1, All} -> Directive[Thickness[.005], cols[[1]]]},
   ImageSize -> 540, Background -> cols[[-1]]],
  {θ, 0, π}
4 Replies
Posted 1 year ago

Yes, the implementation in my reply is intended for en masse application of the stereographic transformation. If I were implementing Stereo[], I would maintain both implementations, and use an argument check so that the applicable method is used.

That is: Stereo[pt_?VectorQ] := (* stuff *) would be the one-point case, corresponding to your implementation, and Stereo[pt_?MatrixQ] := (* stuff *) would be the many-point case, corresponding to my implementation.


Ah, that's a good point! Even after all these years, I think I still have a bit of a mental block about representations of vectors in Mathematica, but of course you're quite right that a list of vectors can be interpreted as a matrix whose rows are the given vectors.

I don't like your redefinition of Stereo[] as much: with your definition I can't apply it to a single point, only to a list of points. Of course, in this particular example I am applying to to a list of points, but this is a function that I reuse constantly, including in circumstances when I want to apply it to single points.

Posted 1 year ago

Here are some quick tips for your future artwork:

  1. The operation RotationMatrix[θ, {1, 0, 0}].# & /@ pts can be recast into a more efficient form with a little linear algebra. Briefly, if you are mapping a premultiplication by a matrix over a list of points, this is equivalent to postmultiplying the list of points by the transpose of the matrix. That is, A.# & /@ list is just the same as list.Transpose[A].

In this case, it is very fortuitous that the transpose of RotationMatrix[] takes on a very convenient form. To sum up, the compact version of this operation is pts.RotationMatrix[-θ, {1, 0, 0}].

  1. You can redefine your function Stereo[] so that it acts on a list of points en masse, instead of you having to map it over each point:

    Stereo[pts_?MatrixQ] := Drop[pts, None, -1]/(1 - pts[[All, -1]])

With these considerations, we can redo the heart of your code as

Stereo[Flatten[pts, 1].RotationMatrix[-θ, {1, 0, 0}]]

with Stereo[] defined for a list of points.

Anyway, nice artwork, as always! :)


enter image description here - Congratulations! This post is now a Staff Pick as distinguished by a badge on your profile! Thank you, keep it coming!

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract