<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://elfnor.com//feed.xml" rel="self" type="application/atom+xml" /><link href="https://elfnor.com//" rel="alternate" type="text/html" /><updated>2026-07-24T02:04:48+00:00</updated><id>https://elfnor.com//feed.xml</id><title type="html">Look, Think, Make</title><subtitle>elfnor&apos;s blog</subtitle><entry><title type="html">Conway Polyhedra in Geometry Nodes</title><link href="https://elfnor.com//2026-07-11-conway-polyhedra-in-geometry-nodes.html" rel="alternate" type="text/html" title="Conway Polyhedra in Geometry Nodes" /><published>2026-07-11T00:00:00+00:00</published><updated>2026-07-11T00:00:00+00:00</updated><id>https://elfnor.com//conway-polyhedra-in-geometry-nodes</id><content type="html" xml:base="https://elfnor.com//2026-07-11-conway-polyhedra-in-geometry-nodes.html"><![CDATA[<p><a href="https://www.blender.org/">Blender 5.2</a> has a <a href="https://docs.blender.org/manual/en/5.2/modeling/geometry_nodes/mesh/operations/mesh_bevel.html">Mesh Bevel Node</a>!!!</p>

<p>This inspired me to revisit my old work on <a href="https://elfnor.com/conway-polyhedron-operators-in-sverchok.html">Conway Polyhedron Operators</a>. I’ve  had a couple of (unpublished) attempts to implement these in Blender’s Geometry Nodes, but was limited by the lack of a mesh bevel node (and my skill level).</p>

<p><a href="https://en.wikipedia.org/wiki/Conway_polyhedron_notation">Conway Polyhedra</a> are formed by applying various operators to a seed polyhedron such as one of the platonic solids. Some of these are the same as nodes already available , for example, the <em>ortho</em> operator is the same as the <em>Subdivide Mesh Node</em> with <em>Level</em> set to  1. Other operators are easily done in edit mode, for example, the <em>kis</em> operator is the same as  <em>Poke Faces</em> on the  Face menu.</p>

<p>For an overview of the operators see <a href="https://en.wikipedia.org/wiki/Conway_polyhedron_notation">wikipedia</a> To play online with the operators see either <a href="https://levskaya.github.io/polyhedronisme/">polyhédronisme</a> or <a href="https://georgehart.com/conway/">George Hart</a>. I’ve implemented most of the Conway Operators in a <a href="https://github.com/elfnor/blend_examples/tree/main">blend file</a> available on GitHub. All the useful node groups are marked as assets and will be available in the asset browser if you save the blend file  on an asset library path. ( for example  <code class="language-plaintext highlighter-rouge">~/Documents/Blender/Assets</code>)</p>

<p>In this post, rather than go into detail on every node group, I’m going to give an overview of the groups I’ve made. I hope to follow up with some  posts grouped on topic rather than node group. I have  a post  planned on evaluating attributes across domains, and another on debugging and testing strategies.</p>

<h2 id="conway-assets">Conway assets</h2>

<p>The blend file contains sixteen operators
<img src="/images/2026-07-11/Pasted%20image%2020260709-115336.png" alt="Conway Operator nodes" /></p>

<p>There’s also a bunch of seed polyhedra and seed tiles to combine with the operators.</p>

<p><img src="/images/2026-07-11/Pasted%20image%2020260709-120256.png" alt="" /></p>

<p>These are simple to construct  but its useful to have them easily accessible with a unit radius.</p>

<p>All the operators also work on 2D mesh tilings. There’s a node group for triangles, squares and hexagons. These are approximately 2 m by 2 m and centred at the origin.</p>

<p><img src="/images/2026-07-11/Pasted%20image%2020260709-120556.png" alt="" /></p>

<p>Each of the above sets of nodes has an overall node with a drop down menu  to quickly switch between operators or between seeds. This is quicker for experimenting with combining operators than rewiring nodes.</p>

<p><img src="/images/2026-07-11/Pasted%20image%2020260709-121018.png" alt="" /></p>

<p>To use these nodes combine a seed with a few operators. For example:</p>

<p><img src="/images/2026-07-11/Pasted%20image%2020260709-152510.png" alt="" /></p>

<p>If implementing a polyhedra in Conway notation, be aware that the notation and node order is reversed. That is, enter <code class="language-plaintext highlighter-rouge">wgD</code> on  <a href="https://levskaya.github.io/polyhedronisme/">polyHédronisme</a> to get the polyhedron above.</p>

<p>Each of these subdivided polyhedra has a standard or canonical form. This form  has all  faces planar and all edges tangential to the unit sphere. The centre of the vertices of the polyhedra should also be at the origin.</p>

<p>The <em>canon</em> node does this. It has two inputs  <em>Iterations</em>  and <em>scale</em>. Applying it makes the polyhedron smoother and more symmetrical.</p>

<p><img src="/images/2026-07-11/Pasted%20image%2020260709-154429.png" alt="" /></p>

<p>Increase the  <em>Iterations</em> ,  and maybe the  <em>scale</em>  until the polyhedron smooths out. The canon algorithm makes <em>scale</em> sized improvement in <em>Iterations</em> number of steps.  Too large a <em>scale</em> value will blow the polyhedron up into a mess.</p>

<p>Here is a  gif of the each iteration of  the <em>canon</em> node on <code class="language-plaintext highlighter-rouge">qoD</code> (a Dodecahedron with an <em>ortho</em> operator followed by a <em>quinto</em> operator) .</p>

<p><img src="/images/2026-07-11/canon_slow_start.gif" alt="" /></p>

<p>The canon operator is applied a few seconds into the animation. The sphere inflates quickly to near the unit sphere, than takes a  lot more iterations to  rotate the smaller quads until the edges connecting them become tangent to the unit sphere.</p>

<p>All the operator nodes work equally well on 2D tilings. Trying an operator on a 2D mesh often helps in understanding what it does</p>

<p><img src="/images/2026-07-11/Pasted%20image%2020260709-154929.png" alt="" /></p>

<p>This is  <em>gyro-whirl</em> applied to the  <em>tri-tile</em> grid.</p>

<p>Or <em>gyro-whirl</em> on a <a href="https://elfnor.com/2026-06-17-poincare-geometry-nodes-part-2.html">hyperbolic tiling</a></p>

<p><img src="/images/2026-07-11/Pasted%20image%2020260709-155458.png" alt="" /></p>

<p><img src="/images/2026-07-11/blog_show-off-polyhedra.png" alt="" /></p>

<p><img src="/images/2026-07-11/blog_show-off-tilings.png" alt="" /></p>]]></content><author><name>elfnor</name></author><category term="blender" /><summary type="html"><![CDATA[Blender 5.2 has a Mesh Bevel Node!!!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2026-07-11/blog_header-03-bright.png" /><media:content medium="image" url="https://elfnor.com//images/2026-07-11/blog_header-03-bright.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Patterns in the Poincaré Plane - Geometry Nodes: Part 3</title><link href="https://elfnor.com//2026-06-18-poincare-geometry-nodes-part-3.html" rel="alternate" type="text/html" title="Patterns in the Poincaré Plane - Geometry Nodes: Part 3" /><published>2026-06-18T00:00:00+00:00</published><updated>2026-06-18T00:00:00+00:00</updated><id>https://elfnor.com//poincare-geometry-nodes-part-3</id><content type="html" xml:base="https://elfnor.com//2026-06-18-poincare-geometry-nodes-part-3.html"><![CDATA[<p>This is the third part of a series on using Blender Geometry nodes to make some pretty patterns on the Poincare disk .</p>

<p><a href="https://elfnor.com/2026-06-16-poincare-geometry-nodes-part-1.html">Part 1</a>  <br />
<a href="https://elfnor.com/2026-06-16-poincare-geometry-nodes-part-2.html">Part 2</a><br />
<a href="https://github.com/elfnor/blend_examples/blob/main/poincare_assets.blend">blend file</a></p>

<p>So far I made a tiling of the Poincaré Disk, but for simplicity I drew  the tiling edges with straight lines.  The edges in the tilings should really be arcs because in Poincaré geometry the shortest distance between two points is a geodesics or circle arc.</p>

<p>I found it  easiest to replace the edges after constructing the tiling. I used two nested “For Element “ loops. The outer one iterates over every face in the tiling, the inner one over every edge in the face. This duplicates calculations but it’s fast enough, so no optimisation needed.</p>

<p>Inner loop</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260603171356.png" alt="HypSegments inner loop nodes" />
The inner loop is simple and just creates a <code class="language-plaintext highlighter-rouge">HypSegment</code> through the two points of each edge on the face.</p>

<p>Outer  Loop</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260603171543.png" alt="outer loop HypSegments nodes" /></p>

<p>The outer loop (optionally) fills the curve with an n-gon. The <code class="language-plaintext highlighter-rouge">Curve to Mesh</code> ` Merge by Distance<code class="language-plaintext highlighter-rouge"> </code>Mesh to Curve` node sequence, merges the extra vertices at the face corners and sorts the vertices into sequential order. After that we replace the curves with a filled mesh circle with the appropriate number of vertices, then set the vertex position to that sampled from the curve.</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260612155417.png" alt="curved edge tiling" /></p>

<p>The full node group <code class="language-plaintext highlighter-rouge">p-tiling-arc-option</code> in the available blend file. has some other draw options.</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260609204134.png" alt="tiling group options" /></p>

<p><code class="language-plaintext highlighter-rouge">geodesics</code> draws a full  <code class="language-plaintext highlighter-rouge">HypLine</code> between the ideal points on the edge of the Poincaré Disk (the unit circle) for every edge.</p>

<p><img src="/_site/images/2026-06-18/Pasted%20image%2020260612160107.png" alt="geodesics option" /></p>

<p>The off centre options allow the polygon that starts the tiling to be displaced from the origin. Setting this up involved creating some more basic tools for working with hyperbolic geometry.</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">h-distance</code>- the length of the geodesic between two points</li>
  <li>h-circle - the euclidean centre and radius of a hyperbolic circle.</li>
</ul>

<h3 id="h-distance"><code class="language-plaintext highlighter-rouge">h-distance</code></h3>

<p>The hyperbolic distance  is the shortest distance between two points in the Poincaré Disk.  A derivation is given here - <a href="https://mphitchman.com/geometry/section5-3.html">GCT Measurement in Hyperbolic Geometry</a>  that doesn’t require finding the ideal points of the geodesic.  The result there is given in complex number notation.</p>

<p>\(d_H(p, q) = |\ln{(\frac{|1-\overline{p}q|+|q-p|}{|1-\overline{p}q|-|q-p|})}|\)
where $p =p_x +ip_y$ and $q= q_x +iq_y$ are complex numbers and  $\overline{p} =p_x -ip_y$ is the complex conjugate of $p$
swapping to vector notation $P=(p_x, p_y)$  and $Q=(q_x, q_y)$,</p>

<p>\(\overline{p}q = (P\cdot Q, |P \times Q|)\)
$P\cdot Q$ is the dot product and $|P\times Q|$ is the length of the cross product.
 or in math formula extension notation</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">ng</span> <span class="nx">h_distance</span><span class="p">(</span><span class="nx">P</span><span class="p">:</span> <span class="nx">vec3</span><span class="p">,</span> <span class="nx">Q</span><span class="p">:</span><span class="nx">vec3</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">hd</span><span class="p">:</span> <span class="nx">float</span><span class="p">{</span>
	<span class="nx">qp</span> <span class="o">=</span> <span class="nx">dist</span><span class="p">(</span><span class="nx">P</span><span class="p">,</span><span class="nx">Q</span><span class="p">);</span>
	<span class="nx">ccpq</span> <span class="o">=</span> <span class="nx">length</span><span class="p">({</span><span class="mi">1</span> <span class="o">-</span> <span class="nx">dot</span><span class="p">(</span><span class="nx">P</span><span class="p">,</span> <span class="nx">Q</span><span class="p">),</span><span class="nx">length</span><span class="p">(</span><span class="nx">cross</span><span class="p">(</span><span class="nx">P</span><span class="p">,</span> <span class="nx">Q</span><span class="p">)),</span><span class="mi">0</span><span class="p">});</span>
	<span class="nx">out</span> <span class="nx">hd</span> <span class="o">=</span> <span class="nx">abs</span><span class="p">(</span><span class="nx">log</span><span class="p">((</span><span class="nx">ccpq</span> <span class="o">+</span> <span class="nx">qp</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="nx">ccpq</span> <span class="o">-</span> <span class="nx">qp</span><span class="p">),</span> <span class="err">#</span><span class="nx">e</span><span class="p">));</span>
<span class="p">}</span>
<span class="nx">h_distance</span><span class="p">({</span><span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">});</span>
</code></pre></div></div>

<p><img src="/images/2026-06-18/Pasted%20image%2020260604171939.png" alt="h-distance node group" /></p>

<h3 id="h-circle"><code class="language-plaintext highlighter-rouge">h-circle</code></h3>

<p>For a hyperbolic circle all the points are an equal hyperbolic distance from the hyperbolic centre.  It can be drawn as an Euclidean circle with the Euclidean centre $B_E$ offset from the hyperbolic centre $B$ on a line toward the origin $O$.</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260608173900.png" alt="h-circle geogebra" /></p>

<p>Distances from a point to the the origin of the Poincaré Disk can be converted back and forth from  hyperbolic $d_H$ to Euclidean $d_E$  distances via</p>

<p>\(d_H=|ln(\frac{1+d_E}{1-d_E})|\)
\(d_H = 2 \tanh^{-1} d_E\)</p>

<p>and
\(d_E = \tanh(\frac{d_H}{2})\)</p>

<p>where $\tanh$ is the hyperbolic tangent function.</p>

<p>Using this we can find he Euclidean centre $B_E$ of a hyperbolic circle, centre at $B$, through $A$</p>

<p>\(r_H
= d_H(\overline{A},\overline{B})\)
\(b_H = d_H(\overline{B},\overline{O})\)</p>

\[e1= \tanh(\frac{b_H+r_H}{2})\]

\[e2= \tanh(\frac{b_H-r_H}{2})\]

\[B_E = \frac{e1+e2}{2}\frac{\overline{B}}{|B|}\]

<p><img src="/images/2026-06-18/Pasted%20image%2020260608175401.png" alt="h-circle" /></p>

<p>Now I have the <code class="language-plaintext highlighter-rouge">h-circle</code> group, I can use it to find the perpendicular bisector geodesic of the desired  centre of a hyperbolic polygon and the origin.  then I reflect a polygon at the origin through this geodesic to place the vertices of the off centre polygon.</p>

<p>The hyperbolic perpendicular bisector construction is analogous to the familiar Euclidean one.  Draw a circle centred on A through B, and another circle centred on B through A. Find the two intersections points of these circles. Draw a line though them.</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260608194037.png" alt="perpendicular bisector geogebra" /></p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260608193937.png" alt="perpendicular bisector nodes" /></p>

<p>And the full  <code class="language-plaintext highlighter-rouge">off-center-polygon</code> group</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260608194139.png" alt="off center polygon node group" /></p>

<p>This is incorporated into the <code class="language-plaintext highlighter-rouge">p-tiling</code> group,within the <code class="language-plaintext highlighter-rouge">p-tiling-arc-option</code> to produce Poincaré tilings with an off centre polygon.</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260612160039.png" alt="vertex centered tiling" /></p>

<p>The <code class="language-plaintext highlighter-rouge">off-center-polygon</code>  can also be used to draw other patterns.</p>

<p>Here a hyperbolic line is drawn through the centre and each vertex of a polygon.</p>

<p><img src="/images/2026-06-18/Pasted%20image%2020260608201906.png" alt="polygon radials" /></p>

<p>So that wraps this series for now. Although I have some ideas for hyperbolic solids in 3D …</p>

<p>All the hyperbolic tools can be found as assets in the provided blend file. Most of the pretty pictures are available in the “demos” collection in that file. There’s also a “tests” collection, that has tests for the <code class="language-plaintext highlighter-rouge">h-circle</code> and <code class="language-plaintext highlighter-rouge">h-distance</code> groups. I needed to rewrite these two groups as I refined and simplified the maths. I wanted to find a way to use tests in a similar way that I would use with text code.  I think this works.</p>

<p>Overall, this was a great learning exercise. I’ve improved my ability to implement maths and geometry in Blender Geometry Nodes heaps. I feel I’ve got my fingers over the edge of the learning cliff and can now pull myself up. Hopefully, I’ll document some more of this here on the blog.</p>]]></content><author><name>elfnor</name></author><category term="blender" /><summary type="html"><![CDATA[This is the third part of a series on using Blender Geometry nodes to make some pretty patterns on the Poincare disk .]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2026-06-18/header-poincare-part-3.png" /><media:content medium="image" url="https://elfnor.com//images/2026-06-18/header-poincare-part-3.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Patterns in the Poincaré Plane - Geometry Nodes: Part 2</title><link href="https://elfnor.com//2026-06-17-poincare-geometry-nodes-part-2.html" rel="alternate" type="text/html" title="Patterns in the Poincaré Plane - Geometry Nodes: Part 2" /><published>2026-06-17T00:00:00+00:00</published><updated>2026-06-17T00:00:00+00:00</updated><id>https://elfnor.com//poincare-geometry-nodes-part-2</id><content type="html" xml:base="https://elfnor.com//2026-06-17-poincare-geometry-nodes-part-2.html"><![CDATA[<p>Last post I covered drawing geodesic lines (they look like circle arcs) on the Poincaré Disk. This time I’m going to cover drawing hyperbolic tilings. See this <a href="https://github.com/elfnor/blend_examples/blob/main/poincare_assets.blend">blend file</a>  for the node groups and assets.</p>

<h2 id="circle-inversion">Circle Inversion</h2>

<p>The next maths step is finding the reflection of a point in the geodesic.
<a href="https://en.wikipedia.org/wiki/Inversive_geometry">Inversive geometry - Wikipedia</a></p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260510151341.png" alt="circle reflect geogebra" /></p>

<p>In the above diagram $D^\prime$ is the  point  $D$ reflected in the arc-line circle. $D^\prime$ lies on the line $CD$, where $C$ is the centre of the arc-line circle (coordinates $(x_0, y_0)$). The inversion position of this point along the line is defined such that :</p>

\[|CD| \cdot |CD^\prime| =r^2\]

<p>or in coordinate geometry:</p>

<p>\(m = \frac{r^2}{(x-x_0)^2 + (y-y_0)^2}\)\(x^\prime = x_0 + m(x-x_0)\)
\(y^\prime=y_0+m(y-y_0)\)
or in math formula extension syntax:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">ng</span> <span class="nx">reflect_point_circle</span><span class="p">(</span><span class="nx">point</span><span class="p">:</span><span class="nx">vec3</span><span class="p">,</span> <span class="nx">center</span><span class="p">:</span><span class="nx">vec3</span><span class="p">,</span> <span class="nx">radius</span><span class="p">:</span><span class="nx">float</span><span class="p">)</span><span class="o">-&gt;</span> <span class="nx">reflect_point</span><span class="p">:</span><span class="nx">vec3</span> <span class="p">{</span> 
 <span class="nx">m</span> <span class="o">=</span> <span class="nx">radius</span><span class="o">**</span><span class="mf">2.0</span><span class="o">/</span><span class="p">(</span><span class="nx">dist</span><span class="p">(</span><span class="nx">point</span><span class="p">,</span> <span class="nx">center</span><span class="p">)</span><span class="o">**</span><span class="mf">2.0</span><span class="p">);</span>
 <span class="nx">d</span> <span class="o">=</span> <span class="nx">sub</span><span class="p">(</span><span class="nx">point</span><span class="p">,</span> <span class="nx">center</span><span class="p">);</span>
 <span class="nx">out</span> <span class="nx">reflect_point</span> <span class="o">=</span> <span class="nx">center</span> <span class="o">+</span> <span class="nx">scale</span><span class="p">(</span><span class="nx">d</span><span class="p">,</span> <span class="nx">m</span><span class="p">);</span>
 <span class="p">}</span>
 <span class="nx">reflect_point_circle</span><span class="p">({</span><span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">.,</span><span class="mi">0</span><span class="p">.,</span><span class="mi">0</span><span class="p">.},</span> <span class="mf">1.0</span><span class="p">);</span>
</code></pre></div></div>

<p>I end up with this node group.</p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260531203409.png" alt="reflect-point-circle node group" /></p>

<p>Check this by drawing a diagram similar to the GeoGebra one above.</p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260531203510.png" alt="reflect point circle blender" /></p>

<h2 id="mirror-a-single-face-in-the-edge-of--a-polygon">Mirror a single face in the edge of  a polygon</h2>

<p>Next lets mirror an entire face in the circle.</p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260531205153.png" alt="face reflect blender" /></p>

<p>The smallest 7-gon is the mirror image of the central 7-gon in one of its edges using circle inversion. For comparison, the euclidean reflection is also shown.</p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260531204826.png" alt="mirror face nodes" /></p>

<h2 id="calculate-the-size-of-the-central-polygon">Calculate the size of the central polygon</h2>

<p>The central polygon of a hyperbolic tiling must have a specific radius $d$ depending on $p$ the number of vertices of each polygon, and $q$ the number of polygons (or edges) meeting  at each vertex.</p>

\[d = \sqrt{ \frac{ \tan\left( \frac{\pi}{2}-\frac{\pi}{q} \right)-\tan\left( \frac{\pi}{p} \right) } { \tan\left( \frac{\pi}{2} - \frac{\pi}{q} \right) + \tan\left( \frac{\pi}{p}\right) } }\]

<p>see <a href="https://www.malinc.se/noneuclidean/en/poincaretiling.php">Non-Euclidean Geometry: Interactive Hyperbolic Tiling in the Poincaré Disc</a> for a  derivation of this.</p>

<p>Math formula extension syntax</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ng radius_center_n_gon(p:int, q:int) -&gt; euclidean_radius: float {
	tq=tan(#(pi/2)-#pi/q);
	tp=tan(#pi/p);
	out euclidean_radius = sqrt((tq-tp)/(tq+tp));
}
radius_center_n_gon(7, 3);
</code></pre></div></div>

<p><img src="/images/2026-06-17/Pasted%20image%2020260516224147.png" alt="radius n-gon node group" /></p>

<h2 id="mirror-the-adjacent-face-for-all-boundary-edges">Mirror the adjacent face for all boundary edges</h2>

<p>Next I wrap this up as a group that loops over all boundary edges, finds the adjacent face and reflects it in the edge.</p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260516222801.png" alt="mirror all boundary edges nodes" /></p>

<h2 id="tiling">Tiling</h2>

<p>Combining all these steps to create  a tiling of the Poincaré Disk.
Recap 
Groups created - names as in the accompanying blend file.</p>
<ul>
  <li>“geodesic” - find the centre and radius of the geodesic through two points on the Poincaré Plane</li>
  <li>“reflect-point-circle” - find the position of a point mirrored in a geodesic</li>
  <li>“radius-center-n-gon”</li>
  <li>“mirror-adjacent-faces-poincare” - mirror - the adjacent face for all boundary edges</li>
</ul>

<p><img src="/images/2026-06-17/Pasted%20image%2020260516221626.png" alt="tiling nodes" /></p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260612154550.png" alt="7,3 poincare tiling straight edges" /></p>

<p>For ease, the edges of the polygons are plotted as a straight lines. They should,  of course, be arcs. I’ll look at replacing the edges with  geodesic segments in  Part 3 of this series.  In that post I’ll also show how to move the start polygon away from the centre.</p>
<h2 id="subdividing-tiling">Subdividing tiling</h2>

<p>Lots of fun can be had by adding  triangulate, dual, and subdivide nodes to the tiling output.</p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260612154634.png" alt="subdivide 1" /></p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260612154647.png" alt="subdivide 2" /></p>

<p><img src="/images/2026-06-17/Pasted%20image%2020260612154703.png" alt="subdivide 3" /></p>

<p><img src="/_site/images/2026-06-17/Pasted%20image%2020260612154730.png" alt="subdivide 4" /></p>

<p>This is related to <a href="https://elfnor.com/conway-polyhedron-operators-in-sverchok.html">Conway Operators</a> which is another thing I’ve been playing with in Geometry Nodes. I’ll write it up here eventually.</p>]]></content><author><name>elfnor</name></author><category term="blender" /><summary type="html"><![CDATA[Last post I covered drawing geodesic lines (they look like circle arcs) on the Poincaré Disk. This time I’m going to cover drawing hyperbolic tilings. See this blend file for the node groups and assets.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2026-06-17/header-poincare-part-2.png" /><media:content medium="image" url="https://elfnor.com//images/2026-06-17/header-poincare-part-2.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Patterns in the Poincaré Plane - Geometry Nodes: Part 1</title><link href="https://elfnor.com//2026-06-16-poincare-geometry-nodes-part-1.html" rel="alternate" type="text/html" title="Patterns in the Poincaré Plane - Geometry Nodes: Part 1" /><published>2026-06-16T00:00:00+00:00</published><updated>2026-06-16T00:00:00+00:00</updated><id>https://elfnor.com//poincare-geometry-nodes-part-1</id><content type="html" xml:base="https://elfnor.com//2026-06-16-poincare-geometry-nodes-part-1.html"><![CDATA[<p>I’ve made several serious efforts to really learn the depths of Blender’s Geometry Nodes. I was really into Sverchok for a while, but I’ve found Geometry Nodes harder. Maybe its the moving target as more nodes are added. Maybe without a scripting node I can’t cheat and just wrap code in a node front end. I have a bit more time lately and I think I’m starting to make progress.</p>

<p>My learning strategy was to make a list of all the available nodes and work through them in groups (for example, all the mesh topology nodes) and make a trivial or simple node example for each. Currently I’ve done about 40% of the nodes in Blender 5.1. I might tidy this up and share at some point.</p>

<p>I mixed the node by node  examples with trying to develop problems to solve that interested me. Watching endless rounds of you-tube videos, wire this node to that node, didn’t work for me.</p>

<p>I previously created <a href="https://elfnor.com/hyperbolic-tiling-in-3d.html">Poincaré tilings in Sverchok</a>  way back in 2015. Then I was mostly interested in producing a 3D model of the hyperbolic plane by <a href="https://elfnor.com/larger-hyperbolic-tilings-in-3d-using-processing.html">unfurling the tiling using Processing</a>.</p>

<p>I was absolutely stoked when an image from the original blog  was used on the cover of  the journal  “For the Learning of Mathematics” (<a href="https://flm-journal.org/Articles/FLM_39-1_00_cover">Vol 39, No 1 (2019)</a>). The issue included an article recalling  the late <a href="https://en.wikipedia.org/wiki/David_W._Henderson">David W. Henderson</a> a mathematician  who did extensive work alongside his wife Daina Taimina on the topology of hyperbolic planes.</p>

<p>This time, I’ll start by creating some node groups to do the basics such as drawing lines and circles and calculating distance in the Poincaré disc model. Then I’ll combine them to draw some pretty patterns including tilings.</p>

<p>All the node groups are available as assets in  a <a href="https://github.com/elfnor/blend_examples/blob/main/poincare_assets.blend">blend file</a> . Refer to them if the screenshots  I use below are a bit small.</p>

<p>I started an unpublished version of this post that had a lot of maths and derivations. This version I’m mostly going to quote the formula for each node group and give a reference to  more detail.</p>

<h2 id="what-is-the-poincaré-disk">What is the Poincaré disk?</h2>

<p>A  Euclidean plane is flat (zero curvature) and can be tiled with  6 hexagons surrounding a central hexagon. If you put 5 hexagons around a pentagon you get a sphere (positive curvature) like a soccer ball. If you put 7 hexagons around a heptagon (7 sided p-polygon) you get a hyperbolic plane with negative curvature everywhere. I describe it better (with pictures) in <a href="https://elfnor.com/blender-adventures-with-hyperbolic-planes.html">Blender Adventures with Hyperbolic Planes</a></p>

<p>The Poincaré disk is a model of the wrinkly 3D surface of a hyperbolic plane drawn flat on a 2D unit disk. All points on the hyperbolic plane are mapped on to a 2D disc with a radius of 1.</p>

<p>To get a feel for the weird geometry where straight lines are circular arcs have a play in the 
 interactive tilings  at <a href="https://www.malinc.se/noneuclidean/en/poincaretiling.php">Non-Euclidean Geometry: Interactive Hyperbolic Tiling in the Poincaré Disc</a> and <a href="https://www.malinc.se/m/ImageTiling.php">Make Hyperbolic Tilings of Images</a></p>

<h2 id="basic-tools">Basic Tools</h2>

<p>I’ve divided this post into three parts. The node groups I’ll describe in each post (blend file) are shown here.
<img src="/images/2026-06-16/Pasted%20image%2020260609202117.png" alt="nodes part 1" />
<img src="/images/2026-06-16/Pasted%20image%2020260609202134.png" alt="nodes part 2" />
<img src="/_site/images/2026-06-16/Pasted%20image%2020260609202202.png" alt="nodes part 3" /></p>

<p>These are all available as assets in the blend file.</p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260609201308.png" alt="nodes in asset browser" /></p>

<h2 id="geodesic-node-group"><code class="language-plaintext highlighter-rouge">geodesic</code> node group</h2>

<p>The first step in creating a tiling on the Poincaré Disk,  is to  draw a line (called a geodesic) through two points. In this non-euclidean geometry this is a circle arc that goes through the two points $(a_x, a_y)$, $(b_x, b_y)$ and is perpendicular to the unit circle at the edge of the disk.  If the geodesic goes through the origin, its a straight line diameter.</p>

<p><img src="/_site/images/2026-06-16/Pasted%20image%2020260609203929.png" alt="geodesic geogebra" /></p>

<p>The <code class="language-plaintext highlighter-rouge">geodesic</code> node group returns the Euclidean centre and radius of the geodesic through two points, input as 3D vectors. If the two points are on a diameter the <code class="language-plaintext highlighter-rouge">Is diameter?</code> output is true,  In this case, the centre is set to (0.0, 0.0, 0.0) and the radius is large. The centre and radius are in Euclidean space so can be used to draw lines and segments  (see <code class="language-plaintext highlighter-rouge">HypLine</code> and <code class="language-plaintext highlighter-rouge">HypSegment</code> groups)</p>

<p>For all these node groups be sure to keep the z-component of the input vectors set to 0.0.  The nodes internally use maths that assumes this.</p>

<p>The formulae for the Euclidean centre $(e_x, e_y)$ and radius $r$ are:
\(e_x = -\frac{1}{2}\frac{a_y(b_x^{2}+b_y^{2} + 1) - b_y(a_x^{2}+a_y^{2} +1)}{a_x b_y-a_y b_x}\)</p>

<p>\(e_y = -\frac{1}{2}\frac{b_x(a_x^{2}+a_y^{2} + 1) - a_x(b_x^{2}+b_y^{2} +1)}{a_x b_y-a_y b_x}\)
\(r=\sqrt{e_x^{2}+e_y^{2}-1}\)</p>

<p>These can be worked out from the formulae in the “By Analytical Geometry” section of  the wikipedia artice on the <a href="https://en.wikipedia.org/wiki/Poincar%C3%A9_disk_model">Poincaré disk model</a>.</p>

<p>Noding this  up is prone to errors (as is typing in the Latex here). For the noding I  used the <a href="https://extensions.blender.org/add-ons/math-formula/">Math Formula </a> extension, which I highly recommend.</p>

<p>Use the shortcut <code class="language-plaintext highlighter-rouge">ALT-F</code> and copy paste the following.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">ng</span> <span class="nx">geodesic</span><span class="p">(</span><span class="nx">v1</span><span class="p">:</span> <span class="nx">vec3</span><span class="p">,</span> <span class="nx">v2</span><span class="p">:</span> <span class="nx">vec3</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">center</span><span class="p">:</span><span class="nx">vec3</span><span class="p">,</span> <span class="nx">radius</span><span class="p">:</span> <span class="nx">float</span><span class="p">,</span> <span class="nx">IsDiameter</span><span class="p">:</span> <span class="nx">bool</span> <span class="p">{</span>
 <span class="nx">ax</span><span class="p">,</span> <span class="nx">ay</span><span class="p">,</span> <span class="nx">_</span> <span class="o">=</span> <span class="nx">separate_xyz</span><span class="p">(</span><span class="nx">v1</span><span class="p">);</span>
 <span class="nx">bx</span><span class="p">,</span> <span class="nx">by</span><span class="p">,</span> <span class="nx">_</span> <span class="o">=</span> <span class="nx">separate_xyz</span><span class="p">(</span><span class="nx">v2</span><span class="p">);</span>
 <span class="nx">cx</span><span class="p">,</span> <span class="nx">cy</span><span class="p">,</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">cross</span><span class="p">(</span><span class="nx">v1</span><span class="p">,</span> <span class="nx">v2</span><span class="p">);</span>
 <span class="nx">sv1</span> <span class="o">=</span> <span class="nx">length</span><span class="p">(</span><span class="nx">v1</span><span class="p">)</span><span class="o">**</span><span class="mf">2.0</span><span class="o">+</span><span class="mf">1.0</span><span class="p">;</span>
 <span class="nx">sv2</span> <span class="o">=</span> <span class="nx">length</span><span class="p">(</span><span class="nx">v2</span><span class="p">)</span><span class="o">**</span><span class="mf">2.0</span><span class="o">+</span><span class="mf">1.0</span><span class="p">;</span>
 <span class="nx">ex</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span><span class="o">*</span><span class="p">(</span><span class="nx">ay</span><span class="o">*</span><span class="nx">sv2</span><span class="o">-</span><span class="nx">by</span><span class="o">*</span><span class="nx">sv1</span><span class="p">)</span><span class="o">/</span><span class="nx">c</span><span class="p">;</span>
 <span class="nx">ey</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span><span class="o">*</span><span class="p">(</span><span class="nx">bx</span><span class="o">*</span><span class="nx">sv1</span><span class="o">-</span><span class="nx">ax</span><span class="o">*</span><span class="nx">sv2</span><span class="p">)</span><span class="o">/</span><span class="nx">c</span><span class="p">;</span>
 <span class="nx">r</span> <span class="o">=</span> <span class="nx">sqrt</span><span class="p">(</span><span class="nx">ex</span><span class="o">**</span><span class="mf">2.0</span> <span class="o">+</span> <span class="nx">ey</span><span class="o">**</span><span class="mf">2.0</span> <span class="o">-</span><span class="mf">1.0</span><span class="p">);</span>
 <span class="nx">out</span> <span class="nx">center</span> <span class="o">=</span> <span class="p">{</span><span class="nx">ex</span><span class="p">,</span> <span class="nx">ey</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">};</span>
 <span class="nx">out</span> <span class="nx">radius</span> <span class="o">=</span> <span class="nx">r</span><span class="p">;</span>
 <span class="nx">out</span> <span class="nx">IsDiameter</span> <span class="o">=</span> <span class="nx">c</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">geodesic</span><span class="p">({</span><span class="mf">0.5</span><span class="p">,</span><span class="mi">0</span><span class="p">.,</span><span class="mi">0</span><span class="p">.},</span> <span class="p">{</span><span class="mi">0</span><span class="p">.,</span><span class="mf">0.5</span><span class="p">,</span><span class="mi">0</span><span class="p">.});</span>
</code></pre></div></div>

<p>On hitting <code class="language-plaintext highlighter-rouge">CTRL-ENTER</code> you should magically get  a new node group with ~ 27 nodes.</p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260531170703.png" alt="geodesic node group" /></p>

<p>The Math Formula is a life saver for this kind of complicated maths.</p>

<h2 id="drawing-geodesics">Drawing geodesics</h2>

<p>To draw the geodesic, The simplest is to translate a <code class="language-plaintext highlighter-rouge">Mesh Circle</code> using the <code class="language-plaintext highlighter-rouge">center</code> output of the <code class="language-plaintext highlighter-rouge">geodesic</code> node and scale using the <code class="language-plaintext highlighter-rouge">radius</code> output.</p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260531170644.png" alt="draw geodesic nodes" /></p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260510143552.png" alt="draw geodesic blender output" /></p>

<p>Moving the x, y coordinates of the line start and end should move the arc around. It should always be through the two points and cross the unit circle at right angles.</p>

<p>To draw a geodesic just between the two points I’ll use the <code class="language-plaintext highlighter-rouge">Arc</code> curve node.</p>

<h3 id="arc-mid-point-node-group"><code class="language-plaintext highlighter-rouge">arc-mid-point</code> node group</h3>

<p>The  “Arc” node (in Points mode) needs a mid point  on the arc.  I need to find Point E in the diagram below.</p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260512214239.png" alt="arc midpoint geogebra" /></p>

<p>Some vector maths gives us:</p>

<p>\(\overline{OD} = \frac{\overline{OA} + \overline{OB}}{2}\)
\(\overline{OE} = \overline{OC} - \frac{\overline{OC}-\overline{OD}}{\Vert \overline{OC}-\overline{OD} \Vert} r\)
or as a node group - <code class="language-plaintext highlighter-rouge">arc-mid-point</code></p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260531171340.png" alt="arc midpoint nodes" /></p>

<h3 id="hypsegment-node-group"><code class="language-plaintext highlighter-rouge">HypSegment</code> node group</h3>

<p><img src="/images/2026-06-16/Pasted%20image%2020260531220448.png" alt="HypSegment node group" /></p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260512215703.png" alt="HypSegment output" /></p>

<h3 id="circle-circle-intersection-node-group"><code class="language-plaintext highlighter-rouge">circle-circle-intersection</code> node group</h3>

<p>A full line on the Poincaré plane should start and end on the unit circle. To draw this,  I need to find the two intersection points of the circle given by the <code class="language-plaintext highlighter-rouge">geodesic</code> node group and the unit circle. These are called the ideal points of the geodesic.</p>

<p>I made a node group for the intersection of any two circles as it will be useful later.</p>

<p>Here’s  the math formula extension notation for that  node group. The derivation can be found <a href="https://www.petercollingridge.co.uk/explorations/computational-geometry/circle-circle-intersections/">here</a> for example.  The symbols in the diagram match the code, uppercase for vectors,  lowercase for scalars.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">ng</span> <span class="nx">circle_circle_intersection</span><span class="p">(</span><span class="nx">A</span><span class="p">:</span><span class="nx">vec3</span><span class="p">,</span><span class="nx">ra</span><span class="p">:</span><span class="nx">float</span><span class="p">,</span> <span class="nx">B</span><span class="p">:</span><span class="nx">vec3</span><span class="p">,</span> <span class="nx">rb</span><span class="p">:</span><span class="nx">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">P1</span><span class="p">:</span><span class="nx">vec3</span><span class="p">,</span> <span class="nx">P2</span><span class="p">:</span><span class="nx">vec3</span><span class="p">,</span> <span class="nx">IsIntersecting</span><span class="p">:</span> <span class="nx">bool</span> <span class="p">{</span>
	<span class="nx">d</span> <span class="o">=</span> <span class="nx">dist</span><span class="p">(</span><span class="nx">A</span><span class="p">,</span> <span class="nx">B</span><span class="p">);</span>
	<span class="nx">U</span> <span class="o">=</span> <span class="nx">normalize</span><span class="p">(</span><span class="nx">B</span><span class="o">-</span><span class="nx">A</span><span class="p">);</span>
	<span class="nx">V</span> <span class="o">=</span> <span class="nx">cross</span><span class="p">(</span><span class="nx">U</span><span class="p">,</span> <span class="p">{</span><span class="mi">0</span><span class="p">.,</span><span class="mi">0</span><span class="p">.,</span><span class="o">-</span><span class="mi">1</span><span class="p">.});</span>
	<span class="nx">f</span> <span class="o">=</span> <span class="p">(</span><span class="nx">ra</span><span class="o">**</span><span class="mf">2.0</span> <span class="o">-</span> <span class="nx">rb</span><span class="o">**</span><span class="mf">2.0</span> <span class="o">+</span> <span class="nx">d</span><span class="o">**</span><span class="mf">2.0</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="nx">d</span><span class="p">);</span>
	<span class="nx">G</span> <span class="o">=</span> <span class="nx">A</span> <span class="o">+</span> <span class="nx">scale</span><span class="p">(</span><span class="nx">U</span><span class="p">,</span> <span class="nx">f</span><span class="p">);</span>
	<span class="nx">H</span> <span class="o">=</span> <span class="nx">scale</span><span class="p">(</span><span class="nx">V</span><span class="p">,</span> <span class="nx">sqrt</span><span class="p">(</span><span class="nx">ra</span><span class="o">**</span><span class="mf">2.0</span> <span class="o">-</span> <span class="nx">f</span><span class="o">**</span><span class="mf">2.0</span><span class="p">));</span>
	<span class="nx">out</span> <span class="nx">P1</span> <span class="o">=</span> <span class="nx">G</span> <span class="o">+</span> <span class="nx">H</span><span class="p">;</span>
	<span class="nx">out</span> <span class="nx">P2</span> <span class="o">=</span> <span class="nx">G</span> <span class="o">-</span> <span class="nx">H</span><span class="p">;</span>
	
	<span class="nx">sr</span> <span class="o">=</span> <span class="nx">ra</span> <span class="o">+</span> <span class="nx">rb</span><span class="p">;</span>
	<span class="nx">mr</span> <span class="o">=</span> <span class="nx">abs</span><span class="p">(</span><span class="nx">ra</span> <span class="o">-</span> <span class="nx">rb</span><span class="p">);</span>
	<span class="nx">out</span> <span class="nx">IsIntersecting</span> <span class="o">=</span> <span class="nx">boolean_math_nor</span><span class="p">(</span><span class="nx">d</span> <span class="o">&lt;</span> <span class="nx">mr</span><span class="p">,</span> <span class="nx">d</span> <span class="o">&gt;</span> <span class="nx">sr</span><span class="p">);</span>
	<span class="p">}</span>
<span class="nx">circle_circle_intersection</span><span class="p">({</span><span class="mi">0</span><span class="p">.,</span><span class="mi">0</span><span class="p">.,</span><span class="mi">0</span><span class="p">.},</span> <span class="mi">2</span><span class="p">.,</span> <span class="p">{</span><span class="mi">1</span><span class="p">.,</span><span class="mi">0</span><span class="p">.,</span><span class="mi">0</span><span class="p">.},</span> <span class="mi">1</span><span class="p">.);</span>
</code></pre></div></div>

<p><img src="/images/2026-06-16/Pasted%20image%2020260527230741.png" alt="circle-circle-intersection" /></p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260531172921.png" alt="circle-circle-intersection node group" /></p>

<h3 id="hypline-node-group"><code class="language-plaintext highlighter-rouge">HypLine</code> node group</h3>

<p>This is similar to  the <code class="language-plaintext highlighter-rouge">HypSegment</code> node group with the addition of the <code class="language-plaintext highlighter-rouge">circle-circle-intersection</code> group.</p>

<h2 id="pretty-pictures">Pretty Pictures</h2>
<p>To end this post lets draw the geometry for the header image.
First connect one point of a mesh circle to all the others via a  <code class="language-plaintext highlighter-rouge">HypLine</code>.</p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260512220108.png" alt="connect one to all" /></p>

<p>If we then instance this pattern on every point, we’ll double up a lot of curves, which show as texture artefacts when I convert the curves to a tube.</p>

<p>There are a couple of different ways to do  this. Only draw half the lines in the for each element loop, then instance that on all points.</p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260512220205.png" alt="connect all" /></p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260531173948.png" alt="connect all points node group" /></p>

<p>Or put a repeat zone around the for element zone</p>

<p><img src="/images/2026-06-16/Pasted%20image%2020260531174501.png" alt="connect all points repeat" /></p>

<p>The <a href="https://github.com/elfnor/blend_examples/blob/main/poincare_assets.blend">blend file</a>  for this post is available.</p>

<p>Next post, I’ll cover circle inversion or mirroring across the geodesic  leading to hyperbolic tilings.</p>]]></content><author><name>elfnor</name></author><category term="blender" /><summary type="html"><![CDATA[I’ve made several serious efforts to really learn the depths of Blender’s Geometry Nodes. I was really into Sverchok for a while, but I’ve found Geometry Nodes harder. Maybe its the moving target as more nodes are added. Maybe without a scripting node I can’t cheat and just wrap code in a node front end. I have a bit more time lately and I think I’m starting to make progress.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2026-06-16/header-poincare-part-1.png" /><media:content medium="image" url="https://elfnor.com//images/2026-06-16/header-poincare-part-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Fence Post + Chair = Desk</title><link href="https://elfnor.com//2024-09-02-fence-post-chair-desk.html" rel="alternate" type="text/html" title="Fence Post + Chair = Desk" /><published>2024-09-02T00:00:00+00:00</published><updated>2024-09-02T00:00:00+00:00</updated><id>https://elfnor.com//fence-post-chair-desk</id><content type="html" xml:base="https://elfnor.com//2024-09-02-fence-post-chair-desk.html"><![CDATA[<p>This is the third or fourth iteration of a DIY pole desk. Scroll down to see it in action. The base is from an old office chair with cast concrete for the weight. The post really is an old fence post from the pile of farm junk down the back of the paddock.</p>

<p><img src="images/2024-09-02/IMG_6913_01.jpg" alt="desk only" /></p>

<p>The fence post was water blasted and then sanded back to bare clean wood. I then used stains and paint to approximate how it looked outside. The cracks and divots have been emphasised with a black stain. It’s really more solid than it looks.</p>

<p><img src="images/2024-09-02/IMG_6954.jpg" alt="base" /></p>

<p>For the concrete base, I dug a few buckets of gravel and sand from the creek down the back. There’s also a nice seam of plastic clay in the creek bed so I hauled back a couple of buckets of that as well.</p>

<p>I turned the chair base upside down and used the clay to create a mould to pour the concrete. The dowels are to create  holes to bolt the base to the chair. I pressed the larger stones into  the clay to form the pattern on the top. Many of the stones were not held well when the concrete set but I still like the pattern. Being that type of person, I did make a mock up in Blender and use the 3D print add-on to check the volume was going to be about right. But then in  making it  was a lot more like mud pies than precision. The clay was so nice, it makes me want to get friendly with a local potter just to see what temperature it might fire at (can’t keep an old potter out of the mud…).</p>

<p>The top of the concrete ( or the bottom when its up the right way) was pretty rough so I cut a decagon out of plywood and painted it black. The ply is bolted  to the chair base with the concrete sandwiched in the middle. There’s lots of cut up bike inner tube between the ply and the concrete to spread the load a bit.</p>

<p><img src="images/2024-09-02/IMG_6462.jpg" alt="mould" /></p>

<p>Here’s some details of the staining and painting. I used a coarse sand gel paint medium to get the gritty lichen texture.</p>

<p><img src="images/2024-09-02/IMG_6920.jpg" alt="detail 1" />
<img src="images/2024-09-02/IMG_6925.jpg" alt="detail 2" /></p>

<p>The band of green paint has a crackle medium under it, but I don’t think I put it on thick enough as it’ didn’t come out as strong as I’d like. A bit of work with some sandpaper gave the worn look I was after.</p>

<p>And here it is in use. The monitors, laptop, keyboard and tablet are all held in place on the post via standard office workstation components.</p>

<p><img src="/_site/images/2024-09-02/IMG_7153_01.jpg" alt="sitting" /></p>

<p>The arms are all adjustable and the desk can be used sitting as above, or standing as below.</p>

<p><img src="/_site/images/2024-09-02/IMG_7130.jpg" alt="standing" /></p>

<p>You can see i have a cable management problem and I’ve got some bits ordered to help tidy that up. The two monitors can be switched individually between the laptop (work) and the large CPU (graphics etc.) via  a couple of HDMI switches. I’m going to mount a single PD power supply that will power both monitors and the laptop.</p>

<p>The whole rig is designed to be easily portable. I can work in the back office watching the bell-birds on the fuchsia outside the window, or in front of the fire in winter or under the air-con in summer.</p>

<p>I’m really pleased with this, its of the land of our new rural block. Its really stable and best of all there are no flat surfaces to accumulate paper. Just a bin in the corner for filing.</p>]]></content><author><name>elfnor</name></author><category term="making" /><summary type="html"><![CDATA[This is the third or fourth iteration of a DIY pole desk. Scroll down to see it in action. The base is from an old office chair with cast concrete for the weight. The post really is an old fence post from the pile of farm junk down the back of the paddock.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2024-09-02/header-fence-post-chair-desk.jpg" /><media:content medium="image" url="https://elfnor.com//images/2024-09-02/header-fence-post-chair-desk.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Spring was coming…</title><link href="https://elfnor.com//2024-08-19-spring-was-coming.html" rel="alternate" type="text/html" title="Spring was coming…" /><published>2024-08-19T00:00:00+00:00</published><updated>2024-08-19T00:00:00+00:00</updated><id>https://elfnor.com//spring-was-coming</id><content type="html" xml:base="https://elfnor.com//2024-08-19-spring-was-coming.html"><![CDATA[<p>Spring was coming … then it snowed!</p>

<p>Last week, I planted seeds for this year’s summer crops. Chillies, tomatoes, cucumbers, rock melons, and pepinos.  This is a week or two earlier than last year, but they’ll go into the glasshouse until after the last frost.</p>

<p>For now they’re all germinating inside in an old aquarium in front of the glass sliding doors. I put the electric heating pad on overnight to keep them happy.</p>

<p>Last year, one of my first-time-can-I-grow-it-here crops was eggplants . The long skinny Asian variety. The seed website said “violet-pink fruit” but some of my plants had white fruit. No idea. I grew them in the glasshouse and they did OK,  but a few pesky caterpillars and lots of whitefly.</p>

<p>This year I’m trying rock melons. I’m probably being a bit cocky but we’ll see.</p>

<p>I’ve planted heaps more chillies, they were really successful last year. Some of the plants were 2nd year although all the plant catalogues say they’re annuals. I’ve left them to over-winter and will see how they do. Black mould is a definite problem. The new chilli seeds this year are all hot varieties - Asian FIre, Carolina Reaper, Bhut Jolokia, Thai Hot and Habanero. That should have us panting.</p>

<p>But for now the snow is pretty cool.</p>

<p><img src="/_site/images/2024-08-19/snowy_hills.png" alt="snowy hills" /></p>]]></content><author><name>elfnor</name></author><category term="garden" /><summary type="html"><![CDATA[Spring was coming … then it snowed!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2024-08-19/header-baby-plant.png" /><media:content medium="image" url="https://elfnor.com//images/2024-08-19/header-baby-plant.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">New Gallery using Thumbsup</title><link href="https://elfnor.com//2024-08-09-new-gallery.html" rel="alternate" type="text/html" title="New Gallery using Thumbsup" /><published>2024-08-09T00:00:00+00:00</published><updated>2024-08-09T00:00:00+00:00</updated><id>https://elfnor.com//new-gallery</id><content type="html" xml:base="https://elfnor.com//2024-08-09-new-gallery.html"><![CDATA[<p>I’ve added a link to my new static photo  <a href="https://elfnor.github.io/elfnor-gallery/index.html">gallery</a> in the blog header.</p>

<p>I mainly wanted somewhere to share some of my photography away from any of the social media sites. I’ve also collected up some albums up of my old clay sculptures (dormant <a href="https://www.deviantart.com/elfnor">deviant art</a> profile) and some digital art that’s also on (<a href="https://www.artstation.com/elfnor">ArtStation</a>).</p>

<p>The gallery deployment needs to be really low effort for me to (hopefully- good intentions) keep updating it. I looked at some nice jekyll themes (<a href="https://github.com/sunbliss/photorama">photorama</a>, <a href="https://github.com/chrisanthropic/starving-artist-jekyll-theme">starving-artist</a>, <a href="https://github.com/rampatra/photography">photography</a>) but settled instead on <a href="https://github.com/thumbsup/thumbsup">thumbsup</a> a standalone  static HTML generator.</p>

<p>The gallery is deployed using the workflow from <a href="https://github.com/gautamkrishnar/github-pages-gallery">github-pages-gallery</a> to setup github actions to host it directly on Github pages.</p>

<p>The <a href="https://gitlab.com/langurmonkey/langurmonkey.gitlab.io/-/tree/master/gallery-theme">theme</a> is adapted from one by <a href="https://tonisagrista.com/blog/2021/static-photo-gallery/">langurmonkey</a>, with a bit of styling to match this blog.</p>

<p>Adding new photos is as simple as:</p>
<ul>
  <li>copy files into  folders/albums in the local git repository for https://github.com/elfnor/elfnor-gallery</li>
  <li>(optional) add a description via the  comment button in <a href="https://wiki.gnome.org/Apps/Gthumb">gthumb</a> or similar.</li>
  <li>(optional) run <code class="language-plaintext highlighter-rouge">docker run -v "$(pwd):/work" ghcr.io/thumbsup/thumbsup /bin/sh -c "cd /work/ &amp;&amp; thumbsup --config config.json"</code> to build locally</li>
  <li>add-commit-push to Github</li>
  <li>DONE!</li>
</ul>

<p>There’s a few things I’d like to improve:</p>
<ul>
  <li>the description banner is a bit intrusive</li>
  <li>and I’d like longer descriptions for some of the artworks - could I reuse the right-hand panel designed for exif info?</li>
  <li>match the styling a little closer to the blog.</li>
  <li>do I want to strip (some/all) exif data? Or show it?</li>
</ul>]]></content><author><name>elfnor</name></author><category term="blog" /><summary type="html"><![CDATA[I’ve added a link to my new static photo gallery in the blog header.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2024-08-09-header-new-gallery.png" /><media:content medium="image" url="https://elfnor.com//images/2024-08-09-header-new-gallery.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">White Tower</title><link href="https://elfnor.com//2022-04-21-white-tower.html" rel="alternate" type="text/html" title="White Tower" /><published>2022-04-21T00:00:00+00:00</published><updated>2022-04-21T00:00:00+00:00</updated><id>https://elfnor.com//white-tower</id><content type="html" xml:base="https://elfnor.com//2022-04-21-white-tower.html"><![CDATA[<p>I’ve been interested in photogrammetry for a long time but struggled to get good results. This year I invested in Creative Shrimp’s video <a href="https://www.creativeshrimp.com/photogrammetry-course">course</a> and its been well worth putting the time into. I’m now really pleased with the large outdoor and smaller turntable models I’m making. I’m using the open-source <a href="https://alicevision.org/">Meshroom</a> to do the 3D reconstruction.</p>

<p>After scanning lots of stuff, I wanted to do something with it. This piece is a quick kit-bash where the main landforms are from a photogrammetry scan of a rock on a local beach. The original rock is about knee high. The tower is based on a ceramic model I made some years ago. I thought about making a photogrammetry model of it as well, but modelled it directly in Blender as I made some significant changes.</p>

<p><a href="../images/2022-04-21/white_tower_filters_3840.png"><img src="../images/2022-04-21/white_tower_filters_1920.png" alt="final" /></a></p>

<p>Click to see full size image.</p>

<p>The water is via the <a href="https://www.blendermarket.com/products/true-terrain-">True Terrain</a> add-on.</p>

<p>I was after a slight painterly effect so used the low sample count and denoise trick. The image is only rendered with 32 samples but using the OpenImageDenoise smooths this out to the final non-realistic look. The advantages of this are speed, and less need for excessive texture detail. I could have also considered using the denoise in the compositor and only applying to some parts of the image.</p>

<p>I also played around a bit with post processing with G’MIC filters in Krita to go even more toward a painterly style. This is really easy to overdo. My process is to make a duplicate layer of the original, above the background layer, apply the filter to the duplicate, then reduce the opacity of the duplicate layer until the effect is just there. To record the current state, a new layer can be created from the visible layers (right click in layer panel -&gt; New Layer From Visible). This new layer can then be duplicated, a filter applied and the opacity adjusted as before. Adding the original layer back on top of the layer stack with low opacity (possibly with a colour LUT) can bring back some lost detail or colour. This process give a dynamic workflow with the G’MIC filters.</p>

<p><a><img src="../images/2022-04-21/white_tower_filters_crop.png" onmouseover="this.src='../images/2022-04-21/white_tower_no_filters_crop.png'" onmouseout="this.src='../images/2022-04-21/white_tower_filters_crop.png'" /></a></p>

<p>Mouse over the image to see the original with no G’MIC filters. The filters used are Black &amp; White - Pencil, Artistic - Dream Smoothing and Colors - Color Presets - LUTs Pack PIXLS.US - Modern Film.</p>

<p>I tend to make a lot of duplicate layers, each with single filter. I name each layer after the filter. Then fiddle. It helps to have an example or a clear idea of the style you’re aiming for. Otherwise the fiddling can lack direction and not result in much improvement.</p>

<p>Another approach is to filter the images used in the textures before rendering. This has a lot longer feedback time, but can be effective. Each filter layer can be exported separately and then combined in the Shader editor in Blender. This give more control over the strength of each filter. Bolder filters work well for NPR effects.</p>

<p>For example, in Krita I applied a G’MIC Dream Smooth and a Sketch filter to the main rock texture image.</p>

<p><img src="/_site/images/2022-04-21/white_tower_texture_filter_crop.png" alt="filtered texture" /></p>

<p>And here’s the original rock on location at the local beach.</p>

<p><img src="../images/2022-04-21/original_rock.JPG" alt="original rock" /></p>]]></content><author><name>elfnor</name></author><category term="blender" /><category term="photogrammetry" /><category term="krita" /><summary type="html"><![CDATA[I’ve been interested in photogrammetry for a long time but struggled to get good results. This year I invested in Creative Shrimp’s video course and its been well worth putting the time into. I’m now really pleased with the large outdoor and smaller turntable models I’m making. I’m using the open-source Meshroom to do the 3D reconstruction.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2022-04-21-header-white-tower.png" /><media:content medium="image" url="https://elfnor.com//images/2022-04-21-header-white-tower.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Floating Island</title><link href="https://elfnor.com//2021-09-05-floating-island.html" rel="alternate" type="text/html" title="Floating Island" /><published>2021-09-05T10:00:00+00:00</published><updated>2021-09-05T10:00:00+00:00</updated><id>https://elfnor.com//floating-island</id><content type="html" xml:base="https://elfnor.com//2021-09-05-floating-island.html"><![CDATA[<p>This project started with a sketch my <a href="https://techmonkeybusiness.com/">partner</a> drew on a ferry trip. (click through for higher resolution on all the images)</p>

<p><a href="../images/2021-09-05/concept-sketch-full.jpg"><img src="../images/2021-09-05/concept-sketch-small.jpg" alt="concept sketch" /></a></p>

<p>I scanned and used the line art to practice with the colorize mask in Krita. <a href="https://www.youtube.com/watch?v=HQdx6H9BIGs">David Revoy’s tutorial</a> is great for this.</p>

<p><a href="../images/2021-09-05/krita-colorize-full.png"><img src="/_site/images/2021-09-05/krita-colorize-small.png" alt="krita colorize" /></a></p>

<p>I enjoyed working in 2D and thought I’d build the basic rock and building outlines in Blender and go back to Krita for another paint over. But I must be more a 3D than a 2D artist, because I couldn’t stop and modelled everything in Blender. This included modelling a plausible back half to the island. Many times I thought I couldn’t match the 3D geometry to the 2D sketch, but the concept artist is also a mechanical engineer and I always found a solution that made sense within his world.</p>

<p><a href="../images/2021-09-05/island-front-full.jpg"><img src="../images/2021-09-05/island-front-small.jpg" alt="blender front" /></a></p>

<p><a href="../images/2021-09-05/island-back-full.jpg"><img src="../images/2021-09-05/island-back-small.jpg" alt="blender back" /></a></p>

<h2 id="video">Video</h2>

<iframe width="1280" height="720" src="https://www.youtube.com/embed/7lbz7FWgUZ0?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>I put the video (and the stills) through a G’MIC LUT filter (PIXL.US Modern Film at 50% strength). This <a href="http://gimpchat.com/viewtopic.php?f=10&amp;t=19008">post here about how to extract the commands from GIMP</a> (I did this in Krita instead) was very useful.</p>

<p>The commands for G’MIC 2.9.8 look different from the version used  tutorial but I ended up with the following bash script to run over all the rendered stills from Blender</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="nb">mkdir</span> ./done
<span class="k">for </span>i <span class="k">in</span> <span class="k">*</span>png
<span class="k">do
</span>gmic <span class="nv">$i</span> <span class="nt">-fx_color_presets</span> 19,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,15,1,1,1,1,1,1,512,50,0,0,0,0,0,0,0,50,50,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span>,<span class="s2">"0"</span> <span class="nt">-o</span> ./done/<span class="nv">$i</span>
<span class="k">done</span>
</code></pre></div></div>

<h2 id="music">Music</h2>

<p>I haven’t worked much with music tracks for video, but I wanted a 25 second clip that would loop seamlessly if the fly-around was played continuously. I initially tried doing this with an mp3 track but I couldn’t get the bars and phrasing to match the length.</p>

<p>I then tried starting with a midi track. Within LMMS it was easy to identify an 8 bar phrase in my <a href="http://midkar.com/country/gone_fishin_mmb.mid">chosen track</a> that would  loop well. Cutting just that bit out of the rest of the midi in LMMS seemed harder than it should be. I ended up finding that the export as wav option could be set to only export the part between the loop markers. I then brought the wav into Audacity and used Effect-&gt; Change Speed to make it exactly 25 seconds long.</p>

<p>Overall this was a fun project that took a lot longer than techmonkey took to make that original concept sketch.</p>]]></content><author><name>elfnor</name></author><category term="blender" /><category term="krita" /><summary type="html"><![CDATA[This project started with a sketch my partner drew on a ferry trip. (click through for higher resolution on all the images)]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2021-09-05-header-floating-island.png" /><media:content medium="image" url="https://elfnor.com//images/2021-09-05-header-floating-island.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Celtic Knot Font</title><link href="https://elfnor.com//2021-06-08-celtic-knot-font.html" rel="alternate" type="text/html" title="Celtic Knot Font" /><published>2021-06-09T22:00:00+00:00</published><updated>2021-06-09T22:00:00+00:00</updated><id>https://elfnor.com//celtic-knot-font</id><content type="html" xml:base="https://elfnor.com//2021-06-08-celtic-knot-font.html"><![CDATA[<p>Stumbling around on another project I came across a link on the Wikipedia entry on <a href="https://en.wikipedia.org/wiki/Celtic_knot">Celtic Knots</a> to  <a href="https://github.com/MrBenGriffin/Knot">MrBenGriffin’s Celtic Knotwork Generator</a>. I was intrigued.</p>

<p>I have little idea how ligatures and fonts work, but I could get this all going fairly simply. I’ll detail my exploration here as I found working out what was going on by trial and error rather fun.</p>

<p>I did this using Linux Mint and LibreOffice but other OS and software should work.</p>

<p>Download the zip file of the font from <a href="https://fontlibrary.org/en/font/knots">fontlibrary</a> or get it with the github repo above. Install it on your system. Right click on one of the font <code class="language-plaintext highlighter-rouge">*.otf</code> files <code class="language-plaintext highlighter-rouge">Open with Fonts</code> and click <code class="language-plaintext highlighter-rouge">Install</code>. (I’m using <code class="language-plaintext highlighter-rouge">KnotsZoo-Rustic.otf</code> for these examples)</p>

<p>Open LibreOffice Writer and select the <code class="language-plaintext highlighter-rouge">KNOTS Zoo</code> font and set the font size to say 40.</p>

<p>Start typing a random string of “i” an “o” characters. See if you can figure what’s going on.</p>

<p><img src="../images/2021-06-09/celtic_knot_02.gif" alt="gif" /></p>

<p>After a while you should see that a string of four characters produces a glyph.</p>

<p><img src="../images/2021-06-09/glyph_strings.png" alt="glyphs with strings" /></p>

<p>After some more experimenting you’ll find that each character in the string of four refers to one side of the glyph, starting at the top and going clockwise.</p>

<p><img src="../images/2021-06-09/glyph_strings_02.png" alt="glyphs with characters" /></p>

<p>An “i” has a connection to the next glyph, an “o” has no connection on that side.</p>

<p>Now see if you can produce this pattern (hint: “oooo” is a blank glyph).</p>

<p><img src="../images/2021-06-09/quiz_01.png" alt="quiz 01" /></p>

<p>What about this one?</p>

<p><img src="/_site/images/2021-06-09/quiz_02.png" alt="quiz 02" /></p>

<p>Now start adding “x” characters to the strings.</p>

<p><img src="../images/2021-06-09/border_oxi.png" alt="glyph_oix" /></p>

<p>The full list of characters available is “hibox”. “h” gives heads, and “b” beaks or spirals.</p>

<p><img src="../images/2021-06-09/border_hibox.png" alt="glyph_hibox" /></p>

<p>For designing patterns LibreOffice Calc is good with four characters or one glyph per cell. its useful in the design stage as you can see the character string in the input line at the same time as you can see the glyph in the cell. You can also easily edit glyph by glyph.</p>

<p><img src="/images/screenshot.png" alt="calc snapshot" /></p>

<p>The project’s github repository includes a python script to produce patterns with particular dimensions and symmetries. It outputs a sting of characters to the terminal that can be pasted back into your text editor or used on a webpage.</p>

<p>You can also use this font to play with other patterns such as the plane symmetry groups. <a href="https://en.wikipedia.org/wiki/Wallpaper_group">Wallpaper group - Wikipedia</a>) Or see my old <a href="https://elfnor.com/Symmetry%20Group%20Links%20and%20Notation.html">blog entry</a></p>

<p>This one has p2 symmetry.</p>

<p><img src="../images/2021-06-09/p2-symmetry.png" alt="p2-symmetry" /></p>

<p>Now I could make a font for playing Escher’s Potato Game… <a href="https://www.sciencedirect.com/science/article/pii/S0195669806000746">Combinatorial enumeration of 2×2 ribbon patterns - ScienceDirect</a>)</p>

<p>Play that game over here <a href="http://www.eschertiles.com/interaction.html">Escher Tiles - Interaction</a></p>]]></content><author><name>elfnor</name></author><category term="krita" /><summary type="html"><![CDATA[Stumbling around on another project I came across a link on the Wikipedia entry on Celtic Knots to MrBenGriffin’s Celtic Knotwork Generator. I was intrigued.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://elfnor.com//images/2021-06-09-header-celtic-knot-font.png" /><media:content medium="image" url="https://elfnor.com//images/2021-06-09-header-celtic-knot-font.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>