<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Daniel Sieger</title>
 <link href="https://danielsieger.com/atom.xml" rel="self"/>
 <link href="https://danielsieger.com/"/>
 <updated>2026-05-09T17:02:50+00:00</updated>
 <id>https://danielsieger.com</id>
 <author>
   <name>Daniel Sieger</name>
   <email></email>
 </author>

 
 <entry>
   <title>Connected Components of a Polygon Mesh</title>
   <link href="https://danielsieger.com/blog/2026/01/01/connected-components.html"/>
   <updated>2026-01-01T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2026/01/01/connected-components</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/connected-components/teaser.jpg&quot; alt=&quot;Many spheres with random positions and colors&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In mesh processing, we often assume ideal 2-manifold meshes consisting of a single connected component. In practice, however, meshes can be more complex: a single object may actually consist of many disconnected components, as shown in the image above.&lt;/p&gt;

&lt;p&gt;Depending on your application, you may need to detect these components for further filtering or processing. I recently added connected component detection to &lt;a href=&quot;https://pmp-library.org&quot;&gt;PMP&lt;/a&gt;. This article provides a concise, practical overview of the algorithm and is also a good exercise for learning to work with meshes.&lt;/p&gt;

&lt;p&gt;I’ll first outline the general algorithm, describe the C++ implementation, and show how to test it. I’ll also briefly demonstrate how to visualize components using color-coding. Finally, I’ll filter components for further downstream processing.&lt;/p&gt;

&lt;h2 id=&quot;basic-algorithm&quot;&gt;Basic Algorithm&lt;/h2&gt;

&lt;p&gt;The algorithm is based on a breadth-first traversal of the vertex graph. Starting from a seed vertex, it incrementally discovers all vertices connected to that seed. Here’s some pseudo-code:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for each vertex

  if vertex not yet visited
    mark vertex as visited
    push vertex to queue

  while queue not empty
    pop vertex from queue

    for each neighbor vertex
      if neighbor not yet visited
        mark neighbor as visited
        push neighbor to queue
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s an image illustrating the principle: starting from a seed vertex, all connected neighbors are visited incrementally.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/connected-components/traversal.jpg&quot; alt=&quot;Selecting neighbor vertices of a seed vertex&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here, connected components are defined with respect to vertex adjacency: two vertices are connected if they share an edge. In other words, components are computed on the vertex graph induced by mesh edges. Face-connected components can be computed similarly by traversing face adjacency.&lt;/p&gt;

&lt;h2 id=&quot;c-implementation&quot;&gt;C++ Implementation&lt;/h2&gt;

&lt;p&gt;Now let’s implement this in C++ using &lt;a href=&quot;https://pmp-library.org&quot;&gt;PMP&lt;/a&gt;. I left out some details in the pseudo-code that are essential for a practical implementation. In particular, we want to keep track of the current component index and remember which vertex belongs to which component. The function should also return the number of components so that callers can easily check if there are multiple components present. Here’s the full implementation:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;connected_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// add component as vertex property&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex_property&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;v:component&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// index to track current component&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;// visit neighboring vertices&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// increment component index&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// return number of components&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that vertices not connected to any other vertex are detected as individual connected components. This naturally follows from the algorithm being based on vertex adjacency.&lt;/p&gt;

&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;/h2&gt;

&lt;p&gt;Let’s verify that the algorithm works. The simplest test case is a mesh with a single component:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connected_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That works. Now let’s add two disconnected triangles:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connected_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Works as well. For a more practical and realistic test case I’ll generate multiple mixed polygon meshes and combine them into a single mesh. For that I need a helper function to append one mesh to another:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[](&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertex_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vertex_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;faces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;face_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;face_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_face&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;face_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you can generate a few randomly placed spheres, combine them into a single mesh, and make sure to detect the right number of components:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RAND_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RAND_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RAND_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sphere&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uv_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connected_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;visualization&quot;&gt;Visualization&lt;/h2&gt;

&lt;p&gt;If you want to visualize the individual components you can assign a color based on the component index to the mesh faces:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_components&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connected_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;face_colors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;face_property&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;f:color&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex_property&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;v:component&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// create a color map&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component_colors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RAND_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RAND_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RAND_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;component_colors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// assign face colors&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;faces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// determine component index from any face vertex&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;face_colors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component_colors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we are, detecting connected components and visualizing them using color-coding:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/connected-components/spheres.jpg&quot; alt=&quot;Color-coded randomly placed spheres&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;filtering&quot;&gt;Filtering&lt;/h2&gt;

&lt;p&gt;Depending on your application, you may want to filter the detected components based on some criterion. The approach is similar to the color-coding example above: first run component detection, then filter according to your chosen criterion. As an example, we’ll extract the largest component, using the bounding box size as a simple metric that works even for meshes with boundaries.&lt;/p&gt;

&lt;p&gt;First, let’s split all components into separate meshes. I’m intentionally using this explicit approach for demonstration purposes and because the functionality itself might be useful in other cases.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;split&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connected_components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meshes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex_property&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;v:component&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// one vertex map per component&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertex_maps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;faces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// determine component from any face vertex&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;face_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;face_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reserve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;valence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertex_maps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;// create vertex only once per component&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meshes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;vmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;face_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;meshes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_face&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;face_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meshes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All that’s left to do is to determine the largest component. I’m using bounding box size for simplicity, adjust accordingly if you want to check for area or volume.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// assume that mesh has several components of varying size&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meshes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;largest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numeric_limits&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meshes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meshes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;largest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Public Drafts With Jekyll</title>
   <link href="https://danielsieger.com/blog/2025/12/31/public-drafts-with-jekyll.html"/>
   <updated>2025-12-31T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2025/12/31/public-drafts-with-jekyll</id>
   <content type="html">&lt;p&gt;I’m using &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt;, a static site generator, to build this website&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. I always have a number of work-in-progress draft posts floating around, some being merely vague ideas, others close to being ready for publication.&lt;/p&gt;

&lt;p&gt;Jekyll natively supports working with &lt;a href=&quot;https://jekyllrb.com/docs/posts/#drafts&quot;&gt;drafts&lt;/a&gt;: files you keep in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_drafts&lt;/code&gt; folder are not built by default. They are only included in the build when you explicitly tell Jekyll to do so, either by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--drafts&lt;/code&gt; option when building the site or by specifying&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;show_drafts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;publishing-drafts&quot;&gt;Publishing Drafts&lt;/h2&gt;

&lt;p&gt;Sometimes, I’d like to include one or more drafts in the published site to send the link to someone for review. Other blogging engines might refer to this as private posts. There are several ways to achieve this. I’ll outline three methods:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Building drafts&lt;/li&gt;
  &lt;li&gt;Hiding a regular post&lt;/li&gt;
  &lt;li&gt;Using a custom collection&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;building-drafts&quot;&gt;Building Drafts&lt;/h2&gt;

&lt;p&gt;You can enable building drafts either by specifying the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--drafts&lt;/code&gt; option or setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show_drafts: true&lt;/code&gt; in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;. By default, this will include all your drafts in the listing of your blog posts, and that’s probably not what you want. Somewhere in your site you probably have a loop over all posts that lists them, something like this:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
{% for post in site.posts %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ post.url }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ post.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
{% endfor %}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You need to modify this loop to exclude drafts. This is straightforward: drafts in Jekyll already have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draft&lt;/code&gt; variable set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; when building drafts is enabled. All you need to do is add a simple check for it:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
{% for post in site.posts %}
  {% unless post.draft %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ post.url }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ post.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  {% endunless %}
{% endfor %}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you have an RSS feed, you should exclude drafts there as well:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- feed boilerplate --&amp;gt;&lt;/span&gt;
{% for post in site.posts %}
  {% unless post.draft %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;entry&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ post.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ site.url }}{{ post.url }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;updated&amp;gt;&lt;/span&gt;{{ post.date | date_to_xmlschema }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/updated&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;{{ site.url }}{{ post.id }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;content&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;html&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ post.content | xml_escape }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/content&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/entry&amp;gt;&lt;/span&gt;
  {% endunless %}
{% endfor %}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that if you are using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll-sitemap&lt;/code&gt; plugin you will want to exclude drafts from there as well. You can do this by setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sitemap: false&lt;/code&gt; in the front matter for each draft, but of course that’s a tedious manual procedure and prone to errors. There’s also a certain risk of forgetting to remove the variable when publishing the post. The last method I present here has a more robust solution to this problem.&lt;/p&gt;

&lt;h2 id=&quot;hiding-regular-posts&quot;&gt;Hiding Regular Posts&lt;/h2&gt;

&lt;p&gt;This is a relatively straightforward method if you only want to include specific posts that are ready for review. Instead of building drafts, you just treat the draft as a regular post and put it in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; folder. Then you simply add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draft&lt;/code&gt; front matter variable:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Your Draft Title&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;draft&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to hide the post, you follow exactly the same procedure as above: exclude posts with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draft&lt;/code&gt; front matter variable from your post listings, feed, and sitemap.&lt;/p&gt;

&lt;p&gt;The major advantage of this approach is that it is more fine-grained: Instead of building and publishing &lt;em&gt;all&lt;/em&gt; drafts, you only include those you want to publish for review.&lt;/p&gt;

&lt;h2 id=&quot;custom-collection&quot;&gt;Custom Collection&lt;/h2&gt;

&lt;p&gt;This is probably the most advanced method, but it allows for greater flexibility. Basically, drafts are a collection, and you can customize how this particular collection is processed. Let’s start by defining the drafts collection in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;drafts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/:collection/:name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we want to make sure that the drafts collection uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post&lt;/code&gt; layout by default and is automatically excluded from the sitemap:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;_drafts&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;post&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;sitemap&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The good thing is that Jekyll still treats those posts as drafts for filtering purposes: they have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draft&lt;/code&gt; variable defined, so you can exclude them from post listings or feeds as shown above. You can even add a possibly hidden &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drafts.md&lt;/code&gt; page to only list your drafts:&lt;/p&gt;

&lt;div class=&quot;language-md highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;page&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Drafts&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Draft&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;articles&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;sitemap&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
{% for post in site.drafts %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ post.url }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ post.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
{% endfor %}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Voilà!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I’m building my site using GitHub pages, so I’m stuck with Jekyll 3.X for now. All testing for this article was done using Jekyll 3.9.5. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Digital Detox</title>
   <link href="https://danielsieger.com/blog/2025/12/30/digital-detox.html"/>
   <updated>2025-12-30T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2025/12/30/digital-detox</id>
   <content type="html">&lt;p&gt;Earlier this year, after reading Cal Newport’s &lt;a href=&quot;https://www.goodreads.com/book/show/40672036-digital-minimalism&quot;&gt;&lt;em&gt;Digital Minimalism&lt;/em&gt;&lt;/a&gt;, I decided to go on a digital detox for a period of 30 days. I stopped reading my usual news outlets, minimized smartphone usage, and avoided social media entirely.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;really&lt;/em&gt; enjoyed the silence.&lt;/p&gt;

&lt;p&gt;Now that this period is over, I’ve started visiting some news sites again, although in a much more focused and targeted way. My smartphone stays tucked away most of the time, with notifications off or Do Not Disturb enabled. Even though my smartphone use was already minimal, intentionally keeping it out of reach and out of sight helped me a lot to reduce distractions and maintain better focus.&lt;/p&gt;

&lt;h2 id=&quot;cutting-social-media&quot;&gt;Cutting Social Media&lt;/h2&gt;

&lt;p&gt;When it comes to social media, I went one step further: I deleted all my accounts. Reddit, Mastodon, LinkedIn, Discord, and whatnot—all gone for good, and I’m not looking back.&lt;/p&gt;

&lt;p&gt;I was never a heavy social media user to begin with. Still, over time, a surprising number of accounts had accumulated, each offering questionable value. More often than not, they led to distraction and procrastination rather than supporting meaningful work, learning, or interaction with others.&lt;/p&gt;

&lt;p&gt;This is not an argument that these platforms provide no value at all. They clearly do; otherwise, they would not attract and retain so many users. Their mechanisms and incentives are well understood. However, I largely agree with Newport’s core argument: marginal value alone is not a sufficient justification for adopting or retaining a digital tool. If a tool consumes attention without providing significant benefit, its net effect may still be negative.&lt;/p&gt;

&lt;h2 id=&quot;leaving-linkedin-behind&quot;&gt;Leaving LinkedIn Behind&lt;/h2&gt;

&lt;p&gt;Deleting my LinkedIn profile was the most difficult decision, as it has the greatest professional impact. More than a decade of accumulated professional and academic contacts carries a certain weight. Letting go of the fear of missing out wasn’t easy: the hypothetical recruiter with the perfect opportunity, or the concern that not having a profile might reflect poorly during a job search. These risks may or may not be real, but I’m willing to accept them.&lt;/p&gt;

&lt;p&gt;The key for me was some honest reflection about what value these tools actually provided. The answer was: close to zero. I realized that I could not recall more than a handful of genuinely meaningful or useful interactions on any of these platforms. Perhaps there was occasional feedback on a blog post, but that was about it. What I do recall is a steady drain on time and attention. In that light, the decision became easier.&lt;/p&gt;

&lt;h2 id=&quot;where-attention-goes&quot;&gt;Where Attention Goes&lt;/h2&gt;

&lt;p&gt;Your mileage may vary, but for now I prefer to invest my time and attention elsewhere: into work that compounds, projects that are intrinsically rewarding, and social interactions in the real world. For me, this is less about abstinence and more about intention: choosing where my attention goes, and creating the conditions for sustained focus and meaningful work.&lt;/p&gt;

&lt;p&gt;If any of this resonates with you, Cal Newport’s &lt;a href=&quot;https://www.goodreads.com/book/show/40672036-digital-minimalism&quot;&gt;&lt;em&gt;Digital Minimalism&lt;/em&gt;&lt;/a&gt; is well worth reading. Trying a short, time-boxed digital detox can be a useful experiment to question habits and discover what matters to you. With the New Year just around the corner, it’s the perfect time to try.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Code Coverage with CMake and CTest</title>
   <link href="https://danielsieger.com/blog/2024/08/03/code-coverage-with-cmake.html"/>
   <updated>2024-08-03T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2024/08/03/code-coverage-with-cmake</id>
   <content type="html">&lt;p&gt;In this article, I’ll walk you through the steps for adding code coverage testing using CMake and CTest. This is an addition to my &lt;a href=&quot;/blog/2022/03/06/code-coverage-for-cpp.html&quot;&gt;previous article&lt;/a&gt; on code coverage testing for C++. Integrating basic coverage testing with CMake has become a lot easier since then.&lt;/p&gt;

&lt;p&gt;The pre-requisites are the same: I’m assuming CMake as a build system and gcc or clang as compiler.&lt;/p&gt;

&lt;h2 id=&quot;a-minimal-setup&quot;&gt;A Minimal Setup&lt;/h2&gt;

&lt;p&gt;Let’s start with some minimal example code:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// main.cpp&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, add a basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CMakeLists.txt&lt;/code&gt; file for compiling the code:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cmake_minimum_required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;VERSION 3.20&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage_test&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# make sure to use a Debug build&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CMAKE_BUILD_TYPE &lt;span class=&quot;s2&quot;&gt;&quot;Debug&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# define executable target&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;add_executable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage_test main.cpp&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Use the standard steps to build using CMake:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;build &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;build &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cmake .. &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cmake &lt;span class=&quot;nt&quot;&gt;--build&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This should give you something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[ 50%] Building CXX object CMakeFiles/coverage_test.dir/main.cpp.o
[100%] Linking CXX executable coverage_test
[100%] Built target coverage_test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Congratulations!&lt;/p&gt;

&lt;h2 id=&quot;adding-coverage-support&quot;&gt;Adding Coverage Support&lt;/h2&gt;

&lt;p&gt;There are three steps required to add code coverage testing to the setup:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add the required compiler and linker flags&lt;/li&gt;
  &lt;li&gt;Enable CTest&lt;/li&gt;
  &lt;li&gt;Add your executable as a test&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both clang and gcc only need a single option to enable generation of coverage information: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-coverage&lt;/code&gt;. However, you need to add this to both your compiler and linker flags:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;target_compile_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage_test PRIVATE -coverage&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;target_link_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage_test PRIVATE -coverage&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’d recommend using the more modern variant of specifying options per target instead of using global options using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_compile_options&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_link_options&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PRIVATE&lt;/code&gt; scope limits the options only for compiling this target.&lt;/p&gt;

&lt;p&gt;Enabling CTest just requires&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CTest&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, in order to register your executable as a test you need to add&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;add_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;NAME coverage COMMAND coverage_test&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This needs to come after defining the executable target. The full &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CMakeLists.txt&lt;/code&gt; now looks like this:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cmake_minimum_required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;VERSION 3.20&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# include CTest support&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CTest&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# define executable target&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;add_executable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage_test main.cpp&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# make sure to use a Debug build&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CMAKE_BUILD_TYPE &lt;span class=&quot;s2&quot;&gt;&quot;Debug&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# compile with coverage options&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;target_compile_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage_test PRIVATE -coverage&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;target_link_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage_test PRIVATE -coverage&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;add_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;NAME coverage COMMAND coverage_test&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;generating-coverage-information&quot;&gt;Generating Coverage Information&lt;/h2&gt;

&lt;p&gt;Re-build the project:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cmake .. &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cmake &lt;span class=&quot;nt&quot;&gt;--build&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run your test with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctest&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ctest &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; Test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Generate coverage information:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ctest &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; Coverage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This should give you something like this as output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Performing coverage
   Processing coverage (each . represents one file):
    .
   Accumulating results (each . represents one file):
    .
        Covered LOC:         7
        Not covered LOC:     1
        Total LOC:           8
        Percentage Coverage: 87.50%
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also combine the two steps into a single call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctest&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ctest &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; Test &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; Coverage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can also verify that additional tests increase your coverage by adding another assertion to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main()&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wipe out any outdated coverage information:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;find &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;*.gcda&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Re-run the whole thing:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cmake &lt;span class=&quot;nt&quot;&gt;--build&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ctest &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; Test &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; Coverage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Congratulations! You achieved 100% code coverage:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Performing coverage
   Processing coverage (each . represents one file):
    .
   Accumulating results (each . represents one file):
    .
        Covered LOC:         9
        Not covered LOC:     0
        Total LOC:           9
        Percentage Coverage: 100.00%
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;

&lt;p&gt;This setup doesn’t provide you with a nice way to visualize which parts of the code are covered. However, this can be achieved either by using &lt;a href=&quot;https://github.com/linux-test-project/lcov&quot;&gt;lcov&lt;/a&gt; as described in my &lt;a href=&quot;/blog/2022/03/06/code-coverage-for-cpp.html&quot;&gt;previous article&lt;/a&gt;, or by using an extension for your IDE to directly visualize the coverage information in your editor. The &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=JacquesLucke.gcov-viewer&quot;&gt;Gcov Viewer&lt;/a&gt; for VS Code seems to be a popular choice, but I did not test it yet.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Opaque Pointer Pattern in C++</title>
   <link href="https://danielsieger.com/blog/2024/08/02/cpp-opaque-pointer-pattern.html"/>
   <updated>2024-08-02T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2024/08/02/cpp-opaque-pointer-pattern</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/opaque-pointer/teaser.jpg&quot; alt=&quot;Opaque Pointer Pattern&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’m doing a lot of code re-design and refactoring these days. One challenge is to change the implementation of a class or module while maintaining a stable interface for its clients. The ability to replace an old implementation with a new one without changing other parts of the code is extremely useful to ensure the correctness of the new implementation: it allows you to run integration tests with the new implementation and hunt down any bugs or regressions.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;opaque pointer&lt;/em&gt; design pattern is extremely useful in this situation. Maybe you’re familiar with it as pointer-to-implementation idiom or compiler firewall. It is also described as &lt;em&gt;Bridge Pattern&lt;/em&gt; in the GoF book&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;This article walks you through the basics of the pattern and shows you how to implement it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;whats-the-problem&quot;&gt;What’s the Problem?&lt;/h2&gt;

&lt;p&gt;The basic problem is that C++ class declarations expose private details of the class. Private member functions and data members need to be declared in the header. Here’s an example for illustration:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.h&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;private:&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While users of this class don’t have direct access to the private data members &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x_&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y_&lt;/code&gt;, there is still a dependency: If you change the private implementation details of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point&lt;/code&gt;, all other compilation units that include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point.h&lt;/code&gt; know about the change and need to be re-compiled.&lt;/p&gt;

&lt;p&gt;This only gets worse for more complex dependency chains, e.g., when there are dependencies to other classes internal to the module that need to be included. To a certain degree, this can be dealt with by using forward declarations. However, at the end of the day there is an information leak: Private implementation details are leaking to clients. This goes directly against the idea of &lt;a href=&quot;https://en.wikipedia.org/wiki/Information_hiding&quot;&gt;information hiding&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The opaque pointer pattern helps to deal with this problem.&lt;/p&gt;

&lt;h2 id=&quot;hiding-behind-a-pointer&quot;&gt;Hiding Behind a Pointer&lt;/h2&gt;

&lt;p&gt;The basic idea of the opaque pointer pattern is to hide the details of the implementation behind a pointer to an incomplete type. Picking up the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point&lt;/code&gt; example from above, a basic version might look like this:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.h&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;private:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Impl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// forward-declaration of the implementation&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// pointer to implementation&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the header file only contains a forward-declaration and a pointer to an incomplete type. This doesn’t tell anything about how the point class actually stores its data. This decision is left to the implementation file:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.cpp&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// There&apos;s a problem in this example. Can you spot it?&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;Point.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Impl&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Impl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point::Impl&lt;/code&gt; is only defined in the implementation file. You can now change the implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point&lt;/code&gt; without changing the API defined in the header. Let’s say you prefer a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::array&lt;/code&gt; instead of two floats:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.cpp&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// There&apos;s still a problem in this example. Can you spot it?&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;Point.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;array&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Impl&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Impl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Voilà! Same interface, different implementation.&lt;/p&gt;

&lt;p&gt;This is clearly a step forward in terms of information hiding. However, the example above has some problems, as already hinted at in the comments. I used a raw pointer to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point::Impl&lt;/code&gt; struct, allocated in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point&lt;/code&gt; constructor. However, I never delete it. Ouch!&lt;/p&gt;

&lt;p&gt;Instead of fixing the above example by using manual memory management, let’s look into an alternative implementation using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;opaque-pointer-with-stdunique_ptr&quot;&gt;Opaque Pointer with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;C++11 came with smart pointer classes that allow you to avoid memory management issues like the above. In particular, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt; is a smart pointer has unique ownership semantics of the resource it manages and automatically takes care of object destruction. Let’s give this a try:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.h&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;memory&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;private:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Impl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;// forward-declaration of the implementation&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Impl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// pointer to implementation&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Aww, too bad, doesn’t compile out of the box:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;unique_ptr.h:66:19: error: invalid application of &apos;sizeof&apos; to an incomplete type &apos;Point::Impl&apos;
  static_assert(sizeof(_Tp) &amp;gt;= 0, &quot;cannot delete an incomplete type&quot;);
                ^~~~~~~~~~~
unique_ptr.h:300:7: note: in instantiation of member function &apos;std::default_delete&amp;lt;Point::Impl&amp;gt;::operator()&apos; requested here
    __ptr_.second()(__tmp);
    ^
unique_ptr.h:266:75: note: in instantiation of member function &apos;std::unique_ptr&amp;lt;Point::Impl&amp;gt;::reset&apos; requested here
  _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX23 ~unique_ptr() { reset(); }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looks like the compiler is trying to do something on an incomplete type, which doesn’t work out. What’s actually missing here is a destructor required for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt; doing its job.&lt;/p&gt;

&lt;p&gt;Fine, let’s add a destructor to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Point&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.h&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// error&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Too bad, still doesn’t compile, but the compiler hints are a little more useful now:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Point.h:34:5: note: in instantiation of member function
&apos;std::unique_ptr&amp;lt;Point::Impl&amp;gt;::~unique_ptr&apos; requested here
  ~Point() = default;  // error
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What’s going on? In order to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt; class member, we need a destructor being available. However, the defaulted destructor in the header is not sufficient because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Impl&lt;/code&gt; is still an incomplete type. What’s actually needed is:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A destructor &lt;em&gt;declared&lt;/em&gt; in the header file.&lt;/li&gt;
  &lt;li&gt;A destructor &lt;em&gt;defined&lt;/em&gt; in the implementation in file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The destructor declaration becomes&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.h&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Point&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and in the implementation file we add&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Point.cpp&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Putting this all together, we finally have a working implementation of the opaque pointer pattern using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt;. Yay!&lt;/p&gt;

&lt;p&gt;To round this up, let’s briefly review some pros and cons.&lt;/p&gt;

&lt;h2 id=&quot;advantages&quot;&gt;Advantages&lt;/h2&gt;

&lt;p&gt;The main advantage obviously is better information hiding: Private implementation details are not exposed to the users of a class. Even more, consistent usage of opaque pointers can be used to ensure binary compatibility, although I didn’t try that in practice, yet.&lt;/p&gt;

&lt;p&gt;Another advantage are reduced compilation dependencies. If you ever worked with a large C++ code base you probably know how annoying long compile times can get. The more definitions you have in your headers the more dependencies you have and the more compilation units need to be re-compiled upon a change. Consistent use of opaque pointers and forward declarations can help to mitigate this problem.&lt;/p&gt;

&lt;h2 id=&quot;drawbacks&quot;&gt;Drawbacks&lt;/h2&gt;

&lt;p&gt;Everything has a cost, and this pattern is no exception. There are two main points to consider:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Implementation overhead&lt;/li&gt;
  &lt;li&gt;Run-time overhead&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As for (1), consistently using this pattern can be a chore and requires engineering discipline in your team. Code reviews and checklists help.&lt;/p&gt;

&lt;p&gt;As for (2), there is a certain overhead involved: at least one level of indirection de-referencing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Impl&lt;/code&gt; pointer. This can be a no-go for performance-critical code. However, I’d consider the main application of opaque pointers to be in higher-level APIs that provides access to more complex and performance-critical functions of a deep module.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;After reading this article, you should understand the basics of the opaque pointer pattern and how you can implement it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unique_ptr&lt;/code&gt;. I also gave some hints on when it is appropriate to use it and when maybe not.&lt;/p&gt;

&lt;p&gt;Admittedly, this article is only scratching the surface of the subject. There’s more to say about opaque pointers, notably when it comes to moving and copying things around. I’ll save that for another day.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Opaque_pointer&quot;&gt;Opaque Pointer&lt;/a&gt; on Wikipedia&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.cppstories.com/2018/01/pimpl/&quot;&gt;The Pimpl Pattern - what you should know&lt;/a&gt; by Bartlomiej Filipek&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/10675945-api-design-for-c&quot;&gt;API Design for C++&lt;/a&gt; by Martin Reddy&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. &lt;em&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/em&gt; (Addison-Wesley, 1995) &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>PMP Library Version 3.0 Released</title>
   <link href="https://danielsieger.com/blog/2023/08/24/pmp-library-version-3.0.html"/>
   <updated>2023-08-24T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2023/08/24/pmp-library-version-3.0</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We just released version 3.0 of &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt;, the Polygon Mesh Processing Library. This is a major version with several additions and API changes. Highlights include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A polygon Laplacian operator allowing several algorithms to work on general polygon meshes, including smoothing, parameterization, fairing, and curvature computation.&lt;/li&gt;
  &lt;li&gt;The geodesics in heat method has been added.&lt;/li&gt;
  &lt;li&gt;The algorithms API has been revamped to use a simple function-based interface.&lt;/li&gt;
  &lt;li&gt;New interactive online demos integrated into the &lt;a href=&quot;https://www.pmp-library.org/algorithms-guide.html&quot;&gt;algorithms guide&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;We no longer use git submodules for handling third-party dependencies.&lt;/li&gt;
  &lt;li&gt;Upgrade C++ standard to C++17&lt;/li&gt;
  &lt;li&gt;… a whole lot of smaller fixes, cleanups, and improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the official &lt;a href=&quot;https://www.pmp-library.org/version-3-0-released-2023-08-24.html&quot;&gt;release announcement&lt;/a&gt; and the &lt;a href=&quot;https://github.com/pmp-library/pmp-library/blob/main/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt; for a full summary of changes.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>API Simplicity</title>
   <link href="https://danielsieger.com/blog/2023/08/06/api-simplicity.html"/>
   <updated>2023-08-06T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2023/08/06/api-simplicity</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/api-simplicity.jpg&quot; alt=&quot;Teaser image: simple function-based subdivision API&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I recently simplified the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt; algorithms API. This was a somewhat embarrassing but also very rewarding experience. Embarrassing because the old code was just absurd in some cases. Rewarding because it made me question some deeply ingrained habits. In fact, this exercise changed my approach to API design.&lt;/p&gt;

&lt;p&gt;Want the short version? Here it is: Stop writing classes, use functions.&lt;/p&gt;

&lt;p&gt;Now, that’s of course too simple. Read on for the full story.&lt;/p&gt;

&lt;h2 id=&quot;complex-class-interfaces&quot;&gt;Complex Class Interfaces&lt;/h2&gt;

&lt;p&gt;Up until the 2.x releases, we were using classes as the primary interface for algorithms. The main reason was convenience and consistency. This led to some absurd usage patterns like this:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceSubdivision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SurfaceFactory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;icosahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or this:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceSimplification&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;simplifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;simplifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;simplifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;simplify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This type of interface looks highly familiar to anyone used to OOP style APIs. In fact, I always had the filter interfaces of &lt;a href=&quot;https://vtk.org&quot;&gt;VTK&lt;/a&gt; in mind when designing the original API. Even though this interface might be familiar, I wouldn’t call it simple.&lt;/p&gt;

&lt;h2 id=&quot;simple-functions&quot;&gt;Simple Functions&lt;/h2&gt;

&lt;p&gt;It turns out, however, that none of our algorithms actually &lt;em&gt;needs&lt;/em&gt; a class-based interface. Plain and simple functions are fully sufficient, and the resulting API is much cleaner, leaner, and easier to use:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;icosahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;loop_subdivision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;decimate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course the above example is somewhat artificial, but I think you get the spirit. Straightforward code, less typing, uniform usage.&lt;/p&gt;

&lt;p&gt;Another benefit is that a simple function-based interface exposes far fewer implementation details in the headers files. And all that without resorting to constructions like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Opaque_pointer&quot;&gt;Pimpl idiom&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;reducing-api-surface&quot;&gt;Reducing API Surface&lt;/h2&gt;

&lt;p&gt;The next step was to reduce the functionality exposed in the public API. Some folks call this the API surface, and I think it’s a useful analogy. It is important to realize that &lt;em&gt;every&lt;/em&gt; externally observable behavior of your API will eventually be used and relied upon. The more dependencies you have the harder it gets to change and maintain your code over time. Therefore, one of your goals should be to keep your API surface small.&lt;/p&gt;

&lt;p&gt;In case of &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt;, the implementations of complex algorithms like remeshing or decimation make use of several helper classes such as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TriangleKdTree&lt;/code&gt; or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Quadric&lt;/code&gt; class. In the past, we used to make those helpers public, just in case someone might have a use for it. &lt;a href=&quot;https://en.wikipedia.org/wiki/You_aren&apos;t_gonna_need_it&quot;&gt;YAGNI&lt;/a&gt; at work. There’s absolutely no need to expose those helpers in the public API. Now they are all neatly tucked away in the implementation files of their respective algorithms.&lt;/p&gt;

&lt;h2 id=&quot;focus-on-singular-use-cases&quot;&gt;Focus on Singular Use Cases&lt;/h2&gt;

&lt;p&gt;Another common pitfall is to provide too many variants of algorithms. When you have an implementation of a well-known algorithm floating around, it’s always tempting to just add it to the library, just in case someone might need it. &lt;a href=&quot;https://en.wikipedia.org/wiki/You_aren&apos;t_gonna_need_it&quot;&gt;YAGNI&lt;/a&gt; again. However, this can lead to a large collection of algorithms with only half of them working correctly. Plus, your maintenance cost increases constantly.&lt;/p&gt;

&lt;p&gt;What I prefer instead is to have one algorithm implementation for a specific task. Example: We now have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loop_subdivision()&lt;/code&gt; for triangle meshes,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;catmull_clark_subdivision()&lt;/code&gt; for quad meshes, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quad_tri_subdivision()&lt;/code&gt; for mixed meshes. And that’s it. No need for three different triangle mesh subdivision schemes.&lt;/p&gt;

&lt;h2 id=&quot;dont-misuse-inheritance&quot;&gt;Don’t Misuse Inheritance&lt;/h2&gt;

&lt;p&gt;Even though I advocate for using functions above, classes and OOP still have their place. Inheritance is a key principle of OOP but it can be easily misused. This can be the case when using inheritance for purely technical reasons, code re-use, or out of convenience and laziness. If your inheritance does not represent an is-a relationship, you should be skeptical.&lt;/p&gt;

&lt;p&gt;In our library, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceMeshGL&lt;/code&gt; class responsible for rendering meshes was inheriting from the core &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurafaceMesh&lt;/code&gt; data structure. The main reason was just code reuse and convenience. It was convenient to have direct access to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceMesh&lt;/code&gt; internals. It was convenient to have a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceMeshGL&lt;/code&gt; member in all viewer classes and to modify the mesh through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceMesh&lt;/code&gt; API.&lt;/p&gt;

&lt;p&gt;However, this construction was in clear contradiction to &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt; principles, in particular the &lt;a href=&quot;https://en.wikipedia.org/wiki/Single-responsibility_principle&quot;&gt;single responsibility principle&lt;/a&gt;. It introduced tight coupling where none was required.&lt;/p&gt;

&lt;p&gt;I am now using an independent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Renderer&lt;/code&gt; class that only has a single responsibility, and I use composition in the viewer classes instead of relying on inheritance. Basic stuff, I know.&lt;/p&gt;

&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom Line&lt;/h2&gt;

&lt;p&gt;Striving for simplicity always has been one of the primary design goals for &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt;. However, things can get lost along the way. It remains a challenge to &lt;a href=&quot;/blog/2022/03/30/kiss-over-time.html&quot;&gt;keep things simple over time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There’s more work to come. I’m not yet happy with all aspects of the API, and there are other areas of doubtful complexity such as the inheritance hierarchy of the viewer classes.&lt;/p&gt;

&lt;h2 id=&quot;references-and-further-reading&quot;&gt;References and Further Reading&lt;/h2&gt;

&lt;p&gt;Related articles I wrote:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2022/03/30/kiss-over-time.html&quot;&gt;Keep it Simple, Over Time&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2022/07/25/your-code-doesnt-have-to-be-a-mess.html&quot;&gt;Your Code Doesn’t Have to Be a Mess&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2023/05/01/cpp-member-vs-free-functions.html&quot;&gt;C++ Member Functions vs. Free Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other Resources:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/SxdOUGdseq4&quot;&gt;Simple Made Easy&lt;/a&gt; by Rich Hickey&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=o9pEzgHorH0&quot;&gt;Stop Writing Classes&lt;/a&gt; by Jack Diedrich&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html&quot;&gt;Execution in the Kingdom of Nouns&lt;/a&gt; by Steve Yegge&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>C++ Member Functions vs. Free Functions</title>
   <link href="https://danielsieger.com/blog/2023/05/01/cpp-member-vs-free-functions.html"/>
   <updated>2023-05-01T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2023/05/01/cpp-member-vs-free-functions</id>
   <content type="html">&lt;p&gt;As a C++ programmer, you are probably familiar with the following design question: Should you implement a function as a class member or as a free function?&lt;/p&gt;

&lt;p&gt;Not so sure about the answer? Well, let’s examine.&lt;/p&gt;

&lt;h2 id=&quot;an-example&quot;&gt;An Example&lt;/h2&gt;

&lt;p&gt;Here’s an example from the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;mesh processing library&lt;/a&gt; I’m working on. Let’s say you have a class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceMesh&lt;/code&gt; for representing polygon meshes and you want to add a function that reads a mesh from different file formats.&lt;/p&gt;

&lt;p&gt;You basically have two obvious options.&lt;/p&gt;

&lt;p&gt;Either you add a class member:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filesystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or you use a free function:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filesystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which option would you choose?&lt;/p&gt;

&lt;p&gt;In the past, we used to have a member function, mostly for sake of convenience. It’s easy to discover, type, and remember. Problem solved?&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;file.obj&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Well, not so fast. This might be the obvious solution, but it’s not necessarily the best way from a software design perspective.&lt;/p&gt;

&lt;p&gt;In fact, there are very solid arguments for preferring free functions. Here are just a few:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Loose Coupling:&lt;/strong&gt; A free function is more loosely coupled to the class it is operating on. It only depends on the interface. This also enables generic functions being usable with different concrete classes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Encapsulation and Hiding:&lt;/strong&gt; A free function promotes encapsulation and information hiding since it does not have access to the implementation details of the class.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Flexibility and Extensibility:&lt;/strong&gt; Adding another free function is cheap and easy and does not require modification of the class definition.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Testing:&lt;/strong&gt; A free function is generally easier to test due to increased independence. No hacks required to test those pesky private member functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the list goes on. In fact, there is an excellent &lt;a href=&quot;https://www.youtube.com/watch?v=nWJHhtmWYcY&quot;&gt;talk&lt;/a&gt; by Klaus Iglberger going through this question in detail. He basically argues that free functions are the preferable choice in most cases. Notably, free functions help to follow &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt; principles.&lt;/p&gt;

&lt;p&gt;Along similar lines, Herb Sutter also recommends free functions in his &lt;a href=&quot;http://www.gotw.ca/publications/c++cs.htm&quot;&gt;C++ Coding Standards&lt;/a&gt;. Scott Meyers also favors free functions in &lt;a href=&quot;https://www.aristeia.com/books.html&quot;&gt;Effective C++&lt;/a&gt; item 23. He even came up with an algorithm to decide when to use a free function or a member function: Given a class &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt; and a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; related to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;, use the following algorithm:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if (f needs to be virtual)
{
    make f a member function of C;
}
else if (f is operator&amp;gt;&amp;gt; or operator&amp;lt;&amp;lt;)
{
    make f a non-member function;
    if (f needs access to non-public members of C)
    {
        make f a friend of C;
    }
}
else if (f needs type conversions on its left-most argument)
{
    make f a non-member function;
    if (f needs access to non-public members of C)
    {
        make f a friend of C;
    }
}
else
{
    make f a member function of C;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Admittedly, there are some advantages of member functions as well. For some folks they just might be easier to use. In particular, you get better IDE support for auto-completion when typing something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mesh.&lt;/code&gt; in the example above. There’s also a little less ambiguity since there’s at least one function argument less to worry about.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;In general, preferring free functions seems like a very reasonable choice. I think the main counter-argument is usability and discovery. However, there also is a &lt;a href=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf&quot;&gt;proposal&lt;/a&gt; by Bjarne Stroustrup and Herb Sutter for a unified function call syntax that would allow to simply write&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;file.stl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;if there is a function with the signature&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While this certainly would add some convenience, I’m not entirely sure it’s worth the added complexity. It’s not that C++ doesn’t already have enough of that!&lt;/p&gt;

&lt;p&gt;Let me close by saying that in practice the choice is not always that obvious. There might be cases when you design an API around free functions only to later realize that some function &lt;em&gt;does&lt;/em&gt; indeed needs access to the internals of the class. This has been exactly the case in the motivating example above, and so I resorted to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;friend&lt;/code&gt; function. 😕&lt;/p&gt;

&lt;h2 id=&quot;references-and-further-reading&quot;&gt;References and Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=nWJHhtmWYcY&quot;&gt;Free Your Functions&lt;/a&gt; by Klaus Iglberger&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.gotw.ca/publications/c++cs.htm&quot;&gt;C++ Coding Standards&lt;/a&gt; by Herb Sutter and Andrei Alexandrescu&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.aristeia.com/books.html&quot;&gt;Effective C++&lt;/a&gt; by Scott Meyers&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf&quot;&gt;Unified Call Syntax Proposal&lt;/a&gt; by Bjarne Stroustrup and Herb Sutter&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>A Framework for Better Documentation</title>
   <link href="https://danielsieger.com/blog/2023/04/24/framework-for-better-documentation.html"/>
   <updated>2023-04-24T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2023/04/24/framework-for-better-documentation</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/diataxis.jpg&quot; alt=&quot;Diataxis Framework&quot; width=&quot;350&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I recently came across an awesome framework for creating better technical documentation: The &lt;a href=&quot;https://diataxis.fr&quot;&gt;Diátaxis&lt;/a&gt; framework developed by Daniele Procida. It is a well-structured system that you can immediately apply to improve your software documentation. The basic idea goes like this.&lt;/p&gt;

&lt;h2 id=&quot;four-types-of-documentation&quot;&gt;Four Types of Documentation&lt;/h2&gt;

&lt;p&gt;The framework distinguishes between &lt;em&gt;four&lt;/em&gt; fundamental types of documentation.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Tutorials&lt;/li&gt;
  &lt;li&gt;Guides&lt;/li&gt;
  &lt;li&gt;Reference&lt;/li&gt;
  &lt;li&gt;Explanation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each type of documentation is geared towards a specific &lt;em&gt;audience&lt;/em&gt; and &lt;em&gt;purpose&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;tutorials&quot;&gt;Tutorials&lt;/h2&gt;

&lt;p&gt;The main goal of a tutorial is to help beginners getting started. The focus is on learning and acquiring the competencies required to use the software. The tutorial should contain step-by-step instructions. Each step should be easily attainable and provide concrete, meaningful results. The structure should be clear and linear. After completing the tutorial, the user should be ready to work with the other parts of the documentation to proceed his learning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience:&lt;/strong&gt; Beginners &lt;br /&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Learning&lt;/p&gt;

&lt;h2 id=&quot;guides&quot;&gt;Guides&lt;/h2&gt;

&lt;p&gt;How-to guides contain precise directions how to achieve a specific goal using the software. In contrast to learning-oriented tutorials, a guide is a form of task-oriented documentation. The user has a concrete question in mind, such as &lt;em&gt;“How do I write a mesh to a file?”&lt;/em&gt;. A guide already assumes a certain degree of familiarity with the subject area. Unnecessary details can be omitted. The goal is not to give the full picture. The focus is on helping the user while he is working with the software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience:&lt;/strong&gt; Intermediate &lt;br /&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Problem-solving&lt;/p&gt;

&lt;h2 id=&quot;reference&quot;&gt;Reference&lt;/h2&gt;

&lt;p&gt;This is the technical reference documentation that describes in detail how the machinery works. In case of a software library, this is most likely the API reference. The main goal of this type of documentation is information. To support this, it should be very concise and to the point. However, this should also include common pitfalls to be aware of.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience:&lt;/strong&gt; Experienced &lt;br /&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Information retrieval&lt;/p&gt;

&lt;h2 id=&quot;explanation&quot;&gt;Explanation&lt;/h2&gt;

&lt;p&gt;This is the more detailed background material that further clarifies the understanding of the software. An in-depth overview of the design of a library might be a good example. Something you’re interested in when you want to understand the internals of the system. Might also go by the names &lt;em&gt;background&lt;/em&gt;, &lt;em&gt;discussion&lt;/em&gt;, or &lt;em&gt;conceptual guides&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience:&lt;/strong&gt; Experts, developers&lt;br /&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Understanding&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;Obviously, I’m only scratching the surface here. If you want to dive deeper, have a look at the full description at &lt;a href=&quot;https://diataxis.fr&quot;&gt;diataxis.fr&lt;/a&gt;. There is also a &lt;a href=&quot;https://www.youtube.com/watch?v=t4vKPhjcMZg&quot;&gt;conference presentation&lt;/a&gt; by Daniele Procida on the same subject.&lt;/p&gt;

&lt;p&gt;Overall, the framework looks very well thought out to me. At least, it made me think about adapting documentation towards specific audiences and keeping their needs in mind. I hope I’ll find some time to put this into practice for &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://diataxis.fr&quot;&gt;Diátaxis Documentation Framework&lt;/a&gt; by Daniele Procida&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=t4vKPhjcMZg&quot;&gt;What nobody tells you about documentation&lt;/a&gt; by Daniele Procida&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jacobian.org/series/great-documentation/&quot;&gt;Writing Great Documentation&lt;/a&gt; by Jacob Kaplan-Moss&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Dieter Rams: Ten Principles for Good Design</title>
   <link href="https://danielsieger.com/blog/2023/03/31/principles-for-good-design.html"/>
   <updated>2023-03-31T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2023/03/31/principles-for-good-design</id>
   <content type="html">&lt;p&gt;Simply inspiring, always giving me new impulses: Ten principles for good design by &lt;a href=&quot;https://en.wikipedia.org/wiki/Dieter_Rams&quot;&gt;Dieter Rams&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-innovative&quot;&gt;Good Design is Innovative&lt;/h2&gt;

&lt;p&gt;The possibilities for innovation are not, by any means, exhausted. Technological development is always offering new opportunities for innovative design. But innovative design always develops in tandem with innovative technology, and can never be an end in itself.&lt;/p&gt;

&lt;h2 id=&quot;good-design-makes-a-product-useful&quot;&gt;Good Design Makes a Product Useful&lt;/h2&gt;

&lt;p&gt;A product is bought to be used. It has to satisfy certain criteria, not only functional but also psychological and aesthetic. Good design emphasizes the usefulness of a product while disregarding anything that could possibly detract from it.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-aesthetic&quot;&gt;Good Design is Aesthetic&lt;/h2&gt;

&lt;p&gt;The aesthetic quality of a product is integral to its usefulness because products are used every day and have an effect on people and their well-being. Only well-executed objects can be beautiful.&lt;/p&gt;

&lt;h2 id=&quot;good-design-makes-a-product-understandable&quot;&gt;Good Design Makes a Product Understandable&lt;/h2&gt;

&lt;p&gt;It clarifies the product’s structure. Better still, it can make the product talk. At best, it is self-explanatory.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-unobtrusive&quot;&gt;Good Design is Unobtrusive&lt;/h2&gt;

&lt;p&gt;Products fulfilling a purpose are like tools. They are neither decorative objects nor works of art. Their design should therefore be both neutral and restrained, to leave room for the user’s self-expression.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-honest&quot;&gt;Good Design is Honest&lt;/h2&gt;

&lt;p&gt;It does not make a product more innovative, powerful or valuable than it really is. It does not attempt to manipulate the consumer with promises that cannot be kept.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-long-lasting&quot;&gt;Good Design is Long-Lasting&lt;/h2&gt;

&lt;p&gt;It avoids being fashionable and therefore never appears antiquated. Unlike fashionable design, it lasts many years – even in today’s throwaway society.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-thorough-down-to-the-last-detail&quot;&gt;Good Design is Thorough Down to the Last Detail&lt;/h2&gt;

&lt;p&gt;Nothing must be arbitrary or left to chance. Care and accuracy in the design process show respect towards the user.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-environmentally-friendly&quot;&gt;Good Design is Environmentally Friendly&lt;/h2&gt;

&lt;p&gt;Design makes an important contribution to the preservation of the environment. It conserves resources and minimizes physical and visual pollution throughout the lifecycle of the product.&lt;/p&gt;

&lt;h2 id=&quot;good-design-is-as-little-design-as-possible&quot;&gt;Good Design is as Little Design as Possible&lt;/h2&gt;

&lt;p&gt;Less, but better – because it concentrates on the essential aspects, and the products are not burdened with non-essentials.&lt;/p&gt;

&lt;p&gt;Back to purity, back to simplicity.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://www.vitsoe.com/gb/about/good-design&quot;&gt;https://www.vitsoe.com/gb/about/good-design&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;License: &lt;a href=&quot;http://creativecommons.org/licenses/by-nc-nd/4.0/&quot;&gt;Creative Commons CC-BY-NC-ND 4.0 licence&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>C++17 Nested Namespaces</title>
   <link href="https://danielsieger.com/blog/2023/02/18/cpp17-nested-namespaces.html"/>
   <updated>2023-02-18T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2023/02/18/cpp17-nested-namespaces</id>
   <content type="html">&lt;p&gt;Nested namespaces used to be somewhat cumbersome in C++. You had to repeat the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;namespace&lt;/code&gt; keyword and by default each namespace resulted in an extra level of indentation:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pmp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;algorithms&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subdivision&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// your code here&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With a bit of tweaking, you could teach your IDE or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-format&lt;/code&gt; to avoid the indentation:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pmp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;algorithms&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subdivision&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// your code here&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Still, this always felt cumbersome to me.&lt;/p&gt;

&lt;p&gt;With C++17 you can write this much more compact manner:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pmp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;algorithms&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subdivision&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// your code here&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Admittedly, this is a relatively minor feature addition in C++17. However, now that I had a chance to use it I don’t want to miss it anymore.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>PMP Library Version 2.0 Released</title>
   <link href="https://danielsieger.com/blog/2022/08/15/pmp-library-version-2.0.html"/>
   <updated>2022-08-15T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/08/15/pmp-library-version-2.0</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We just released version 2.0 of &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt;, the Polygon Mesh Processing Library. This is a major version with several additions and improvements as well as some API changes. Highlights include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Support for texture seams in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceSimplification&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;A new quad/triangle subdivision scheme&lt;/li&gt;
  &lt;li&gt;A new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceFactory&lt;/code&gt; class for generating basic shapes&lt;/li&gt;
  &lt;li&gt;Error reporting using exceptions&lt;/li&gt;
  &lt;li&gt;Improved compatibility with the STL and CGAL&lt;/li&gt;
  &lt;li&gt;Additional rendering capabilities&lt;/li&gt;
  &lt;li&gt;Switch to C++14&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the official &lt;a href=&quot;https://www.pmp-library.org/version-2-0-released-2022-08-14.html&quot;&gt;release announcement&lt;/a&gt; and the &lt;a href=&quot;https://github.com/pmp-library/pmp-library/blob/master/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt; for a full summary of changes.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Your Code Doesn't Have to Be a Mess</title>
   <link href="https://danielsieger.com/blog/2022/07/25/your-code-doesnt-have-to-be-a-mess.html"/>
   <updated>2022-07-25T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/07/25/your-code-doesnt-have-to-be-a-mess</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Fools ignore complexity. Pragmatists suffer it. Some can avoid it. Geniuses remove it. - &lt;a href=&quot;https://www.cs.yale.edu/homes/perlis-alan/quotes.html&quot;&gt;Alan Perlis&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’ve been developing software for a while, you know that code has this natural tendency to turn into a mess. Keeping software simple over time is a challenge that keeps me thinking. My &lt;a href=&quot;/blog/2022/03/30/kiss-over-time.html&quot;&gt;last post&lt;/a&gt; left you hanging without much concrete advice. This time I will outline a few high-level strategies to keep software simple.&lt;/p&gt;

&lt;h2 id=&quot;define-clear-goals&quot;&gt;Define Clear Goals&lt;/h2&gt;

&lt;p&gt;Define clear goals what problem your software is trying to solve. Write them down, keep them visible. Always keep them in mind when making decisions about adding a new feature or accepting a proposed change. Do one thing and do it well. Don’t try to solve a myriad of problems at the same time. Follow basic &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_philosophy&quot;&gt;Unix philosophy&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;setup-constraints&quot;&gt;Setup Constraints&lt;/h2&gt;

&lt;p&gt;Define your non-goals as well: What problems does your software explicitly &lt;em&gt;not&lt;/em&gt; solve? Constrain the scope of your software. Setup technical constraints on programming languages, libraries, or models of computation you are using. Embrace those constraints and stick to them. They will force you to think harder about the problem at hand. Get creative within the bounds of your constraints. Working with constraints can &lt;a href=&quot;https://web.archive.org/web/20230211171326/https://www.inc.com/thomas-oppong/for-a-more-creative-brain-embrace-constraints.html&quot;&gt;foster creativity and innovation&lt;/a&gt;. However, be aware when you need to bend your code too much.&lt;/p&gt;

&lt;h2 id=&quot;say-no&quot;&gt;Say No&lt;/h2&gt;

&lt;p&gt;There is almost always an infinite demand for new features and functionality. Learning to say no is crucial to keep your software from growing wildly into too many directions. This can be super tough or downright impossible, notably in a commercial context. But even then: Do what is needed, but not more. Be aware of feature creep. But also be aware of when saying no would be unreasonable.&lt;/p&gt;

&lt;h2 id=&quot;eliminate-waste&quot;&gt;Eliminate Waste&lt;/h2&gt;

&lt;p&gt;Regularly pare down your code, and be relentless while doing it. Remove any unused features, dead code, debugging helpers, or prototype code used during development. Version control has your back. Eliminating waste is a core principle of &lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development&quot;&gt;lean software development&lt;/a&gt;. Borderline but fun: Only accept PRs that reduce net code size for a while. Be aware of code obfuscation though.&lt;/p&gt;

&lt;h2 id=&quot;minimize-dependencies&quot;&gt;Minimize Dependencies&lt;/h2&gt;

&lt;p&gt;Be picky about adding any dependencies. Don’t treat code re-use as a holy grail. Carefully consider the pros and cons. Dependencies might break, disappear, turn into garbage, or become a security risk. Consider to &lt;a href=&quot;https://macwright.com/2021/03/11/vendor-by-default.html&quot;&gt;vendor by default&lt;/a&gt;. If the functionality in question is crucial for your core business: Consider &lt;a href=&quot;https://www.joelonsoftware.com/2001/10/14/in-defense-of-not-invented-here-syndrome/&quot;&gt;doing it yourself&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;closing-remarks&quot;&gt;Closing Remarks&lt;/h2&gt;

&lt;p&gt;Obviously, the above strategies are not equally applicable in all settings. Your mileage may vary a lot between commercial development, an open source project, or creative coding.&lt;/p&gt;

&lt;p&gt;Similarly, striving for simplicity can be much harder if you are working on software that tackles complex problems. Some problem domains have an inherent complexity that can not be negotiated away. However, even in those cases you can strive for simplicity in the building blocks of your complex system.&lt;/p&gt;

&lt;p&gt;If you are developing software on a team, there is also an important social dimension. Some folks just revel in complexity, and it can be tough to develop a sense for simplicity with them. I’ve got the suspicion that the C++ crowd is particularly vulnerable to this disposition, but that’s another story.&lt;/p&gt;

&lt;p&gt;Finally, keep in mind that simplicity is not a value by itself. It is a means to an end: produce better software, and be able to maintain and evolve it over time.&lt;/p&gt;

&lt;h2 id=&quot;references-and-further-reading&quot;&gt;References and Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/SxdOUGdseq4&quot;&gt;Simple Made Easy&lt;/a&gt; by Rich Hickey
&lt;!-- - [The Myth of Software Simplicity](https://iansommerville.com/technology/software-simplicity/) by Ian Sommerville --&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_philosophy&quot;&gt;Unix philosophy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Lean_software_development&quot;&gt;Lean software development&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.cs.yale.edu/homes/perlis-alan/quotes.html&quot;&gt;Epigrams in Programming&lt;/a&gt; by Alan Perlis&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/3735293-clean-code&quot;&gt;Clean Code&lt;/a&gt; by Robert C. Martin&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/39996759-a-philosophy-of-software-design&quot;&gt;A Philosophy of Software Design&lt;/a&gt; by John Ousterhout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href=&quot;https://news.ycombinator.com/item?id=32224508&quot;&gt;discussion on HackerNews&lt;/a&gt; makes an interesting read, thanks to all participants!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Keep it Simple, Over Time</title>
   <link href="https://danielsieger.com/blog/2022/03/30/kiss-over-time.html"/>
   <updated>2022-03-30T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/03/30/kiss-over-time</id>
   <content type="html">&lt;p&gt;Perhaps you already heard of the &lt;a href=&quot;https://en.wikipedia.org/wiki/KISS_principle&quot;&gt;KISS principle&lt;/a&gt;. It’s an acronym for “keep it simple, stupid”. It states that most systems work best if kept simple. It’s a guiding principle in software engineering to favor simple solutions over complex ones.&lt;/p&gt;

&lt;p&gt;Simplicity as a design goal is one aspect of the KISS principle. I think another aspect is even more important, and that’s the &lt;em&gt;temporal&lt;/em&gt; one:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Keep&lt;/em&gt; it simple, over time.&lt;/p&gt;

&lt;p&gt;Coming up with a clean and lean design for a new project is already a challenge. Keeping things simple over time is a much bigger challenge due to the different forces at play at different points in time. New features, bug fixes, workarounds, engineering and business tradeoffs. They all make it extremely hard to maintain simplicity.&lt;/p&gt;

&lt;p&gt;Do I have an easy solution to this challenge? Sorry, not this time. It’s a question that makes me think. And I invite you to think about it as well.&lt;/p&gt;

&lt;p&gt;How do you &lt;em&gt;keep&lt;/em&gt; things simple, over time?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Code Coverage Testing for C++</title>
   <link href="https://danielsieger.com/blog/2022/03/06/code-coverage-for-cpp.html"/>
   <updated>2022-03-06T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/03/06/code-coverage-for-cpp</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/code-coverage/teaser.jpg&quot; alt=&quot;Code coverage visualization&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Do you have unit tests for your code? Yes? Awesome!&lt;/p&gt;

&lt;p&gt;Do you know how much of your code is executed by your tests? No?&lt;/p&gt;

&lt;p&gt;Aww, don’t feel bad!&lt;/p&gt;

&lt;p&gt;This is what code coverage testing is for: it gives you detailed information on how much of your code base is covered by your test suite.&lt;/p&gt;

&lt;p&gt;This post describes how to add code coverage testing to your C++ project. I’m assuming you are using CMake as build system and GCC or Clang as compiler.&lt;/p&gt;

&lt;h2 id=&quot;whats-code-coverage&quot;&gt;What’s Code Coverage?&lt;/h2&gt;

&lt;p&gt;Code coverage tells you which parts of your code are executed by your test suite and—even more important—which parts are not. The coverage rate is typically specified as a percentage of files, functions, blocks, or lines being covered.&lt;/p&gt;

&lt;p&gt;Code coverage works by instrumenting your code so that the resulting executable will generate statistics on which code paths are executed how many times. You can visualize the coverage information in different forms, such as a HTML report, in your CI system, or your IDE.&lt;/p&gt;

&lt;h2 id=&quot;why-use-code-coverage&quot;&gt;Why Use Code Coverage?&lt;/h2&gt;

&lt;p&gt;The main goal of code coverage testing to provide insight which parts of your code get tested. This increases confidence in your test suite. You can make sure that important code paths are properly executed by your tests. It shows if all branches are triggered or if there are corner cases left untested.&lt;/p&gt;

&lt;p&gt;A second advantage is that it helps to avoid redundancy. Without any information which code is triggered by a test, you are likely to run certain code paths over and over again. This contradicts the goal of having a test suite that runs fast, which is a key requirement for efficient testing.&lt;/p&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;I’ll proceed in three steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Command line usage&lt;/li&gt;
  &lt;li&gt;CMake integration&lt;/li&gt;
  &lt;li&gt;Continuous integration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For command line usage, I’ll use the &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/Gcov.html&quot;&gt;Gcov&lt;/a&gt; code coverage analysis tool. Both GCC and Clang can generate profiling information that can be processed by &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/Gcov.html&quot;&gt;Gcov&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s start with this simple example C++ code:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Compile this with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-coverage&lt;/code&gt; flag to tell the compiler to instrument the code:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;clang++ -O0 -coverage test.cpp &amp;amp;&amp;amp; ./a.out
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that disabling optimizations is required to get reliable coverage results, hence the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O0&lt;/code&gt; flag. After running the test program, you’ll see two additional files being generated:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;test.&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;test.cpp        test.gcda       test.gcno
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gcda&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gcno&lt;/code&gt; files contain the coverage data. Now run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcov&lt;/code&gt; to process the results:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;gcov test.cpp
&lt;span class=&quot;go&quot;&gt;File &apos;test.cpp&apos;
Lines executed:87.50% of 8
Creating &apos;test.cpp.gcov&apos;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Nice! This tells us that we already cover 87.5% of our lines of code. Not too bad, but there’s room for improvement.&lt;/p&gt;

&lt;p&gt;The resulting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.cpp.gcov&lt;/code&gt; file gives a more detailed breakdown which lines have been executed how many times:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        -:    0:Source:test.cpp
        -:    0:Graph:test.gcno
        -:    0:Data:test.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include &amp;lt;cassert&amp;gt;
        -:    2:
        1:    3:int max(int a, int b) {
        1:    4:    if (a &amp;gt; b) {
        1:    5:        return a;
        -:    6:    }
    #####:    7:    return b;
        1:    8:}
        -:    9:
        1:   10:int main() {
        1:   11:    assert(max(1, 0) == 1);
        1:   12:}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Not surprisingly, our little test here does not trigger all branches of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max()&lt;/code&gt; function. Let’s fix that by adding another assertion:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This bumps up our line coverage to 100%:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;gcov test.cpp
&lt;span class=&quot;go&quot;&gt;File &apos;test.cpp&apos;
Lines executed:100.00% of 9
Creating &apos;test.cpp.gcov&apos;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, let’s have a look how to visualize this information in a more accessible manner.&lt;/p&gt;

&lt;h2 id=&quot;generate-a-html-report&quot;&gt;Generate a HTML Report&lt;/h2&gt;

&lt;p&gt;Checking code coverage for a simple example like above is easy. However, for a larger project you want something to visualize the coverage information in a more convenient manner. In particular, identifying parts of the code which are not yet covered is important.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href=&quot;https://github.com/linux-test-project/lcov&quot;&gt;lcov&lt;/a&gt; comes in: it is a graphical fronted to your coverage data. In particular, you can use it to generate HTML reports. This is done in two steps. First, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lcov&lt;/code&gt; in the directory with the coverage information:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;lcov --directory . --capture --output-file coverage.info
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then generate the HTML files:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;genhtml --demangle-cpp -o coverage coverage.info
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open the resulting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coverage/index.html&lt;/code&gt; file in a browser of your choice and you’ll see an overview like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/code-coverage/lcov-overview.jpg&quot; alt=&quot;Code coverage results visualized using lcov&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This allows you to locally browse through your code base and check which parts are covered (light blue) and which not (orange).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/code-coverage/lcov.jpg&quot; alt=&quot;Code coverage results visualized using lcov&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that I’m showing the version for the lower coverage rate here.&lt;/p&gt;

&lt;h2 id=&quot;cmake-integration&quot;&gt;CMake Integration&lt;/h2&gt;

&lt;p&gt;For convenience, you can integrate the report generation directly into your build system. Here’s a basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CMakeLists.txt&lt;/code&gt; file that adds a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coverage&lt;/code&gt; target to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lcov&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;genhtml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cmake_minimum_required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;VERSION 3.6&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage-example&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;ENABLE_COVERAGE&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# set compiler flags&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CMAKE_CXX_FLAGS &lt;span class=&quot;s2&quot;&gt;&quot;-O0 -coverage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# find required tools&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;find_program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;LCOV lcov REQUIRED&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;find_program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;GENHTML genhtml REQUIRED&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# add coverage target&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;add_custom_target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;coverage
    &lt;span class=&quot;c1&quot;&gt;# gather data&lt;/span&gt;
    COMMAND &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LCOV&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; --directory . --capture --output-file coverage.info
    &lt;span class=&quot;c1&quot;&gt;# generate report&lt;/span&gt;
    COMMAND &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GENHTML&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; --demangle-cpp -o coverage coverage.info
    WORKING_DIRECTORY &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CMAKE_BINARY_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;add_executable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;test test.cpp&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Configure and build the project with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ENABLE_COVERAGE&lt;/code&gt; option:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;cmake -DENABLE_COVERAGE=true .. &amp;amp;&amp;amp; make
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you can run the executable and generate the HTML report:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;./test &amp;amp;&amp;amp; make coverage
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;continuous-integration&quot;&gt;Continuous Integration&lt;/h2&gt;

&lt;p&gt;You can take coverage testing one step further and directly integrate it into your continuous integration (CI) pipeline. This is useful for checking how the coverage rate evolves and to make sure it does not decrease as you integrate new features into your project.&lt;/p&gt;

&lt;p&gt;In this example, I’m using &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt; for integration builds and the &lt;a href=&quot;https://coveralls.io&quot;&gt;Coveralls&lt;/a&gt; web service to visualize results.&lt;/p&gt;

&lt;p&gt;Here is an example for a GitHub workflow that builds and runs the example project from above and uploads the coverage results to Coveralls:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;coverage&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;push&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;BUILD_TYPE&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Debug&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Install dependencies&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;runner.os == &apos;Linux&apos;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo apt-get install -o Acquire::Retries=3 lcov&lt;/span&gt;

      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Create build directory&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cmake -E make_directory ${{runner.workspace}}/build&lt;/span&gt;

      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configure CMake&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bash&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{runner.workspace}}/build&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD -DENABLE_COVERAGE=true&lt;/span&gt;

      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{runner.workspace}}/build&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bash&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cmake --build . --config $BUILD_TYPE&lt;/span&gt;

      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Run&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{runner.workspace}}/build&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bash&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./test&lt;/span&gt;

      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Coverage&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;working-directory&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{runner.workspace}}/build&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bash&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;make coverage&lt;/span&gt;

      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Coveralls&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;coverallsapp/github-action@master&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;path-to-lcov&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{runner.workspace}}/build/coverage.info&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;github-token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you are curious what the result looks like for a real-world project, check out the &lt;a href=&quot;https://coveralls.io/github/pmp-library/pmp-library?branch=main&quot;&gt;Coveralls page&lt;/a&gt; for our &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;mesh processing library&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom Line&lt;/h2&gt;

&lt;p&gt;Code coverage testing is a tremendously useful tool that I regularly use during development. When writing new code, it gives me confidence that my tests are doing what I think they do. However, I find it particularly useful when bringing legacy code under test. The coverage information guides me which tests to write until I reach sufficient coverage for that code.&lt;/p&gt;

&lt;p&gt;Beware though that using code coverage as a quality metric can be misleading. High coverage is not a goal in itself. It’s a means, not an end. The fact that there is a test triggering your code does not guarantee you anything about wether the test does something &lt;em&gt;meaningful&lt;/em&gt; at all.&lt;/p&gt;

&lt;p&gt;Give code coverage a try. I bet that once you experience the benefit of having coverage information available you don’t want to miss it form your development toolbox.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>C++ Trailing Return Types</title>
   <link href="https://danielsieger.com/blog/2022/01/28/cpp-trailing-return-types.html"/>
   <updated>2022-01-28T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/01/28/cpp-trailing-return-types</id>
   <content type="html">&lt;p&gt;The other day, I was modernizing the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP library&lt;/a&gt; code using &lt;a href=&quot;https://clang.llvm.org/extra/clang-tidy/&quot;&gt;clang-tidy&lt;/a&gt;. One of the suggestions was to use trailing function return types. I didn’t look too close at this C++11 feature before. Read on for a brief introduction and a summary of pros and cons.&lt;/p&gt;

&lt;h2 id=&quot;whats-this&quot;&gt;What’s This?&lt;/h2&gt;

&lt;p&gt;Trailing return types are an alternative syntax introduced in C++11 to declare the return type of a function. In the old form you specify the return type before the name of the function:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With the new syntax you write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto&lt;/code&gt; before the function name and specify the return type &lt;em&gt;after&lt;/em&gt; the function name and parameters:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This looks strange to a C++ developer at first. However, other languages like Swift, Rust, or Haskell use a similar notation. Thinking of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto&lt;/code&gt; as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;func&lt;/code&gt; keyword might help.&lt;/p&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;The main motivation for this alternative syntax is to specify the return type of a function template when the return type depends on the template arguments. Consider the following function:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;???&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case, the general return type of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multiply()&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decltype(a*b)&lt;/code&gt;. However, you can’t write this using the standard function syntax. C++ parses from left to right. Therefore, the function parameters &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; are not yet in scope when specifying the return type before the function name.&lt;/p&gt;

&lt;p&gt;There is a workaround using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;declval()&lt;/code&gt;, but this gets confusing:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;decltype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;declval&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;declval&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The alternative syntax solves this problem. Now you can directly write the correct return type:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;decltype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;pros&quot;&gt;Pros&lt;/h2&gt;

&lt;p&gt;With two different ways to specify the return type the question comes up which one to use. Let’s have a look at the pros first.&lt;/p&gt;

&lt;h3 id=&quot;consistency&quot;&gt;Consistency&lt;/h3&gt;

&lt;p&gt;I think consistency is a strong argument for the new syntax. The example above shows that the new syntax is helpful in certain cases. Lambda functions use trailing return types as well:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;square&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The new syntax is aligned with the general trend of modern C++ to move towards a left to right syntax:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;square&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Herb Sutter goes into more detail in his &lt;a href=&quot;https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/&quot;&gt;Almost Always Auto Style&lt;/a&gt; article.&lt;/p&gt;

&lt;h3 id=&quot;understanding&quot;&gt;Understanding&lt;/h3&gt;

&lt;p&gt;When reading a function declaration the main thing I’m interested in is &lt;em&gt;understanding&lt;/em&gt; what it does. Assuming that functions are properly named by their developers, the most important information is in the function name and not the return type. Therefore, it makes sense to put the name first.&lt;/p&gt;

&lt;p&gt;A trailing return type is also closer to mathematical notation and the way we speak about functions in math. Let $f\;\colon\;\mathbb{R} \to \mathbb{R}$ be a function…&lt;/p&gt;

&lt;h3 id=&quot;readability&quot;&gt;Readability&lt;/h3&gt;

&lt;p&gt;Using trailing return types neatly aligns the function names:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number_of_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertices_begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VertexIterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The notation can be shorter than the standard return type, for example when returning a type defined inside a class such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VertexIterator&lt;/code&gt; above. The standard syntax would require the class scope to be specified explicitly:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VertexIterator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices_begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The new syntax is slightly more concise:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SurfcaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices_begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VertexIterator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;cons&quot;&gt;Cons&lt;/h2&gt;

&lt;p&gt;Two main drawbacks come to mind.&lt;/p&gt;

&lt;h3 id=&quot;lack-of-familiarity&quot;&gt;Lack of Familiarity&lt;/h3&gt;

&lt;p&gt;Obviously, most existing code does not use the new syntax. Therefore, not all developers are familiar with it. There’s also a pitfall with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;override&lt;/code&gt;, which has to go &lt;em&gt;after&lt;/em&gt; the return type since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;override&lt;/code&gt; is not part of the function type:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve seen the new syntax being used in some open source libraries. However, they are clearly in the minority. Using the new syntax therefore would make your library &lt;em&gt;inconsistent&lt;/em&gt; with large parts of the C++ ecosystem.&lt;/p&gt;

&lt;h3 id=&quot;more-typing&quot;&gt;More Typing&lt;/h3&gt;

&lt;p&gt;Using the new syntax can require more typing, notably for trivial functions. I don’t think that many folks would prefer writing&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;instead of&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Excluding such cases would kill the consistency argument from above.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I’m not sure if using trailing return types everywhere is a good idea. The consistency argument and potential improvements in readability and understanding &lt;em&gt;almost&lt;/em&gt; got me sold. They’re only nice to have though, and not much more.&lt;/p&gt;

&lt;p&gt;The lack of familiarity is a major reason not to use the new syntax. Furthermore, C++14 introduced the possibility to automatically deduce the return type. With that, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multiply()&lt;/code&gt; example from above gets even simpler:&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This reduces the number of cases where the new return syntax is required, thereby making it a rather odd choice for normal function declarations.&lt;/p&gt;

&lt;p&gt;Keep in mind though that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto&lt;/code&gt; return type deduction is not always what you want. It’s certainly fine for short functions like the example above. In general, however, I prefer explicit return types so that users know what they get without reading and understanding the full implementation or relying on an IDE.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/&quot;&gt;GotW #94 Solution: AAA Style&lt;/a&gt; by Herb Sutter&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.petrzemek.net/2017/01/17/pros-and-cons-of-alternative-function-syntax-in-cpp/&quot;&gt;Pros and Cons of Alternative Function Syntax in C++&lt;/a&gt; by Petr Zemek&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://arne-mertz.de/2018/05/trailing-return-types-east-const-and-code-style-consistency/&quot;&gt;Trailing Return Types, East Const, and Code Style Consistency&lt;/a&gt; by Arne Mertz&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.fluentcpp.com/2018/09/28/auto-stick-changing-style/&quot;&gt;“auto to stick” and Changing Your Style&lt;/a&gt; by Jonathan Boccara&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Join the &lt;a href=&quot;https://www.reddit.com/r/cpp/comments/su6eyf/c_trailing_return_types/&quot;&gt;discussion on Reddit&lt;/a&gt;. Thanks for all the comments. Special thanks to &lt;a href=&quot;https://www.reddit.com/user/jwakely/&quot;&gt;u/jwakely&lt;/a&gt; for spotting an inaccuracy with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::declval&amp;lt;&amp;gt;&lt;/code&gt; parameter types.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Unit Testing: Short and Sweet</title>
   <link href="https://danielsieger.com/blog/2022/01/21/unit-testing-short-and-sweet.html"/>
   <updated>2022-01-21T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/01/21/unit-testing-short-and-sweet</id>
   <content type="html">&lt;p&gt;This is the short and sweet introduction to unit testing I always wanted to have as a reference for colleagues, friends, and family. Enjoy.&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-unit-test&quot;&gt;What Is a Unit Test?&lt;/h2&gt;

&lt;p&gt;A unit test ensures that an individual unit of code behaves as intended. A &lt;em&gt;unit&lt;/em&gt; is a minimal chunk of code that can be tested &lt;em&gt;in isolation&lt;/em&gt;, such as a function or a class.&lt;/p&gt;

&lt;p&gt;A test is &lt;em&gt;not&lt;/em&gt; a unit test if it talks to a database, requires network access, writes to the filesystem, or requires a complex environment to be setup. This is crucial to keep things independent, robust, and fast.&lt;/p&gt;

&lt;p&gt;Unit tests form the basis of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Test_automation&quot;&gt;test automation pyramid&lt;/a&gt;. Write lots of them. Make them run fast.&lt;/p&gt;

&lt;h2 id=&quot;why-unit-testing&quot;&gt;Why Unit Testing?&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Correctness:&lt;/strong&gt; Unit testing helps you to write correct code. You detect errors early during development and avoid costly changes later on.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Evolution:&lt;/strong&gt; Unit tests allow you to evolve your code over time. You can refactor your code without fear of introducing subtle bugs. This is key for reducing technical debt and improving your design.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Design:&lt;/strong&gt; Unit testing encourages good design practices such as modularization and minimizing dependencies between components.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Documentation:&lt;/strong&gt; Unit tests document the behavior of the code. They serve as a form of executable specification.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;unit-testing-best-practices&quot;&gt;Unit Testing Best Practices&lt;/h2&gt;

&lt;p&gt;Good unit tests follow &lt;strong&gt;FIRST&lt;/strong&gt; principles:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Fast:&lt;/strong&gt; Run fast so that developers can run them frequently&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Independent:&lt;/strong&gt; Run standalone, in any order, without dependencies&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Repeatable:&lt;/strong&gt; Give consistent and reliable results on each run&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Self-validating:&lt;/strong&gt; Indicate success or failure without manual inspection&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Timely:&lt;/strong&gt; Written together with production code to foster testable design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clean unit tests follow the &lt;strong&gt;AAA&lt;/strong&gt; pattern:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Arrange:&lt;/strong&gt; Setup the test&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Act:&lt;/strong&gt; Execute the function under test&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Assert:&lt;/strong&gt; Use an appropriate assert&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern implies testing a &lt;strong&gt;single concept&lt;/strong&gt; per test case, using a &lt;strong&gt;single assertion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Start with testing the &lt;strong&gt;happy path&lt;/strong&gt;: Make sure that intended usage of the code produces the desired result.&lt;/p&gt;

&lt;p&gt;Don’t forget the &lt;strong&gt;unhappy paths&lt;/strong&gt;: Gracefully handle corner cases, unexpected input, pre-condition violations, or error conditions.&lt;/p&gt;

&lt;p&gt;Aim to cover your complete &lt;strong&gt;public API&lt;/strong&gt; with unit tests. Trivial functions like getters and setters might be excluded.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;code coverage&lt;/strong&gt; tools to analyze which code paths are actually triggered by your tests.&lt;/p&gt;

&lt;p&gt;Let your testing code follow the same &lt;strong&gt;high standards&lt;/strong&gt; as your production code: well designed, thoughtfully partitioned, and using meaningful names. Comments explain what is tested and why.&lt;/p&gt;

&lt;p&gt;Refactor common setup code into a &lt;strong&gt;fixture&lt;/strong&gt; to avoid repetition.&lt;/p&gt;

&lt;p&gt;If your tests use tolerances, make them configurable so that you can check that &lt;em&gt;nothing&lt;/em&gt; changed in the results.&lt;/p&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;Next time you…&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;add new code, write at least one unit test covering the happy path&lt;/li&gt;
  &lt;li&gt;find a bug, write a unit test that would have caught it&lt;/li&gt;
  &lt;li&gt;refactor a part of your code, bring it under test first&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When time and circumstances permit: Setup code coverage and bring all critical parts of your code under test.&lt;/p&gt;

&lt;h2 id=&quot;the-bottom-line&quot;&gt;The Bottom Line&lt;/h2&gt;

&lt;p&gt;Unit testing is like exercising: you know it’s good for you, but it can be tough to get started. It’s even more difficult to stick to it after the initial enthusiasm wears off. It’s an investment in the future of your code that pays off.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/387190.Test_Driven_Development&quot;&gt;Test-Driven Development: By Example&lt;/a&gt; by Kent Beck&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/43242144-refactoring&quot;&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt; by Martin Fowler&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/44919.Working_Effectively_with_Legacy_Code&quot;&gt;Working Effectively with Legacy Code&lt;/a&gt; by Michael Feathers&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.tbray.org/ongoing/When/202x/2021/05/15/Testing-in-2021&quot;&gt;Testing in the Twenties&lt;/a&gt; by Tim Bray&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackify.com/unit-testing-basics-best-practices&quot;&gt;You Still Don’t Know How to Do Unit Testing&lt;/a&gt; by Erik Dietrich&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other articles I’ve written on testing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2018/09/11/unit-testing-geometric-algorithms.html&quot;&gt;Unit Testing Geometric Algorithms&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2019/01/20/unit-testing-file-io.html&quot;&gt;Unit Testing File IO&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2019/01/05/software-testing-in-research.html&quot;&gt;On Software Testing in Research&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>One Week of Ray Tracing in Rust</title>
   <link href="https://danielsieger.com/blog/2022/01/16/ray-tracing-in-rust.html"/>
   <updated>2022-01-16T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/01/16/ray-tracing-in-rust</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/ray-tracing-in-rust/teaser.jpg&quot; alt=&quot;Teaser image: Three spheres with shadows&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I started this year with one week of learning Rust and implementing a ray tracer from scratch using test-driven development.&lt;/p&gt;

&lt;p&gt;My primary goal was to learn more about Rust. I had a look at the language before, but I did not yet find the time to work on any substantial project.&lt;/p&gt;

&lt;p&gt;Writing a ray tracer from scratch is an ideal project for learning a new language. The task itself is straightforward, but you can go arbitrarily deep and sophisticated. Plus, working on something that gives instant visual results is always a pleasure.&lt;/p&gt;

&lt;h2 id=&quot;the-ray-tracer-challenge&quot;&gt;The Ray Tracer Challenge&lt;/h2&gt;

&lt;p&gt;I followed the book &lt;a href=&quot;http://www.raytracerchallenge.com&quot;&gt;&lt;em&gt;The Ray Tracer Challenge&lt;/em&gt;&lt;/a&gt; by Jamis Buck, a test-driven guide to ray tracing. The book is written in an approachable style and does not assume any previous knowledge. As long as you have basic knowledge in any programming language you should be able to follow the text without problems.&lt;/p&gt;

&lt;p&gt;The book is unique in the sense that it follows a test-driven approach independent of a particular programming language. Tests are described in easy to understand &lt;a href=&quot;https://en.wikipedia.org/wiki/Cucumber_(software)#Gherkin_language&quot;&gt;Gherkin language&lt;/a&gt;. Here’s an example:&lt;/p&gt;

&lt;div class=&quot;language-gherkin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;Scenario&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; The magnitude of a normalized vector
  &lt;span class=&quot;nf&quot;&gt;Given &lt;/span&gt;v ← vector(1, 2, 3)
  &lt;span class=&quot;nf&quot;&gt;When &lt;/span&gt;norm ← normalize(v)
  &lt;span class=&quot;nf&quot;&gt;Then &lt;/span&gt;magnitude(norm) = 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s up to you to either implement the corresponding unit tests or to hook up the Gherkin files as test cases. I chose to write unit tests myself for sake of simplicity (at the expense of tedious repetition).&lt;/p&gt;

&lt;p&gt;I admit: Learning a new language &lt;em&gt;and&lt;/em&gt; following a test-driven approach slowed me down somewhat in the beginning. However, once I figured out the basics, things went smoothly. By the end of the week, I was comfortable enough to do much of the work without looking up things all the time.&lt;/p&gt;

&lt;h2 id=&quot;rust-experience&quot;&gt;Rust Experience&lt;/h2&gt;

&lt;p&gt;My experience working with Rust was consistently positive. This applies to both the language and the ecosystem around it. Rust prides itself for being a performant, reliable, and productive language. And Rust delivers.&lt;/p&gt;

&lt;p&gt;If you have a C++ background like me, you’ll find that learning the basics is not that difficult. You’ll likely find the build system, package management, and IDE integration to be an absolute blessing. Having a minimal unit testing framework readily available was great for a quick start. Personally, I found generic programming in Rust to be much more enjoyable than in C++.&lt;/p&gt;

&lt;p&gt;I won’t go down the rabbit hole of writing a comprehensive comparison between Rust and C++. You can find enough of them online. Instead, I’ll briefly list the pros and cons that I came across during this week.&lt;/p&gt;

&lt;h3 id=&quot;the-good&quot;&gt;The Good&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Memory-safe and thread-safe by default&lt;/li&gt;
  &lt;li&gt;Immutable by default: Only allow change when necessary&lt;/li&gt;
  &lt;li&gt;Strict by default: No implicit type conversions&lt;/li&gt;
  &lt;li&gt;Concise yet expressive syntax: Sometimes Rust feels like a wild mix of C++ and Haskell, but in a positive sense.&lt;/li&gt;
  &lt;li&gt;Trailing function return types: Feels much more natural and closer to mathematical notation.&lt;/li&gt;
  &lt;li&gt;Traits system and generic programming: Helpful error messages!&lt;/li&gt;
  &lt;li&gt;Error reporting: The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Result&amp;lt;T,E&amp;gt;&lt;/code&gt; type is cleaner than normal error codes and much simpler than exceptions.&lt;/li&gt;
  &lt;li&gt;Cargo package management and build system&lt;/li&gt;
  &lt;li&gt;IDE integration with VS Code and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rust-analyzer&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Static analysis with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clippy&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Straightforward parallelization with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rayon&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;the-annoying&quot;&gt;The Annoying&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Working with strings. Although everything is consistent if you know the rationale behind, it is more cumbersome than in other languages&lt;/li&gt;
  &lt;li&gt;Having to type dots for floating point numbers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;) is a pain. At least in the beginning. Now it’s in muscle memory.&lt;/li&gt;
  &lt;li&gt;No &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operator()&lt;/code&gt; to overload. Therefore, no conventional matrix notation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A(i,j)&lt;/code&gt; for element access.&lt;/li&gt;
  &lt;li&gt;No default constructors, cumbersome &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; initializers&lt;/li&gt;
  &lt;li&gt;No function overloading&lt;/li&gt;
  &lt;li&gt;No default arguments&lt;/li&gt;
  &lt;li&gt;No variable argument lists&lt;/li&gt;
  &lt;li&gt;Const generics: As a recent addition to the language, this feature is incomplete.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;summing-up&quot;&gt;Summing Up&lt;/h2&gt;

&lt;p&gt;Learning Rust and working with the language was a breeze of fresh air. Writing a ray tracer from scratch is a great programming exercise, and the book by Jamis Buck provides a low-barrier entry. The test-driven approach is well thought out and encourages using TDD in practice. I haven’t finished all the chapters yet, but I’m sure I’ll continue.&lt;/p&gt;

&lt;p&gt;Likewise, I’ll deepen my knowledge about Rust. I was skeptical at first because of all the hype. However, the more I work with the language the more I enjoy it.&lt;/p&gt;

&lt;p&gt;I encourage you to try Rust yourself. Stop reading blog posts about Rust! Head over to the &lt;a href=&quot;https://www.rust-lang.org&quot;&gt;Rust homepage&lt;/a&gt;, learn the basics, and use the language for a side project.&lt;/p&gt;

&lt;p&gt;Keep an open mind.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Exceptions vs. Error Codes</title>
   <link href="https://danielsieger.com/blog/2022/01/02/exceptions_vs_error_codes.html"/>
   <updated>2022-01-02T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2022/01/02/exceptions_vs_error_codes</id>
   <content type="html">&lt;p&gt;Consistent error handling is a key feature of a high quality software library. Until recently, the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;mesh processing library&lt;/a&gt; I’m working on did a poor job in this regard. This gave me the opportunity to revisit C++ error handling. I took a few notes in between. Hope this helps you choosing an error handling strategy in your C++ projects.&lt;/p&gt;

&lt;p&gt;There are two major approaches to error handling in C++:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;Error codes&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Exceptions&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’ll briefly introduce both approaches and highlight their pros and cons.&lt;/p&gt;

&lt;h2 id=&quot;error-codes&quot;&gt;Error Codes&lt;/h2&gt;

&lt;p&gt;The traditional way to report errors is by using &lt;em&gt;error codes&lt;/em&gt;&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. They come in various forms, such as returning a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bool&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; value:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;667&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This basic form of error reporting relies on convention: What does it mean to return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;667&lt;/code&gt;? Something good or bad? That’s up for interpretation and documentation. The error code does not convey any meaning by itself.&lt;/p&gt;

&lt;p&gt;More well-engineered error reporting uses an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enum&lt;/code&gt; or similar to provide symbolic constants that convey meaning about what type of error occurred:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ReturnType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SUCCESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOLVE_FAILED&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BAD_INPUT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A major drawback of error codes is that they lead to function calls being intertwined with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if..else&lt;/code&gt; blocks testing for the various error conditions.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SUCCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;yay!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOLVE_FAILED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nay!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BAD_INPUT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;meh!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The result is that program logic is mixed up with error handling. This is not a big issue in the simple example above, but it quickly becomes confusing in real-world code.&lt;/p&gt;

&lt;h2 id=&quot;exceptions&quot;&gt;Exceptions&lt;/h2&gt;

&lt;p&gt;Exceptions are a more modern alternative to error codes. An exception is an error generated at runtime which is propagated through the call stack until it is either caught or the program terminates. Here’s a simple example:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdexcept&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runtime_error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runtime_error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cerr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;pros&quot;&gt;Pros&lt;/h3&gt;

&lt;p&gt;Here are the biggest advantages I see in using exceptions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cleaner code.&lt;/strong&gt; Exceptions can be &lt;em&gt;thrown&lt;/em&gt; at any point in the program, including class constructors which don’t return any value. Exceptions are independent of the return type of a function. The code &lt;em&gt;catching&lt;/em&gt; the exception can be separate from the location the error occurred, thereby avoiding intertwining of application logic and error handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proper types.&lt;/strong&gt; Exceptions use proper types checked by the compiler. You can create your own exception classes to give the error additional semantic meaning and to pass information about the error with the exception. A practical example from mesh processing would be to include information about the location of the error so that you could highlight the problematic region in your visualization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Harder to ignore.&lt;/strong&gt; Function return values can be silently ignored. Exceptions need to be handled explicitly, otherwise the program will terminate. You are free to ignore an exception locally as long as it is taken care of higher up the call stack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standardization.&lt;/strong&gt; You can’t avoid exceptions if you are using the standard library. The &lt;a href=&quot;https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines&quot;&gt;C++ Core Guidelines&lt;/a&gt; recommend the use of exceptions. Using exceptions is a modern C++ best practice.&lt;/p&gt;

&lt;h3 id=&quot;cons&quot;&gt;Cons&lt;/h3&gt;

&lt;p&gt;Here are my top three drawbacks of exceptions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visibility.&lt;/strong&gt; Exceptions are not directly visible in the source code. You can’t see what exceptions can be thrown by a function by looking at its signature. Even looking at the implementation does not reveal which exceptions could be thrown by &lt;em&gt;other&lt;/em&gt; functions called in the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control flow.&lt;/strong&gt; Exceptions are an abrupt change in control flow, much like a goto statement. This can make it difficult to reason about the control flow of the program, making it harder to debug the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation effort.&lt;/strong&gt; Exceptions need special care when implementing them. Otherwise, you risk subtle errors such as memory leaks. Following the RAII&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; idiom is a key guideline here.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Personally, I like the simplicity of return codes. It’s a straightforward approach. You can teach it to a beginner in no time. This is not the case with exceptions. Doing exceptions right is a challenge. I’m not even sure I’m getting things right in &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt; right now.&lt;/p&gt;

&lt;p&gt;However, I feel that the advantages outweigh the disadvantages. If you are developing a library that adheres to modern C++ best practices, exceptions are the method of choice for error handling&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id=&quot;references-and-further-reading&quot;&gt;References and Further Reading&lt;/h2&gt;

&lt;p&gt;Check out the following references if you are interested in more concrete guidelines on writing exception-safe code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://isocpp.org/blog/2012/11/exception-safe-coding-in-cpp&quot;&gt;Exception-Safe Coding in C++&lt;/a&gt; by Jon Kalb&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/cpp/cpp/how-to-design-for-exception-safety?view=msvc-160&quot;&gt;How to: Design for exception safety&lt;/a&gt; by Microsoft&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-170&quot;&gt;Modern C++ best practices for exceptions and error handling&lt;/a&gt; by Microsoft&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/1853243/do-you-really-write-exception-safe-code/1853769#1853769&quot;&gt;Do you (really) write exception safe code?&lt;/a&gt; on StackOverflow&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://isocpp.org/wiki/faq/exceptions&quot;&gt;ISO C++ FAQ on Exceptions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.stroustrup.com/3rd_safe.pdf&quot;&gt;Standard-Library Exception Safety&lt;/a&gt; by Bjarne Stroustrup&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I use the term ‘error codes’ instead of ‘return codes’ because the codes could be reported differently than through a function return value, for example via a global error status variable. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;RAII stands for “resource acquisition is initialization” and means that resources are acquired during object initialization and released during object destruction. See the Wikipedia &lt;a href=&quot;https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization&quot;&gt;article&lt;/a&gt; for more information. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There are a few exceptions, though (no pun intended). Special purpose code like hard real-time systems might have different constraints that prohibit the use of exceptions. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Using clang-tidy with CMake</title>
   <link href="https://danielsieger.com/blog/2021/12/21/clang-tidy-cmake.html"/>
   <updated>2021-12-21T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/12/21/clang-tidy-cmake</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://clang.llvm.org/extra/clang-tidy/&quot;&gt;Clang-tidy&lt;/a&gt; is a C++ static analysis tool from the &lt;a href=&quot;https://llvm.org&quot;&gt;LLVM
project&lt;/a&gt; that is particularly helpful when modernizing your code base or
when checking your code for compliance with established guidelines and best
practices.&lt;/p&gt;

&lt;p&gt;Typically, you need to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-tidy&lt;/code&gt; with the same options and compiler flags
you use for compilation. Doing this manually can be quite a hassle.&lt;/p&gt;

&lt;p&gt;One way to help with this is to use a &lt;a href=&quot;https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html&quot;&gt;compilation database&lt;/a&gt;. However, I
always found this to be rather complicated by itself.&lt;/p&gt;

&lt;p&gt;Luckily, if you are using CMake, there is a simpler alternative: You can
directly use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-tidy&lt;/code&gt; from CMake.&lt;/p&gt;

&lt;p&gt;You need to do two steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Find and setup the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-tidy&lt;/code&gt; command&lt;/li&gt;
  &lt;li&gt;Tell CMake to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-tidy&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the first step, you only need to use CMake’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find_program()&lt;/code&gt; and set the
corresponding CMake variable to the command and options you want to use:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;find_program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CLANG_TIDY_EXE NAMES &lt;span class=&quot;s2&quot;&gt;&quot;clang-tidy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CLANG_TIDY_COMMAND &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CLANG_TIDY_EXE&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-checks=-*,modernize-*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the above, I disable all default checks (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-*&lt;/code&gt;) and only enable checks that
advocate the use of modern C++ language constructs (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modernize-*&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For the second step, you tell CMake to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-tidy&lt;/code&gt; by setting the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CXX_CLANG_TIDY&lt;/code&gt; property for your build target:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;set_target_properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;target PROPERTIES CXX_CLANG_TIDY &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CLANG_TIDY_COMMAND&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s all! Run your build as usual and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-tidy&lt;/code&gt; will report suggestions
for modernization as warnings.&lt;/p&gt;

&lt;p&gt;Here’s a fully self-contained &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CMakeLists.txt&lt;/code&gt; file for demonstration purposes:&lt;/p&gt;

&lt;div class=&quot;language-cmake highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cmake_minimum_required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;VERSION 3.6&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;clang-tidy-example&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# generate hello world file&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  GENERATE
  OUTPUT &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CMAKE_CURRENT_BINARY_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;/hello.cpp
  CONTENT
    &lt;span class=&quot;s2&quot;&gt;&quot;#include &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; int main() { std::cout &amp;lt;&amp;lt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Hello World&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;lt;&amp;lt; std::endl; exit(0); }&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# search for clang-tidy&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;find_program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CLANG_TIDY_EXE NAMES &lt;span class=&quot;s2&quot;&gt;&quot;clang-tidy&quot;&lt;/span&gt; REQUIRED&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# setup clang-tidy command from executable + options&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;CLANG_TIDY_COMMAND &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CLANG_TIDY_EXE&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-checks=-*,modernize-*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# add target using generated source file&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;add_executable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;hello &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CMAKE_CURRENT_BINARY_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;/hello.cpp&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# set CXX_CLANG_TIDY property after defining the target&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set_target_properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;hello PROPERTIES CXX_CLANG_TIDY &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CLANG_TIDY_COMMAND&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run this with the usual cmake build steps:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;mkdir build &amp;amp;&amp;amp; cd build &amp;amp;&amp;amp; cmake .. &amp;amp;&amp;amp; make
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And you’ll see something like this:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;hello.cpp:2:6: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt; int main() { std::cout &amp;lt;&amp;lt; &quot;Hello World&quot; &amp;lt;&amp;lt; std::endl;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; ~~~ ^
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt; auto           -&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;int
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ll leave it up to you to decide whether the advice of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clang-tidy&lt;/code&gt; makes sense
in this particular case. Read &lt;a href=&quot;/blog/2022/01/28/cpp-trailing-return-types.html&quot;&gt;this article&lt;/a&gt; to learn more about C++ trailing return types.&lt;/p&gt;

&lt;p&gt;Hope this helps.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>SGP 2021 Virtual Field Trip Report</title>
   <link href="https://danielsieger.com/blog/2021/08/25/sgp-virtual-field-trip.html"/>
   <updated>2021-08-25T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/08/25/sgp-virtual-field-trip</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/sgp-2021/teaser.jpg&quot; alt=&quot;SGP teaser image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I attended this year’s &lt;a href=&quot;http://www.geometryprocessing.org&quot;&gt;Symposium on Geometry Processing (SGP)&lt;/a&gt;, one of the
premier conferences for publishing cutting-edge research in geometry processing.
Here is my brief resume.&lt;/p&gt;

&lt;p&gt;The conference was scheduled to take place in Toronto, Canada. However, due to
current circumstances, the conference was virtual only. In any case, the
organizers did an awesome job organizing a top notch conference and making it a
highly worthwhile experience.&lt;/p&gt;

&lt;p&gt;Positive side-effect of the virtual conference: All the graduate school
lectures, technical papers, and keynotes are &lt;a href=&quot;https://sgp2021.github.io/&quot;&gt;available online&lt;/a&gt;. Check
out the &lt;a href=&quot;https://sgp2021.github.io/program&quot;&gt;program&lt;/a&gt;, there’s a whole bunch of interesting lectures and
presentations. The graduate school lectures from previous years are &lt;a href=&quot;http://school.geometryprocessing.org&quot;&gt;archived
online&lt;/a&gt; as well.&lt;/p&gt;

&lt;h2 id=&quot;graduate-school-highlights&quot;&gt;Graduate School Highlights&lt;/h2&gt;

&lt;p&gt;The graduate school is one of the most valuable aspects of SGP. It enables
practitioners to stay up to date with the state of the art and to expand their
knowledge in concentrated manner.&lt;/p&gt;

&lt;p&gt;I particularly enjoyed the following lectures:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Maps Between Surfaces&lt;/em&gt; by Marcel Campen and Patrick Schmidt. Awesome
presentation, great content, very instructive. I learned a lot from it,
especially since this is a somewhat more recent area of research.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Shape Approximation and Applications&lt;/em&gt; by Tamy Boubekeur. A great overview
on shape approximation techniques, including a classification of different
methods and their development over time, as well as some recent research
highlights. Well done and entertaining presentation definitely worth watching.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Digital Geometry&lt;/em&gt; by David Coeurjolly and Jacques-Oliver Lachaud. Geometry
processing on voxel representations! Since I’m dealing a lot with voxel-based
modeling in my day job, this was of particular interest to me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;paper-highlights&quot;&gt;Paper Highlights&lt;/h2&gt;

&lt;p&gt;The main part of the conference were three packed days of technical paper
presentations. Quite a marathon! Zoom fatigue kicked in from time to time, but I
kept on watching (almost) all presentations.&lt;/p&gt;

&lt;h3 id=&quot;best-paper-awards&quot;&gt;Best Paper Awards&lt;/h3&gt;

&lt;p&gt;There were plenty of interesting papers, most notably those winning this year’s
best paper awards:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Surface Map Homology Inference&lt;/li&gt;
  &lt;li&gt;Geodesic Distance Computation via Virtual Source Propagation&lt;/li&gt;
  &lt;li&gt;Simulated Jet Engine Bracket Dataset&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;papers-of-interest&quot;&gt;Papers of Interest&lt;/h3&gt;

&lt;p&gt;Beyond the above, there were a couple of papers I found very interesting.
Without particular order:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Delaunay Meshing and Repairing of Defect-laden NURBS Models&lt;/li&gt;
  &lt;li&gt;Globally Injective Geometry Optimization with Non-Injective Steps&lt;/li&gt;
  &lt;li&gt;Simpler Quad Layouts using Relaxed Singularities&lt;/li&gt;
  &lt;li&gt;The Diamond Laplace for Polygonal and Polyhedral Meshes&lt;/li&gt;
  &lt;li&gt;Frame Field Operators&lt;/li&gt;
  &lt;li&gt;On Landmark Distances in Polygons&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;test-of-time-award&quot;&gt;Test of Time Award&lt;/h3&gt;

&lt;p&gt;This is a new type of award to recognize papers that have stood the test of
time, i.e., papers which are widely recognized throughout the community even
after more than ten years. Great idea to highlight research that really sticks
and has a long-lasting impact.&lt;/p&gt;

&lt;p&gt;This first iteration of the award went to &lt;a href=&quot;https://dx.doi.org/10.2312/SGP/SGP06/061-070&quot;&gt;Poisson Surface
Reconstruction&lt;/a&gt;. That’s certainly a
well deserved recognition. The method and the corresponding
&lt;a href=&quot;https://github.com/mkazhdan/PoissonRecon&quot;&gt;software&lt;/a&gt; has become the de-facto
standard for surface reconstruction.&lt;/p&gt;

&lt;h2 id=&quot;keynotes&quot;&gt;Keynotes&lt;/h2&gt;

&lt;p&gt;We had three keynote speakers, each offering their unique insights:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Bradley Rothenberg, CEO, nTopology: “Engineering-driven design: a new foundation”&lt;/li&gt;
  &lt;li&gt;Geoffrey Hinton, University of Toronto/Google Research: “How to represent part-whole hierarchies in a neural net”&lt;/li&gt;
  &lt;li&gt;Lining Yao, Carnegie Mellon University: “Computing Morphing Matter: the Marriage of Geometry and Hidden Forces”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the &lt;a href=&quot;https://sgp2021.github.io/program/#keynotes&quot;&gt;full descriptions&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;Enjoy the show!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Awesome Doxygen Style</title>
   <link href="https://danielsieger.com/blog/2021/07/07/awesome-doxygen-style.html"/>
   <updated>2021-07-07T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/07/07/awesome-doxygen-style</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.doxygen.org&quot;&gt;Doxygen&lt;/a&gt; is the de-facto standard tool for C++ API documentation. It comes with a whole bunch of useful features such as auto-generated API documentation from annotated sources or automatic cross-references.&lt;/p&gt;

&lt;p&gt;Unfortunately, the default Doxygen HTML output is quite dated, both in terms of visual style as well as navigation. Here’s an example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/awesome-doxygen/default-docs.jpg&quot; alt=&quot;Default Doxygen HTML output&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Especially on mobile devices the resulting pages are notoriously difficult to navigate&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id=&quot;customized-html&quot;&gt;Customized HTML&lt;/h2&gt;

&lt;p&gt;Since I was not really satisfied with the above, I did &lt;a href=&quot;/blog/2018/08/26/polishing-pmp-library-documentation.html&quot;&gt;some work&lt;/a&gt; to customize the output for our &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;mesh processing library&lt;/a&gt; to have a slightly more modern look and feel. The results looked like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/awesome-doxygen/pmp-docs.jpg&quot; alt=&quot;Customized Doxygen HTML output&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While this is arguably better than the default, it is far away from perfect.&lt;/p&gt;

&lt;h2 id=&quot;doxygen-awesome-css&quot;&gt;doxygen-awesome-css&lt;/h2&gt;

&lt;p&gt;I recently came across a project that takes Doxygen customization even further: the &lt;a href=&quot;https://github.com/jothepro/doxygen-awesome-css&quot;&gt;doxygen-awesome-css&lt;/a&gt; project developed by &lt;a href=&quot;https://github.com/jothepro&quot;&gt;@jothepro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some of the advantages are&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a modern look and feel&lt;/li&gt;
  &lt;li&gt;simple integration and customization&lt;/li&gt;
  &lt;li&gt;improved mobile usability&lt;/li&gt;
  &lt;li&gt;dark mode support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I immediately adopted it for &lt;a href=&quot;https://www.pmp-library.org/&quot;&gt;PMP&lt;/a&gt;. Here’s a snapshot:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/awesome-doxygen/pmp-awesome.jpg&quot; alt=&quot;Customized Doxygen HTML output&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Personally, I think this is indeed an awesome improvement.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;If you are looking for a more modern style for your Doxygen docs, just give &lt;a href=&quot;https://github.com/jothepro/doxygen-awesome-css&quot;&gt;doxygen-awesome-css&lt;/a&gt; a try. Installation is super easy, you basically only need to include the additional CSS files into your repository and tell Doxygen to use them through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTML_EXTRA_STYLESHEET&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href=&quot;https://jothepro.github.io/doxygen-awesome-css/&quot;&gt;project website&lt;/a&gt; for more details. Hope this helps.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;One might argue that mobile is not so important for API documentation. Fair enough. However, Doxygen can also used to build complete project websites including landing pages, tutorials, or high-level documentation. Therefore, accessibility on mobile is still an important aspect. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Digital Gardens. Seriously?</title>
   <link href="https://danielsieger.com/blog/2021/05/30/digital-gardens.html"/>
   <updated>2021-05-30T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/05/30/digital-gardens</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/digital-garden/teaser.jpg&quot; alt=&quot;Digitized wild garden from https://commons.wikimedia.org/wiki/File:Wild_garden2.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Some ideas take time to flourish. Maybe digital gardens are one of those ideas.
Is it just a hyped revival of the personal website or is there more to it?&lt;/p&gt;

&lt;h2 id=&quot;what-are-digital-gardens&quot;&gt;What Are Digital Gardens?&lt;/h2&gt;

&lt;p&gt;A digital garden is a digital space to cultivate your thoughts, ideas, notes,
and knowledge. Think of personal wikis and experimental knowledge bases. Digital
gardens are curated and evolve over time, sometimes growing wildly and sometimes
getting pruned.&lt;/p&gt;

&lt;p&gt;Digital gardens are less focused on publishing highly polished results but more
about the process of developing ideas, thoughts, and knowledge over time. Less
personal branding and search engine optimization but more personal growth and
development instead.&lt;/p&gt;

&lt;p&gt;Digital gardens are typically public so that others can learn from your current
knowledge and understanding and provide feedback at an early stage. They are a
prime example of working and &lt;a href=&quot;https://www.swyx.io/learn-in-public&quot;&gt;learning in
public&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;what-are-the-origins&quot;&gt;What Are the Origins?&lt;/h2&gt;

&lt;p&gt;Digital gardens are clearly reminiscent of the quirky personal websites of the
early web. Early roots of digital gardens can be traced back to Mark Bernstein’s
1998 essay &lt;a href=&quot;https://www.eastgate.com/garden/Enter.html&quot;&gt;Hypertext Gardens&lt;/a&gt;. Of course personal websites
continue to exist today (hello &lt;a href=&quot;https://neocities.org/&quot;&gt;https://neocities.org/&lt;/a&gt;), but they got largely
superseded by blogs and social media, as Amy Hoy argues in &lt;a href=&quot;https://stackingthebricks.com/how-blogs-broke-the-web/&quot;&gt;How the Blog Broke
the Internet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In 2015, Mike Caulfield refined the metaphor of a garden further in his article
&lt;a href=&quot;https://hapgood.us/2015/10/17/the-garden-and-the-stream-a-technopastoral&quot;&gt;The Garden and the Stream&lt;/a&gt;. In his analogy, the &lt;em&gt;stream&lt;/em&gt; is the
short-lived linear content like your blog or social media time-line whereas the
&lt;em&gt;garden&lt;/em&gt; is for content of a more durable nature with more complex relations in
between. He traces the original idea of a garden back to Vannevar Bush’s 1945
(!) visionary essay &lt;a href=&quot;https://www.theatlantic.com/magazine/archive/1945/07/as-we-may-think/303881/&quot;&gt;As We May Think&lt;/a&gt; (read it, it’s a total blast).&lt;/p&gt;

&lt;p&gt;The idea of a digital garden recently gained more and more traction. Two
frequently cited examples are John Critchlow’s &lt;a href=&quot;https://tomcritchlow.com/2018/10/10/of-gardens-and-wikis/&quot;&gt;Of Digital Streams, Campfires
and Gardens&lt;/a&gt; and Joel Hook’s &lt;a href=&quot;https://joelhooks.com/digital-garden&quot;&gt;My blog is a digital garden, not a
blog&lt;/a&gt;. Maggie Appleton’s &lt;a href=&quot;https://maggieappleton.com/garden-history&quot;&gt;A Brief History &amp;amp; Ethos of the Digital
Garden&lt;/a&gt; provides a more in-depth introduction for those who are
curious to learn more.&lt;/p&gt;

&lt;h2 id=&quot;are-they-any-good&quot;&gt;Are They Any Good?&lt;/h2&gt;

&lt;p&gt;In short: yes, absolutely! I think it’s an idea worth exploring.&lt;/p&gt;

&lt;p&gt;It’s amazing that more and more people think about alternatives to the
one-size-fits-all streamlined silos of InstaTwitBook. Digital gardens stimulate
the idea to create personalized content that is built to last and independent of
locked-down third-party platforms. The &lt;a href=&quot;https://indieweb.org/&quot;&gt;IndieWeb
community&lt;/a&gt; deserves a mention here as well.&lt;/p&gt;

&lt;p&gt;One of the most interesting aspects is the idea of non-performative writing,
thinking, and learning in public. This allows you to get your ideas out there
early and refine them over time. It lowers the friction to start writing, and
reduces the fear of being judged. We are all learners. Anyone having the courage
to share his knowledge with the rest of the world deserves respect.&lt;/p&gt;

&lt;p&gt;Of course, there’s a flip side to that approach as well, and that’s false
information. The raw material inevitably contains factual errors. This can,
however, be mitigated to some extent by indicating the maturity and reliability
of the content. Maggie Appleton keeps up the gardening metaphor and categorizes
her content as &lt;em&gt;seedling&lt;/em&gt; (rough ideas), &lt;em&gt;budding&lt;/em&gt; (somewhat cleaned up), or
&lt;em&gt;evergreen&lt;/em&gt; (fairly mature). Sounds like a fine solution to me. After all, it’s
up to you to always question the reliability of information you find online.&lt;/p&gt;

&lt;h2 id=&quot;just-a-hype&quot;&gt;Just a Hype?&lt;/h2&gt;

&lt;p&gt;Closing the loop to my initial question: Is it just a hype or re-branding of the
good old personal website?&lt;/p&gt;

&lt;p&gt;Yes. And No.&lt;/p&gt;

&lt;p&gt;Digital gardens clearly continue the tradition of personal websites, wikis, and
knowledge bases.&lt;/p&gt;

&lt;p&gt;But then, there’s more to it.&lt;/p&gt;

&lt;p&gt;The metaphor itself already fosters a different way of thinking. The aspect of
working and learning in public adds a whole new dimension. Longevity, continuous
growth and evolution are key characteristics. The connections and relations
between different pieces of information get a completely new significance.&lt;/p&gt;

&lt;p&gt;And then there’s technical evolution.&lt;/p&gt;

&lt;p&gt;People are constantly exploring new
&lt;a href=&quot;https://github.com/MaggieAppleton/digital-gardeners&quot;&gt;tools&lt;/a&gt; to better support
this style of working. Especially bi-directional linking between pages seems to
emerge as a key technology. Interactive visualizations enable completely novel
ways to explore these relations. And then there is the question how to bridge
the boundaries of individual gardens.&lt;/p&gt;

&lt;h2 id=&quot;get-your-hands-dirty&quot;&gt;Get Your Hands Dirty?&lt;/h2&gt;

&lt;p&gt;Now, should you grow a digital garden?&lt;/p&gt;

&lt;p&gt;I can only offer my perspective: I’ve been tinkering with different approaches
to capture personal knowledge for quite some time. The simple linear nature of a
blog never really cut it for me. Therefore, I integrated a simple workflow to
capture notes and ideas directly into my website. It’s based on Jekyll and plain
Markdown and serves me quite well. You might call this a digital garden, it’s
just not a public one for the moment.&lt;/p&gt;

&lt;p&gt;Maybe it’s time to rethink a few things.&lt;/p&gt;

&lt;h2 id=&quot;references-and-further-reading&quot;&gt;References and Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://hapgood.us/2015/10/17/the-garden-and-the-stream-a-technopastoral&quot;&gt;The Garden and the Stream: A Technopastoral&lt;/a&gt; by Mike Caulfield&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tomcritchlow.com/2018/10/10/of-gardens-and-wikis/&quot;&gt;Of Digital Streams, Campfires and Gardens&lt;/a&gt; by Tom Critchlow&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tomcritchlow.com/2019/02/17/building-digital-garden/&quot;&gt;Building a Digital Garden&lt;/a&gt; by Tom Critchlow&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://joelhooks.com/digital-garden&quot;&gt;My blog is a digital garden, not a blog&lt;/a&gt; by Joel Hook&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackingthebricks.com/how-blogs-broke-the-web/&quot;&gt;How the Blog Broke the Internet&lt;/a&gt; by Amy Hoy&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://maggieappleton.com/garden-history&quot;&gt;A Brief History &amp;amp; Ethos of the Digital Garden&lt;/a&gt; by Maggie Appleton&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.swyx.io/digital-garden-tos/&quot;&gt;Digital Garden Terms of Service&lt;/a&gt; by Shawn Wang&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.swyx.io/learn-in-public&quot;&gt;Learn In Public&lt;/a&gt; by Shawn Wang&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.theatlantic.com/magazine/archive/1945/07/as-we-may-think/303881/&quot;&gt;As We May Think&lt;/a&gt; by Vannevar Bush&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/DigitalGardens/&quot;&gt;DigitalGardens&lt;/a&gt; on reddit&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/MaggieAppleton/digital-gardeners&quot;&gt;Digital Gardening&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>A Minimalist Jekyll Style Guide</title>
   <link href="https://danielsieger.com/blog/2021/05/26/minimalist-jekyll-style-guide.html"/>
   <updated>2021-05-26T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/05/26/minimalist-jekyll-style-guide</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;You cannot get a simple system by adding simplicity to a complex system. - &lt;a href=&quot;https://erlang.org/pipermail/erlang-questions/2012-March/065087.html&quot;&gt;Richard O’Keefe&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a style guide for clean and lean Jekyll websites. Its primary goal is to
foster simplicity, performance, and maintainability. The contained guidelines
are highly opinionated, totally biased, and somewhat radical. Nevertheless, I
hope you’ll find some useful bits and pieces.&lt;/p&gt;

&lt;h2 id=&quot;no-external-dependencies&quot;&gt;No External Dependencies&lt;/h2&gt;

&lt;p&gt;Don’t depend on external services or content delivery networks (CDNs). Bundle
all resources locally so that you can still build, develop, and use your website
while being offline.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;performance&lt;/li&gt;
  &lt;li&gt;offline use&lt;/li&gt;
  &lt;li&gt;data privacy&lt;/li&gt;
  &lt;li&gt;version control&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;no-css-frameworks&quot;&gt;No CSS Frameworks&lt;/h2&gt;

&lt;p&gt;Modern &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout&quot;&gt;CSS Grid
Layout&lt;/a&gt; and
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox&quot;&gt;Flexbox&lt;/a&gt;
are powerful enough to create highly usable and responsive layouts with a few
lines of code. No need to rely on heavy frameworks such as Bootstrap.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
  &lt;li&gt;performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;no-javascript&quot;&gt;No JavaScript&lt;/h2&gt;

&lt;p&gt;A website as simple as mine does not really need JavaScript. Yours maybe
neither. Less code to maintain, less to transfer over the wire. In addition, the
site remains accessible for users with JavaScript disabled.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
  &lt;li&gt;performance&lt;/li&gt;
  &lt;li&gt;accessibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exception: MathJax for typesetting math. Only include it when you need it, see
&lt;a href=&quot;/blog/2020/12/14/jekyll-website-performance-improvement.html&quot;&gt;this post&lt;/a&gt;
for details. I’m not happy with this exception, but I don’t see an alternative
for the moment.&lt;/p&gt;

&lt;h2 id=&quot;no-tracking&quot;&gt;No Tracking&lt;/h2&gt;

&lt;p&gt;I had to remind myself why I’m writing this blog at all: First and foremost, I
write for myself. For the pleasure of writing, to keep notes and to structure
thoughts. If any of this turns out to be useful for others, great, glad I could
help. No need to spy on my visitors.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;data privacy&lt;/li&gt;
  &lt;li&gt;performance&lt;/li&gt;
  &lt;li&gt;peace of mind&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;no-comments&quot;&gt;No Comments&lt;/h2&gt;

&lt;p&gt;Let’s face it: Static site generators are simply not made for this. Sure, there
are workarounds, I used to use one myself, but they are hackish at best and
typically rely on some external service. Feedback via
&lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;e-mail&lt;/a&gt; is fully sufficient.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
  &lt;li&gt;maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;rss-over-e-mail-subscription&quot;&gt;RSS over E-Mail Subscription&lt;/h2&gt;

&lt;p&gt;Provide an &lt;a href=&quot;https://en.wikipedia.org/wiki/RSS&quot;&gt;RSS feed&lt;/a&gt; to allow users to get
notified of new posts. Let your website be part of a better web that doesn’t
constantly ask for e-mail addresses or personal information.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;data privacy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;no-favicons&quot;&gt;No Favicons&lt;/h2&gt;

&lt;p&gt;I simply refuse to give in to the craziness today’s favicons. This used to be a
single, simple, small image file added to your website. Nowadays, you are
supposed to generate half a dozen images at different resolutions and formats
plus some obscure, non-standard XML and text files. In addition, you need to
include half a dozen &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;link&amp;gt;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tags in your HTML header to make
those work. Heck, you need an external service to generate all this cruft for
you. Just stop it.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
  &lt;li&gt;maintainability&lt;/li&gt;
  &lt;li&gt;peace of mind&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;no-pre-built-theme&quot;&gt;No Pre-Built Theme&lt;/h2&gt;

&lt;p&gt;Jekyll themes are great to get you started, but most of them come with a &lt;em&gt;lot&lt;/em&gt;
of boilerplate code. Ironically, some of the most bloated ones carry the word
“minimal” in their name. It’s in the nature of a theme to provide a highly
generic solution. Instead, build your own site from scratch. Only include what
you need and understand.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;performance&lt;/li&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
  &lt;li&gt;maintainability&lt;/li&gt;
  &lt;li&gt;learning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hint: set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theme: null&lt;/code&gt; in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt; to avoid generating default CSS
styles.&lt;/p&gt;

&lt;h2 id=&quot;no-web-fonts&quot;&gt;No Web Fonts&lt;/h2&gt;

&lt;p&gt;This is the hardest part for me. I’m a confessing typophile, and I just &lt;em&gt;adore&lt;/em&gt;
a beautiful and well-crafted typeface. I used to waste a lot of time switching
back and forth between different fonts and tweaking their settings. Enough of
that. The performance impact is non-negligible, and so is the implementation and
maintenance burden. Therefore, I finally settled with a simple system font
stack.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;performance&lt;/li&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
  &lt;li&gt;productivity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;plain-markdown&quot;&gt;Plain Markdown&lt;/h2&gt;

&lt;p&gt;Use plain Markdown whenever possible. No inline HTML or Liquid language in blog
posts. This ensures your content can easily be converted to another format if
needed. Use a linting tool to check your Markdown files.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;minimal-liquid-code&quot;&gt;Minimal Liquid Code&lt;/h2&gt;

&lt;p&gt;Keep Liquid code to a bare minimum. It’s tempting to add more and more features
with a few lines of code, but it only gets harder to maintain over time.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
  &lt;li&gt;maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;minimal-plugins&quot;&gt;Minimal Plugins&lt;/h2&gt;

&lt;p&gt;I use GitHub Pages, so I’m restricted to the officially supported plugins. I
keep it down to a few essential ones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;jekyll-feed&lt;/li&gt;
  &lt;li&gt;jekyll-seo-tag&lt;/li&gt;
  &lt;li&gt;jekyll-sitemap&lt;/li&gt;
  &lt;li&gt;jekyll-redirect-from&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;no-syntax-highlighting&quot;&gt;No Syntax Highlighting&lt;/h2&gt;

&lt;p&gt;Sounds crazy, but in fact many syntax highlighting color schemes are more than
sub-optimal in terms of accessibility. Think of bad contrast ratios and
color-blindness. Choose whatever you like in your IDE, but I’ll keep it plain
and simple on my site. Bonus points: No superfluous CSS required. No excessive
DOM size due to the huge amount of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements being generated by the
Jekyll default syntax highlighter.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;accessibility&lt;/li&gt;
  &lt;li&gt;performance&lt;/li&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hint: Disable syntax highlighting in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;kramdown&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;syntax_highlighter_opts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;disable&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;no-responsive-images&quot;&gt;No Responsive Images&lt;/h2&gt;

&lt;p&gt;Generating and serving responsive images is sort of a science on its own. You
eventually end up generating a dozen files in different resolutions, versions,
and file formats. This is certainly doable using additional plugins, custom
Liquid code, or external web services. However, none of those approaches is
simple and all of them violate some other guideline above. Therefore, I stick to
simple compressed and optimized JPEG images for the moment.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;simplicity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;no-embedded-videos&quot;&gt;No Embedded Videos&lt;/h2&gt;

&lt;p&gt;Embedding videos from external sources is convenient but comes with a cost: Lots
of JavaScript and CSS gets pulled from an external domain. In addition, this
approach can be problematic in terms of data privacy (cookies, tracking). Also
requires inline HTML or custom Liquid as well as additional CSS for embedding.
For now, I just use a good old link with an optional image.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;performance&lt;/li&gt;
  &lt;li&gt;data privacy&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;closing-remarks&quot;&gt;Closing Remarks&lt;/h2&gt;

&lt;p&gt;Obviously, these guidelines are not for everyone and not for every situation.
That being said, I still hope I got you thinking about wether all the bells and
whistles on your website are really worth it.&lt;/p&gt;

&lt;p&gt;Finally, I’m curious how long it’ll take before I break one of the rules.
&lt;a href=&quot;/atom.xml&quot;&gt;Subscribe via RSS&lt;/a&gt; and check the next post for fancy web fonts. ;-)&lt;/p&gt;

&lt;p&gt;In the meantime, here’s some food for thought:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://idlewords.com/talks/website_obesity.htm&quot;&gt;The Website Obesity Crisis - Maciej Cegłowski&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://macwright.com/2016/05/03/the-featherweight-website.html&quot;&gt;This page weighs 15kb - Tom MacWright&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tonsky.me/blog/disenchantment/&quot;&gt;Software disenchantment - Nikita Tonsky&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://kokorobot.ca/site/leaner_web.html&quot;&gt;leanerweb - Rek Bellum&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.boia.org/wcag-2.1-a/aa-principles-and-checkpoints&quot;&gt;WCAG 2.1 A/AA Principles and Checkpoints&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Generating Primitive Shapes in C++</title>
   <link href="https://danielsieger.com/blog/2021/05/03/generating-primitive-shapes.html"/>
   <updated>2021-05-03T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/05/03/generating-primitive-shapes</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/generating-primitives/teaser.jpg&quot; alt=&quot;Primitive shapes in front of blurry code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is the last part of my brief series on procedural mesh generation of simple
shapes in C++. The two previous articles covered generating &lt;a href=&quot;/blog/2021/01/03/generating-platonic-solids.html&quot;&gt;Platonic
solids&lt;/a&gt; and different types of &lt;a href=&quot;/blog/2021/03/27/generating-spheres.html&quot;&gt;spheres&lt;/a&gt;. I recommend reading
the other articles first, especially if you want to try out the code yourself.&lt;/p&gt;

&lt;p&gt;This part covers the following primitives:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Plane&lt;/li&gt;
  &lt;li&gt;Cone&lt;/li&gt;
  &lt;li&gt;Cylinder&lt;/li&gt;
  &lt;li&gt;Torus&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As with the previous articles, the code is in C++, using the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt; library,
and written with a focus on simplicity. I only expose a minimal set of options
and don’t really optimize for performance. However, you can easily extend the
code to control additional properties such as position, size, and orientation.&lt;/p&gt;

&lt;h2 id=&quot;the-plane&quot;&gt;The Plane&lt;/h2&gt;

&lt;p&gt;Let’s start with the simplest shape, the plane. In the most trivial case, this is
just single quad with four vertices lying in the plane:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;plane&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// add vertices in x-y plane&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// add face&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While the above is fine for basic applications, you typically want to be able to
refine the mesh into smaller elements, such as shown in the sequence below.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-primitives/plane_refinement.jpg&quot; alt=&quot;Uniform refinement of a planar mesh&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Generating such a regular grid isn’t that much more complicated. All you need is
two nested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loops to generate vertices and faces. For the sake of
simplicity, I fix the resolution to be the same in each direction.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;plane&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// generate vertices&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// generate faces&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you’re curious to experiment with the code, go ahead and de-couple the
resolution for the different plane directions, or add options for position,
size, and orientation.&lt;/p&gt;

&lt;h2 id=&quot;the-cone&quot;&gt;The Cone&lt;/h2&gt;

&lt;p&gt;Next, let’s have a look at a slightly more complex shape, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cone&quot;&gt;cone&lt;/a&gt;. A
cone basically consists of a circular base connected to a single tip or
&lt;a href=&quot;https://en.wikipedia.org/wiki/Apex_(geometry)&quot;&gt;apex&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-primitives/cone_refinement.jpg&quot; alt=&quot;Meshes of a cone in different resolutions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The coarsest approximation to a cone is a tetrahedron (the leftmost image
above), which you already saw in the tutorial about &lt;a href=&quot;/blog/2021/01/03/generating-platonic-solids.html&quot;&gt;Platonic solids&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code for generating a cone follows the same pattern that you are familiar
with by now: Generate vertices first and then connect the faces.&lt;/p&gt;

&lt;p&gt;For generating vertices, I sample a circle in the &lt;em&gt;x-y&lt;/em&gt; plane, controlled by
parameters for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolution&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;radius&lt;/code&gt;. I offset the tip vertex in &lt;em&gt;z&lt;/em&gt;
direction by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;height&lt;/code&gt; and add it last.&lt;/p&gt;

&lt;p&gt;Adding faces is as simple as connecting two consecutive vertices from the base
circle to the tip vertex. Finally, I add a single polygonal face to close the
bottom of the cone.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add vertices subdividing a circle&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ratio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ratio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;M_PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;base_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add the tip of the cone&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// generate triangular faces&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// reverse order for consistent face orientation&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add polygonal base face&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_face&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-cylinder&quot;&gt;The Cylinder&lt;/h2&gt;

&lt;p&gt;Next, let’s have a look at cylinders which are barely more complicated than
cones. To be more precise, I consider discrete approximations to a cylinder
which are &lt;a href=&quot;https://en.wikipedia.org/wiki/Prism_(geometry)&quot;&gt;prisms&lt;/a&gt;, i.e., &lt;em&gt;n&lt;/em&gt;-sided polygonal base faces parallel to each
other connected by &lt;em&gt;n&lt;/em&gt; other quadrilateral faces joining the two base faces.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-primitives/cylinder_refinement.jpg&quot; alt=&quot;Meshes of a cylinder in different resolutions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Generating a cylinder is very similar to generating a cone as described above.
The major difference is that I sample two different base circles and generate
quadrilateral faces connecting pairs of vertices from those two circles.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cylinder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                     &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                     &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// generate vertices&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bottom_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;top_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ratio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ratio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;M_PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bottom_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;top_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add faces around the cylinder&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ll&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ii&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add top polygon&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_face&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;top_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// reverse order for consistent face orientation&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottom_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bottom_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add bottom polygon&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_face&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottom_vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-torus&quot;&gt;The Torus&lt;/h2&gt;

&lt;p&gt;The final shape I’ll describe in this tutorial is the well-known &lt;a href=&quot;https://en.wikipedia.org/wiki/Torus&quot;&gt;torus&lt;/a&gt;
or doughnut shape. A torus is generated by revolving a circle in
three-dimensional space about an axis that is coplanar with a circle.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-primitives/torus_refinement.jpg&quot; alt=&quot;Meshes of a torus in different resolutions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The code pattern remains the same: Vertex generation comes first, then add the
corresponding faces. The indexing of the faces gets a bit more tricky due to the
nested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; loops, but that’s basically about it. I use some intermediate
variables to make the code clearer, hope this helps.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;torus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radial_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thickness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// generate vertices&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radial_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;M_PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radial_resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;M_PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thickness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thickness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thickness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add quad faces&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radial_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i_next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radial_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j_next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j_next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i_next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j_next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i_next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tubular_resolution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;closing-remarks&quot;&gt;Closing Remarks&lt;/h2&gt;

&lt;p&gt;This finishes my brief series on procedural mesh generation of simple shapes.
Together with &lt;a href=&quot;/blog/2021/01/03/generating-platonic-solids.html&quot;&gt;part I&lt;/a&gt; and &lt;a href=&quot;/blog/2021/03/27/generating-spheres.html&quot;&gt;part II&lt;/a&gt; this should provide you
with a solid basis for creating simple shapes in a modeling application or to
test an algorithm against shapes with known properties.&lt;/p&gt;

&lt;p&gt;The complete &lt;a href=&quot;/download/MyViewer_generating_primitives.cpp&quot;&gt;code&lt;/a&gt; is available
as well. In order to try it out, just copy the file to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/MyViewer.cpp&lt;/code&gt; in the
PMP &lt;a href=&quot;https://github.com/pmp-library/pmp-template&quot;&gt;project template&lt;/a&gt;, build the project, and run the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./myviewer&lt;/code&gt; executable.&lt;/p&gt;

&lt;p&gt;Comments or questions? Simply drop me a &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;mail&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Check for Broken Links in Jekyll</title>
   <link href="https://danielsieger.com/blog/2021/03/28/check-broken-links-jekyll.html"/>
   <updated>2021-03-28T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/03/28/check-broken-links-jekyll</id>
   <content type="html">&lt;p&gt;You know the frustrating experience: There you are, reading an interesting
article, you click on that promising link… and all you get is a 404 page.&lt;/p&gt;

&lt;p&gt;If you are lucky, that is.&lt;/p&gt;

&lt;p&gt;Let’s try to do better than that. Fixing dead links will not only delight your
esteemed readers but also make search engine crawlers happy. Here’s a simple way
to check for broken links in your Jekyll-based website.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/gjtorikian/html-proofer&quot;&gt;html-proofer&lt;/a&gt; Ruby gem is a tool to check the validity of your HTML output.
Among other things, it checks for broken links, both internal and external.&lt;/p&gt;

&lt;p&gt;Installation is quick and easy:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem &quot;html-proofer&quot;&lt;/code&gt; to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle install&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run the tool on your Jekyll build directory:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;bundle exec htmlproofer --assume_extension &apos;.html&apos; ./_site
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--assume_extension&lt;/code&gt; option automatically adds extensions to file paths, as
this is used by extension-less URLs in Jekyll 3 and GitHub pages.&lt;/p&gt;

&lt;p&gt;See the HTMLProofer &lt;a href=&quot;https://github.com/gjtorikian/html-proofer/blob/main/README.md&quot;&gt;README&lt;/a&gt; for more details and options. In my case, I
added the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--http_status_ignore=999&lt;/code&gt; option to filter some external links
returning that particular error when not using a regular browser.&lt;/p&gt;

&lt;p&gt;You can use the Ruby-based task automation tool &lt;a href=&quot;https://en.wikipedia.org/wiki/Rake_(software)&quot;&gt;Rake&lt;/a&gt; to further automate
the process. Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem &quot;rake&quot;&lt;/code&gt; to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle install&lt;/code&gt; again
to install it. Then create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;html-proofer&apos;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bundle exec jekyll build&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:assume_extension&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.html&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;HTMLProofer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;check_directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;_site/&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you can simply run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle exec rake test&lt;/code&gt; to check your HTML files.&lt;/p&gt;

&lt;p&gt;Depending on your setup, you could also integrate this into your build pipeline
to run the test automatically, e.g., when you push new changes or regularly
during a nightly build.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Generating Meshes of a Sphere</title>
   <link href="https://danielsieger.com/blog/2021/03/27/generating-spheres.html"/>
   <updated>2021-03-27T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/03/27/generating-spheres</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/generating-spheres/teaser.jpg&quot; alt=&quot;Spheres in front of blurry C++ code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Spheres are one of the most basic geometric shapes we can think of. However,
there are a variety of methods for generating surface meshes of a sphere. In
this brief tutorial, I will describe four of them:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;UV sphere&lt;/li&gt;
  &lt;li&gt;Icosphere&lt;/li&gt;
  &lt;li&gt;Quad sphere&lt;/li&gt;
  &lt;li&gt;Goldberg polyhedra&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article is a follow-up on my previous tutorial on &lt;a href=&quot;/blog/2021/01/03/generating-platonic-solids.html&quot;&gt;generating Platonic
solids&lt;/a&gt;. I recommend reading it first since I will re-use parts of the
code from that article. The code is in C++ and using the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt; library. Use
the PMP &lt;a href=&quot;https://github.com/pmp-library/pmp-template&quot;&gt;project template&lt;/a&gt; for ease of implementation and
visualization.&lt;/p&gt;

&lt;h2 id=&quot;the-uv-sphere&quot;&gt;The UV Sphere&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-spheres/uv_sphere_refinement.jpg&quot; alt=&quot;Different refinement levels of the UV sphere&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The UV sphere is a standard shape available in many 3D modeling tools such as
Blender. The basic approach is to tessellate the sphere along meridians and
parallels, i.e., lines from one pole to another and lines parallel to the
equator. The resulting mesh contains a fan of triangles around the poles and
quadrilateral elements everywhere else.&lt;/p&gt;

&lt;p&gt;The code below is rather straightforward. I first add all vertices and then add
the corresponding triangular and quadrilateral faces. Note that I intentionally
did not optimize the code in any way for the purpose of this article.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;uv_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_stacks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add top vertex&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// generate vertices per stack / slice&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_stacks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;M_PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_stacks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;M_PI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add bottom vertex&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add top / bottom triangles&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_stacks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_stacks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add quads per stack / slice&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_stacks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_slices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-icosphere&quot;&gt;The Icosphere&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-spheres/icosphere_refinement.jpg&quot; alt=&quot;Different refinement levels of the icosphere&quot; /&gt;&lt;/p&gt;

&lt;p&gt;An alternative to the classic UV sphere is the icosphere. The core idea here is
to iteratively subdivide an icosahedron. In contrast to the UV sphere, the
resulting mesh is a pure triangle mesh and has a much more regular vertex
distribution and element size.&lt;/p&gt;

&lt;p&gt;Generating an icosphere basically requires three steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Generate an initial icosahedron&lt;/li&gt;
  &lt;li&gt;Subdivide the triangles&lt;/li&gt;
  &lt;li&gt;Project the vertices to the sphere&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I already covered steps #1 and #3 in my &lt;a href=&quot;/blog/2021/01/03/generating-platonic-solids.html&quot;&gt;previous article&lt;/a&gt;. We can
directly re-use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icosahedron()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;project_to_unit_sphere()&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;The only missing piece is a way to subdivide the triangles of the initial
icosahedron. In this implementation, I’m using the Loop subdivision function
available in &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;PMP&lt;/a&gt;. See the &lt;a href=&quot;https://www.pmp-library.org/group__algorithms.html&quot;&gt;reference docs&lt;/a&gt; and the Wikipedia
&lt;a href=&quot;https://en.wikipedia.org/wiki/Loop_subdivision_surface&quot;&gt;article&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;The resulting code is straightforward:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;icosphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_subdivisions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;icosahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceSubdivision&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subdivision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_subdivisions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;subdivision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;project_to_unit_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Bonus task: Try implementing the Loop subdivision step yourself! The algorithm
is rather straightforward and provides a excellent opportunity to exercise your
skills to work with meshes. If you get stuck, you can always check the
implementation provided in PMP.&lt;/p&gt;

&lt;h2 id=&quot;the-quad-sphere&quot;&gt;The Quad Sphere&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-spheres/quad_sphere_refinement.jpg&quot; alt=&quot;Different refinement levels of the quad sphere&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The quad sphere is another standard shape available in many 3D modeling tools.
The algorithm to generate a quad sphere iteratively subdivides an initial
hexahedron. As the name implies, the resulting mesh is a pure quad mesh.&lt;/p&gt;

&lt;p&gt;The code is quite similar to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icosphere()&lt;/code&gt; function above: I start by
generating a hexahedron and then use a subdivision function to refine the mesh.
As before, I project the points back to the unit sphere during each iteration to
get a nicely regularized shape.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;quad_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_subdivisions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hexahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceSubdivision&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subdivision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_subdivisions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;subdivision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;catmull_clark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;project_to_unit_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I already introduced the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hexahedron()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;project_to_unit_sphere()&lt;/code&gt;
functions &lt;a href=&quot;/blog/2021/01/03/generating-platonic-solids.html&quot;&gt;before&lt;/a&gt;. However, since I’m dealing with a quad mesh here, I
need something different for the subdivision step. The algorithm of choice is
Catmull-Clark subdivision, a very well known technique in computer graphics. See
the &lt;a href=&quot;https://www.pmp-library.org/group__algorithms.html&quot;&gt;PMP reference docs&lt;/a&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface&quot;&gt;Wikipedia article&lt;/a&gt;
for more information.&lt;/p&gt;

&lt;h2 id=&quot;goldberg-polyhedra&quot;&gt;Goldberg Polyhedra&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-spheres/goldberg_polyhedra.jpg&quot; alt=&quot;Different Goldberg polyhedra&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can generate yet another type of sphere mesh simply by re-using another
function already introduced in the &lt;a href=&quot;/blog/2021/01/03/generating-platonic-solids.html&quot;&gt;previous article&lt;/a&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dual()&lt;/code&gt;
function computes the dual polyhedron of a mesh. Applying this function to the
icosphere meshes yields polygonal meshes as shown above, also known as &lt;a href=&quot;https://en.wikipedia.org/wiki/Goldberg_polyhedron&quot;&gt;Goldberg
polyhedra&lt;/a&gt;. The resulting meshes contain only hexagonal and
pentagonal faces.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;That’s all for today. I said it would be a brief article, and so it is. Hope
this was useful anyway. The full
&lt;a href=&quot;/download/MyViewer_generating_spheres.cpp&quot;&gt;code&lt;/a&gt; is available to experiment
with as well.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Generating Platonic Solids in C++</title>
   <link href="https://danielsieger.com/blog/2021/01/03/generating-platonic-solids.html"/>
   <updated>2021-01-03T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2021/01/03/generating-platonic-solids</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/generating-platonics/teaser.jpg&quot; alt=&quot;Platonic solids in front of blurry C++ code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is a short tutorial on generating polygonal surface meshes of the five
&lt;a href=&quot;https://en.wikipedia.org/wiki/Platonic_solid&quot;&gt;Platonic solids&lt;/a&gt; in C++. You can learn a few basics of working with
meshes along the way. I’m using the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;Polygon Mesh Processing Library&lt;/a&gt; for
implementation. The code is straightforward, so you can easily adapt it to
another data structure or programming language.&lt;/p&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;My primary motivation for this article is very simple:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You want to generate a mesh of a Platonic solid&lt;/li&gt;
  &lt;li&gt;Here is some straightforward C++ code to do so&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now why exactly would this be interesting? Well, having the possibility to
generate a mesh with known properties is useful in many situations. Here are
three examples:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Generating example data for an algorithm you are developing&lt;/li&gt;
  &lt;li&gt;Generating shapes in your application without shipping meshes&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2018/09/11/unit-testing-geometric-algorithms.html&quot;&gt;Unit testing geometric algorithms&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Generating simple shapes also is a canonical example for doing your first steps
using a mesh library, a sort of “Hello, mesh!”. If you are new to working with
meshes, this is a great starting point to get familiar with the basics.&lt;/p&gt;

&lt;h2 id=&quot;bootstrapping&quot;&gt;Bootstrapping&lt;/h2&gt;

&lt;p&gt;I’m using the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;Polygon Mesh Processing Library&lt;/a&gt; (PMP) as mesh data
structure in this tutorial. However, any modern mesh data structure providing
basic functions such as adding vertices and polygonal faces should be sufficient
for this tutorial. Skip this section if you’re using another data structure.&lt;/p&gt;

&lt;p&gt;If you want to quickly visualize the resulting meshes, I recommend downloading
and compiling the PMP &lt;a href=&quot;https://github.com/pmp-library/pmp-template&quot;&gt;project template&lt;/a&gt;, which contains a
ready-to-use mesh viewer. Just clone the repository:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;git clone --recursive https://github.com/pmp-library/pmp-template.git
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Build the project:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;cd pmp-template &amp;amp;&amp;amp; mkdir build &amp;amp;&amp;amp; cd build &amp;amp;&amp;amp; cmake .. &amp;amp;&amp;amp; make
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run the viewer:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;./myviewer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;During this tutorial, I’ll define a few functions to generate the different
shapes. It’s easiest to add those functions to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyViewer&lt;/code&gt; class and call
them on a keyboard shortcut. Here’s how to do this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Find the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyViewer::keyboard()&lt;/code&gt; function in your favorite IDE&lt;/li&gt;
  &lt;li&gt;Add a new case label such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GLFW_KEY_G&lt;/code&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; statement&lt;/li&gt;
  &lt;li&gt;Add the function you want to call&lt;/li&gt;
  &lt;li&gt;Add a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update_mesh()&lt;/code&gt; to update the viewer&lt;/li&gt;
  &lt;li&gt;Re-compile and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./myviewer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all you need to get started, so let’s go!&lt;/p&gt;

&lt;h2 id=&quot;the-five-platonic-solids&quot;&gt;The Five Platonic Solids&lt;/h2&gt;

&lt;p&gt;The Platonic solids are a set of well-known convex &lt;a href=&quot;https://en.wikipedia.org/wiki/Polyhedron&quot;&gt;polyhedra&lt;/a&gt; with
particular properties, e.g., all faces are of the same type, the faces are
regular (all angles and sides are the same), and the same number of faces are
incident to each vertex. In 3D space, there are only five polyhedra satisfying
these criteria: The tetrahedron, hexahedron, octahedron, dodecahedron, and the
icosahedron. Here they are, from left to right:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-platonics/platonic_solids.jpg&quot; alt=&quot;The five Platonic solids&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The Platonic solids date back to the time of the ancient Greeks, if not earlier.
They played a key role in Plato’s philosophy, hence the name. If you are
interested, see the Wikipedia &lt;a href=&quot;https://en.wikipedia.org/wiki/Platonic_solid&quot;&gt;article&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2 id=&quot;the-tetrahedron&quot;&gt;The Tetrahedron&lt;/h2&gt;

&lt;p&gt;Let’s begin with the simplest Platonic solid, the tetrahedron. Four vertices and
four triangular faces, that’s all. Here’s the code:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tetrahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// choose coordinates on the unit sphere&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;8.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;9.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;9.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add the 4 vertices&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add the 4 faces&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-hexahedron&quot;&gt;The Hexahedron&lt;/h2&gt;

&lt;p&gt;The code for the hexahedron isn’t that much more complicated. You just have to
add a few more points and faces: Eight vertices, six quadrilateral faces:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hexahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// choose coordinates on the unit sphere&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add the 8 vertices&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add the 6 faces&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_quad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The next shape in the series is the octahedron. You could do exactly the same as
above and manually specify all vertex coordinates and face indices. However,
this becomes tedious rather quickly.&lt;/p&gt;

&lt;p&gt;Instead, you can do something slightly more intelligent and exploit the fact
that every convex polyhedron has a &lt;a href=&quot;https://en.wikipedia.org/wiki/Dual_polyhedron&quot;&gt;dual polyhedron&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;interlude-computing-the-dual-polyhedron&quot;&gt;Interlude: Computing the Dual Polyhedron&lt;/h2&gt;

&lt;p&gt;The dual polyhedron is a bit like a twin—or maybe it is more like &lt;a href=&quot;https://en.wikipedia.org/wiki/Strange_Case_of_Dr_Jekyll_and_Mr_Hyde&quot;&gt;Dr. Jekyll
and Mr. Hyde&lt;/a&gt;? I’ll leave it up to you. Here’s the slightly more
formal definition: For each convex polyhedron, there is a &lt;em&gt;dual polyhedron&lt;/em&gt; with
a face for each vertex and a vertex for each face of the original polyhedron.
Here’s an illustration of the concept of duality:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-platonics/dual_w_zoom.jpg&quot; alt=&quot;Illustration of the concept of a dual mesh.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The original mesh is a triangle mesh of a sphere, edges shown in dark gray. The
edges of the dual mesh are highlighted in teal. Each vertex of the dual mesh
corresponds to a face in the original mesh; each vertex of the original mesh
corresponds to a polygonal face in the dual mesh. Note that computing the dual
also is a practical way to convert a triangle mesh into an general polygon mesh.
Here is how you can compute the dual:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// the new dual mesh&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// a property to remember new vertices per face&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fvertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_face_property&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;f:vertex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// for each face add the centroid to the dual mesh&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;faces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fvertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;centroid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add new face for each vertex&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Vertex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;faces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fvertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_face&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// swap old and new meshes, don&apos;t copy properties&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Admittedly, this code is a little more specific to the PMP library. I’m using
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;centroid()&lt;/code&gt; function to compute the center of a face. Here’s the
definition:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;centroid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Face&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I am also using the built-in property mechanism to attach data to mesh entities
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mesh.add_face_property...&lt;/code&gt;). Here, I’m storing and retrieving the vertices
added to the dual mesh. If you want to keep it simple, you can also use a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::vector&lt;/code&gt; for managing this information.&lt;/p&gt;

&lt;p&gt;I’m also using two frequently used operations when working with meshes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I’m using &lt;em&gt;iterators&lt;/em&gt; to go through all mesh entities (faces, vertices)&lt;/li&gt;
  &lt;li&gt;I’m using a &lt;em&gt;circulator&lt;/em&gt; to traverse all faces &lt;em&gt;incident&lt;/em&gt; to a vertex.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The circulator is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for (auto f : mesh.faces(v))&lt;/code&gt; part. If you are using a
different data structure, you need to figure out how to do this for yourself.
Check the API documentation of your library. Or just switch to PMP!&lt;/p&gt;

&lt;h2 id=&quot;the-octahedron&quot;&gt;The Octahedron&lt;/h2&gt;

&lt;p&gt;With the new function to compute the dual mesh in place, we have all it takes to
generate another Platonic solid. The octahedron is the dual polyhedron of the
hexahedron, which we can already generate using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hexahedron()&lt;/code&gt; function. All
that’s left is to combine the two:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;octahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hexahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that’s a function to my liking: Create something, do something, and return
the result. As simple and clear as it gets. Comparing the original hexahedron
and the dual octahedron shows that there is an issue, though: The dual mesh is
much smaller and inside the original hexahedron.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-platonics/oct_in_hex.jpg&quot; alt=&quot;The dual octahedron contained in the original hexahedron&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;normalizing-positions-on-the-unit-sphere&quot;&gt;Normalizing Positions on the Unit Sphere&lt;/h2&gt;

&lt;p&gt;For the functions defined so far, I took care to compute the vertex coordinates
in such a way that they are on the unit sphere. It would be nice to have the
same property for the dual meshes as well. A simple solution is to project the
vertices of the dual mesh back to the unit sphere. Here’s a function for doing
exactly that:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;project_to_unit_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;norm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now let’s use this in our function generating the octahedron:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;octahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hexahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;project_to_unit_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And this is what the result looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-platonics/oct_hex_sphere.jpg&quot; alt=&quot;Octahedron and hexahedron within a sphere&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Much better. The two shapes have all their points nicely aligned on the unit
sphere, just as we want them to be.&lt;/p&gt;

&lt;h2 id=&quot;icosahedron-and-dodecahedron&quot;&gt;Icosahedron and Dodecahedron&lt;/h2&gt;

&lt;p&gt;Finally, let’s tackle the remaining two polyhedra, icosahedron and dodecahedron.
The two are dual to another, so we only need to generate one of them by hand and
then compute the other one using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dual()&lt;/code&gt; function. I’m choosing the
icosahedron for the manual implementation:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;icosahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;5.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// golden ratio&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add vertices&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;project_to_unit_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// add triangles&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_triangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Computing the dodecahedron now is straightforward:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dodecahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;icosahedron&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;dual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;project_to_unit_sphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And here is the result showing both the icosahedron and dodecahedron enclosed by
the unit sphere:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/generating-platonics/ico_dod_sphere.jpg&quot; alt=&quot;Icosahedron and dodecahedron within the unit sphere&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;Alright, that’s it for the moment. I hope this was useful to you. The &lt;a href=&quot;/download/MyViewer_platonic_solids.cpp&quot;&gt;full
code&lt;/a&gt; is available as well. I’ll
eventually write more articles like this one, so stay tuned.&lt;/p&gt;

&lt;p&gt;In the meantime, tell me what you think. Comments? Questions? Suggestions? Drop
me a &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;mail&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://www.reddit.com/user/lycium/&quot;&gt;u/lycium&lt;/a&gt; on Reddit for
suggesting a simplification of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;icosahedron()&lt;/code&gt; function.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Graphics and Geometry Resources</title>
   <link href="https://danielsieger.com/blog/2020/12/30/graphics-geometry-resources.html"/>
   <updated>2020-12-30T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2020/12/30/graphics-geometry-resources</id>
   <content type="html">&lt;p&gt;Now here’s a positive consequence of 2020: There are plenty of awesome resources
on graphics and geometry available online for everyone to watch, enjoy, and
educate oneself. Here’s my current watch list.&lt;/p&gt;

&lt;h2 id=&quot;toronto-geometry-colloquium&quot;&gt;Toronto Geometry Colloquium&lt;/h2&gt;

&lt;p&gt;This is a regular online seminar presenting varying topics from geometry
processing and related disciplines such as computational fabrication, graphics,
or 3D deep learning. The format is innovative: A 10 minute short presentation
shows recent work and a longer 50 minute session provides a more in-depth
presentation.&lt;/p&gt;

&lt;p&gt;The talks are broadcast live on YouTube. Recordings are available on their
YouTube &lt;a href=&quot;https://www.youtube.com/channel/UCWBK_AH2d370JxmLJVpa9bA&quot;&gt;channel&lt;/a&gt; as well. Checkout their &lt;a href=&quot;https://toronto-geometry-colloquium.github.io/&quot;&gt;website&lt;/a&gt; for more
information.&lt;/p&gt;

&lt;h2 id=&quot;technion-seminar&quot;&gt;Technion Seminar&lt;/h2&gt;

&lt;p&gt;The Technion Center for Graphics and Geometric Computing organizes an
international seminar on geometric modeling, geometry processing, and
computational geometry. The format is a more traditional one hour talk.
&lt;del&gt;Checkout their website for the program, schedule, and abstracts.&lt;/del&gt;&lt;/p&gt;

&lt;h2 id=&quot;symposium-on-geometry-processing-2020&quot;&gt;Symposium on Geometry Processing 2020&lt;/h2&gt;

&lt;p&gt;This year’s SGP conference talks are still available on YouTube. Checkout the
&lt;a href=&quot;https://sgp2020.sites.uu.nl/programme/&quot;&gt;program&lt;/a&gt; and the &lt;a href=&quot;https://sgp2020.sites.uu.nl/&quot;&gt;conference website&lt;/a&gt;. All paper sessions and
keynotes are available on the conference YouTube &lt;a href=&quot;https://www.youtube.com/channel/UCLYK514PAUu3HdCqzZL2txA&quot;&gt;channel&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;eurographics-2020&quot;&gt;Eurographics 2020&lt;/h2&gt;

&lt;p&gt;Similarly, this year’s &lt;a href=&quot;https://conferences.eg.org/egev20/&quot;&gt;Eurographics&lt;/a&gt; conference has lots of material
online: There is a YouTube &lt;a href=&quot;https://www.youtube.com/channel/UCBXKSgLrinZTzHQAHZxba1A&quot;&gt;channel&lt;/a&gt; with all the paper sessions and
keynotes. The conference papers are also freely accessible from the &lt;a href=&quot;https://diglib.eg.org/handle/10.2312/2632885&quot;&gt;digital
library&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;ke-sen-huangs-graphics-resources&quot;&gt;Ke-Sen Huang’s Graphics Resources&lt;/h2&gt;

&lt;p&gt;Finally, a page that is always worth sharing: Ke-Sen Huang’s &lt;a href=&quot;https://www.realtimerendering.com/kesen/&quot;&gt;resources for
computer graphics&lt;/a&gt; contains a curated list of graphics conferences,
including links to full-text papers, videos, supplemental material, code,
project pages, etc. Probably one of &lt;em&gt;the&lt;/em&gt; most valuable resources on graphics
out there.&lt;/p&gt;

&lt;p&gt;Do you have a great resource on graphics and geometry to share? I’d
be glad to &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;hear&lt;/a&gt;!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Jekyll Website Performance Improvement</title>
   <link href="https://danielsieger.com/blog/2020/12/14/jekyll-website-performance-improvement.html"/>
   <updated>2020-12-14T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2020/12/14/jekyll-website-performance-improvement</id>
   <content type="html">&lt;p&gt;This article provides practical tips on how to optimize the loading speed of
your website. Some advice specifically aims at users of &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt;, the
blog-enabled static site generator. However, the basic ideas also apply to other
tools and should therefore be easy to transfer.&lt;/p&gt;

&lt;p&gt;Note: This is an article written by and for the occasional web developer. If
you’re a professional full-time web developer, you might know much of the
content. I still encourage you to continue reading, though!&lt;/p&gt;

&lt;h2 id=&quot;why-care&quot;&gt;Why Care?&lt;/h2&gt;

&lt;p&gt;Why should you care about performance? We’ve got tiny supercomputers in our
pockets, so who cares? And aren’t static websites such as those generated by
&lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt; super fast out of the box? Well, not so fast.&lt;/p&gt;

&lt;p&gt;Performance matters a lot, and tiny improvements can make a vast difference.
According to research from Google, the speed it takes to load a page has an
impact of around 75% for user experience, clearly above other criteria such as
ease of use or attractiveness:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/jekyll-performance/speed_impact.jpg&quot; alt=&quot;Impact of Speed on UX&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you would like to learn more, have a look at this talk from Google’s 2019 I/O
conference:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mLjxXPHuIJo&quot;&gt;&lt;img src=&quot;/images/jekyll-performance/youtube-io-2019.jpg&quot; alt=&quot;Google IO talk 2019&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it comes to static websites the situation surely is not as bad as in other
cases. Remember Flash, anyone? However, investigating performance more closely
reveals opportunities for optimization even for static sites.&lt;/p&gt;

&lt;h2 id=&quot;performance-analysis&quot;&gt;Performance Analysis&lt;/h2&gt;

&lt;p&gt;First, we need to measure performance before we can optimize it. My current tool
of choice is Google’s &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse&quot;&gt;Lighthouse&lt;/a&gt;. You can either run it in a
browser through &lt;a href=&quot;https://developers.google.com/web/tools/chrome-devtools&quot;&gt;Chrome Dev Tools&lt;/a&gt; or online at Google’s &lt;a href=&quot;https://web.dev/measure&quot;&gt;web.dev&lt;/a&gt;
pages.&lt;/p&gt;

&lt;p&gt;Lighthouse not only analyzes raw performance but also provides insight into how
well your website performs according to&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Accessibility&lt;/li&gt;
  &lt;li&gt;Best practices&lt;/li&gt;
  &lt;li&gt;Search engine optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s what I got for an older version of my site using Chrome Dev Tools:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/jekyll-performance/lighthouse_perf_old.jpg&quot; alt=&quot;Performance results on old website&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s quite a bit of red and orange. In contrast, this is what I get after
optimization, using &lt;a href=&quot;https://web.dev/measure&quot;&gt;web.dev&lt;/a&gt; this time:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/jekyll-performance/lighthouse_perf_results.jpg&quot; alt=&quot;Performance results on current website&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Read on to see how you might get there as well.&lt;/p&gt;

&lt;h2 id=&quot;minification&quot;&gt;Minification&lt;/h2&gt;

&lt;p&gt;Low-hanging fruits first.&lt;/p&gt;

&lt;p&gt;A straightforward way to reduce the size of your pages is to minify the HTML
code. Just like other text-based formats, HTML can be minified by reducing white
space, comments, newlines, or optional closing tags.&lt;/p&gt;

&lt;p&gt;There is a Jekyll plugin that exactly does that job for you:
&lt;a href=&quot;https://github.com/penibelst/jekyll-compress-html&quot;&gt;jekyll-compress-html&lt;/a&gt;. The usage is super simple:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Download the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compress.html&lt;/code&gt; file from the repository&lt;/li&gt;
  &lt;li&gt;Copy it to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_layouts&lt;/code&gt; folder of your Jekyll website&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Edit your top-level layout file (usually &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default.html&lt;/code&gt;) to have the
following front matter:&lt;/p&gt;

    &lt;div class=&quot;language-liquid highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
layout: compress
---
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will change your HTML code from something nicely formatted and
human-readable to something much more compact. Here is a comparison before and
after enabling minification:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/jekyll-performance/compress_before_after.jpg&quot; alt=&quot;HTML minification example&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This saves about 1K in size on a random HTML page of mine. Doesn’t sound too
impressive, but Lighthouse already shows some improvement.&lt;/p&gt;

&lt;h2 id=&quot;only-include-what-you-need&quot;&gt;Only Include What You Need&lt;/h2&gt;

&lt;p&gt;From here on things get slightly more complicated, but the gain in speed is also
significantly greater. Hang tight.&lt;/p&gt;

&lt;p&gt;Depending on your Jekyll setup, you eventually include a &lt;em&gt;lot&lt;/em&gt; of additional
assets like CSS frameworks, JavaScript libraries, or custom fonts. Chances are
that you only need a subset of them.&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&quot;https://getbootstrap.com&quot;&gt;Bootstrap&lt;/a&gt; to build this site (see &lt;a href=&quot;/blog/2019/01/12/creating-jekyll-bootstrap-template.html&quot;&gt;this post&lt;/a&gt;),
which depends on &lt;a href=&quot;https://jquery.com/&quot;&gt;jQuery&lt;/a&gt;. Both libraries are quite heavyweight. Turns
out I only need a fraction of them, offering an excellent opportunity for size
reduction.&lt;/p&gt;

&lt;h3 id=&quot;bootstrap&quot;&gt;Bootstrap&lt;/h3&gt;

&lt;p&gt;I compile my own version of Bootstrap using &lt;a href=&quot;https://en.wikipedia.org/wiki/Sass_(stylesheet_language)&quot;&gt;Sass&lt;/a&gt;, see this
&lt;a href=&quot;/blog/2019/01/12/creating-jekyll-bootstrap-template.html&quot;&gt;post&lt;/a&gt; for details. Therefore, I can easily configure which CSS
modules to include from the Bootstrap distribution. Here is my top-level
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.scss&lt;/code&gt; file with all unused modules commented out:&lt;/p&gt;

&lt;div class=&quot;language-scss highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;functions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;variables&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mixins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;reboot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;images&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;grid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;tables&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;forms&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;buttons&quot;; */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;transitions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;dropdown&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;button-group&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;input-group&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;custom-forms&quot;; */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nav&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;navbar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;card&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;breadcrumb&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;pagination&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;badge&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;jumbotron&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;alert&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;progress&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;media&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;list-group&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;close&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;toasts&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;modal&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;tooltip&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;popover&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;carousel&quot;; */&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;spinners&quot;; */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;utilities&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/* @import &quot;print&quot;; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s more than half of the modules, and I’m sure I could optimize this even
further after more careful investigation.&lt;/p&gt;

&lt;h3 id=&quot;jquery&quot;&gt;jQuery&lt;/h3&gt;

&lt;p&gt;The Bootstrap JavaScript code depends on jQuery, which is quite a heavy library
providing a lot of functionality. The good news is: As long as you are only
using the CSS part of Bootstrap, you are fine &lt;em&gt;not&lt;/em&gt; to include it.&lt;/p&gt;

&lt;p&gt;Check if you really need the Bootstrap JavaScript modules. If not, just remove
the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags for both from your template and watch your
performance score improving.&lt;/p&gt;

&lt;p&gt;In my case, I still use jQuery to retrieve comments on blog posts via GitHub,
see &lt;a href=&quot;/blog/2018/10/23/blog-comments-using-github.html&quot;&gt;this post&lt;/a&gt; for details. However, instead of including jQuery by
default on all pages, I now only include it on blog posts using the comment
functionality:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{% if page.issue and site.github_comments_repository %} ...
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/js/jquery.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
... {% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I admit that it is still overkill include jQuery just to retrieve some data from
GitHub. I’m sure there are more lightweight alternatives.&lt;/p&gt;

&lt;h3 id=&quot;mathjax&quot;&gt;MathJax&lt;/h3&gt;

&lt;p&gt;Many technical blogs include support for &lt;a href=&quot;https://www.mathjax.org/&quot;&gt;MathJax&lt;/a&gt;, a convenient way to
typeset mathematical formulas in your posts. Again, this is quite a heavy
dependency pulling in lots of JavaScript code.&lt;/p&gt;

&lt;p&gt;Similarly, the solution is to use conditional inclusion: Only include MathJax
when you really need it. Here, a dedicated front-matter variable in posts
needing MathJax support will do the trick:&lt;/p&gt;

&lt;div class=&quot;language-liquid highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
title: Fancy Post With Lots of Math
mathjax: true
---
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, change your layout or include file (depending on where you actually
include MathJax) to check for the variable being defined:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{% if page.mathjax %}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/x-mathjax-config&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;!--&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;your&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;here&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/MathJax.js?config=TeX-AMS_HTML&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
{% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; attribute above to enable asynchronous loading of the script.
This eventually enhances performance in case you actually use MathJax.&lt;/p&gt;

&lt;h2 id=&quot;deferred-loading&quot;&gt;Deferred Loading&lt;/h2&gt;

&lt;p&gt;As shown above, adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; attribute to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags is one way to
improve page load time for scripts that you absolutely have to load. Using the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defer&lt;/code&gt; attribute is another alternative. See the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script&quot;&gt;script&lt;/a&gt; HTML
element documentation for more information.&lt;/p&gt;

&lt;p&gt;Another commonly used technique is to defer the loading by placing your
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags at the very end of the document. However, you should not need
this anymore when using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defer&lt;/code&gt; attributes.&lt;/p&gt;

&lt;p&gt;For more information on how to eliminate render-blocking resources, please see
the corresponding Google Developers &lt;a href=&quot;https://web.dev/render-blocking-resources/&quot;&gt;page&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;inline-critical-css&quot;&gt;Inline Critical CSS&lt;/h2&gt;

&lt;p&gt;Another optimization technique is to &lt;em&gt;inline&lt;/em&gt; CSS code directly into the HTML
document instead of loading an external script. The key point is to inline only
&lt;em&gt;critical&lt;/em&gt; CSS styles needed to render the first paint and make the core
functionality work.&lt;/p&gt;

&lt;p&gt;I adopted a simple version of this by using an online critical path CSS
&lt;a href=&quot;https://jonassebastianohlsson.com/criticalpathcssgenerator/&quot;&gt;generator&lt;/a&gt;. This takes your website URL and the full CSS code as
input and generates a small set of critical CSS styles to include directly in
your HTML header.&lt;/p&gt;

&lt;p&gt;The resulting CSS looks far from being optimal, but for the moment it works
fine. I am sure there are better alternatives out there. Maybe you know
something that integrates well with Jekyll? Drop me a &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;mail&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;asynchronous-loading-of-css&quot;&gt;Asynchronous Loading of CSS&lt;/h2&gt;

&lt;p&gt;Another tweak I applied was to defer loading of the full CSS files using a
&lt;del&gt;hack&lt;/del&gt; creative solution based on the media attribute.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;style.css&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;media=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;print&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;onload=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;this.media=&apos;all&apos;&quot;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that this requires inlining of critical CSS, otherwise you will get ugly
“Flashes of Unstyled Content” (FOUC). See the full &lt;a href=&quot;https://css-tricks.com/the-simplest-way-to-load-css-asynchronously/&quot;&gt;description&lt;/a&gt; at
&lt;a href=&quot;https://css-tricks.com/&quot;&gt;css-tricks.com&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h2 id=&quot;fonts&quot;&gt;Fonts&lt;/h2&gt;

&lt;p&gt;Custom web fonts are popular and available to everyone through services like
&lt;a href=&quot;https://fonts.google.com&quot;&gt;Google Fonts&lt;/a&gt;. However, ask yourself if you really need them.&lt;/p&gt;

&lt;p&gt;As an alternative, consider using a system font stack relying on fonts already
installed on the user’s system. This offers significant performance gains since&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;there are no font files to transfer and load&lt;/li&gt;
  &lt;li&gt;the browser likely has the fonts cached&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All major operating systems include somewhat decent fonts these days, so this
really is an alternative. Plus, the system fonts match the look and feel of the
operating system, so users are used to it.&lt;/p&gt;

&lt;p&gt;Here’s one way to use system fonts:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-apple-system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BlinkMacSystemFont&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;Segoe UI&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Roboto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Helvetica&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Arial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sans-serif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;Apple Color Emoji&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;Segoe UI Emoji&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;Segoe UI Symbol&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, if you are like me and want more precise control over the fonts being
used, there are some guidelines to do this efficiently:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Host the fonts yourself if possible. This avoids additional connection
requests and/or name resolution.&lt;/li&gt;
  &lt;li&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;font-display: swap&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@font-face&lt;/code&gt; definition to make sure text
remains visible while the browser loads the fonts.&lt;/li&gt;
  &lt;li&gt;Reduce the size of the font files by sub-setting. Only include the glyphs for
the languages you are using.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pre-load essential font files by adding appropriate special tags to your header:&lt;/p&gt;

    &lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;preload&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/font.woff2&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;as=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;font&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;font/woff2&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;crossorigin&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last remark: Popular icon font sets such as &lt;a href=&quot;https://fontawesome.com/&quot;&gt;Font Awesome&lt;/a&gt; are quite heavy
as well. The latter contains something around 1000 icons (depending on your
version), and I doubt you really need all of them. Consider creating a
customized version containing only the icons you actually use. However, this is
a story for another day. Time to wrap up.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;In this article, I showed a few basic techniques to optimize the performance of
your website, with a particular focus on Jekyll users.&lt;/p&gt;

&lt;p&gt;There are plenty of ways to optimize the speed of your website even further.
Images are one area I didn’t cover. There is a lot to gain from using modern
image formats and compression. You can also provide images in different
pre-scaled resolutions so that the browser has less work to do.&lt;/p&gt;

&lt;p&gt;However, these examples also show that optimization usually comes with a certain
cost in terms of&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;implementation effort and&lt;/li&gt;
  &lt;li&gt;maintenance overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some techniques described here make maintenance and development much more
cumbersome. The manual inlining of critical CSS is one such example. It requires
manual updates whenever you change one of your critical styles. There are better
solutions out there, but I did not yet investigate in detail.&lt;/p&gt;

&lt;p&gt;Do you have further advice on performance optimization? Something easy and
efficient based on Jekyll? Drop me a &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;mail&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>PMP Library at SGP</title>
   <link href="https://danielsieger.com/blog/2020/12/03/pmp-library-at-sgp.html"/>
   <updated>2020-12-03T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2020/12/03/pmp-library-at-sgp</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Earlier this year, we were honored to be invited to give a presentation on
our
&lt;a href=&quot;https://www.pmp-library.org&quot;&gt;pmp-library&lt;/a&gt; at the
&lt;a href=&quot;https://sgp2020.sites.uu.nl/&quot;&gt;SGP 2020&lt;/a&gt;
&lt;a href=&quot;https://sgp2020.sites.uu.nl/graduates/&quot;&gt;graduate school&lt;/a&gt;.
Unfortunately, due to the special circumstances, the event was virtual only. The
good thing is that a &lt;a href=&quot;https://www.youtube.com/watch?v=RXc9af0Rq8s&quot;&gt;recording&lt;/a&gt; is
available on YouTube:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=RXc9af0Rq8s&quot;&gt;&lt;img src=&quot;/images/pmp-sgp-2020/youtube-pmp-sgp-2020.jpg&quot; alt=&quot;YouTube video presenting PMP at SGP&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All other videos from the SGP graduate school are
&lt;a href=&quot;http://school.geometryprocessing.org/&quot;&gt;available online&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;Enjoy the show!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>PMP Library Version 1.2.1 Released</title>
   <link href="https://danielsieger.com/blog/2020/05/10/pmp-library-version-1.2.1.html"/>
   <updated>2020-05-10T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2020/05/10/pmp-library-version-1.2.1</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We just released a minor bug-fix release of the Polygon Mesh Processing Library, version 1.2.1. See the official &lt;a href=&quot;https://www.pmp-library.org/version-1-2-1-released-2020-05-10.html&quot;&gt;release announcement&lt;/a&gt; as well as the full &lt;a href=&quot;https://github.com/pmp-library/pmp-library/blob/master/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Task Tracking and the Bullet Journal Method</title>
   <link href="https://danielsieger.com/blog/2020/05/02/task-tracking-and-bullet-journal-method.html"/>
   <updated>2020-05-02T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2020/05/02/task-tracking-and-bullet-journal-method</id>
   <content type="html">&lt;p&gt;For the last decade or so I used &lt;a href=&quot;https://orgmode.org&quot;&gt;Org mode&lt;/a&gt; for tracking
tasks and taking notes. This worked reasonably well while I was mostly working
full time on a single project. Nowadays, things are a bit more complicated. I
usually have multiple projects going on both at work and in private. Over time,
I ended up with a wild bunch of different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.org&lt;/code&gt; files for different purposes
floating around on different computers. As you can imagine, things got
increasingly hard to track. Eventually, I almost stopped consistently tracking
tasks due to the inadequacy of this system. It was clear that I needed a better
solution.&lt;/p&gt;

&lt;h2 id=&quot;modern-note-taking-apps-no-thanks&quot;&gt;Modern Note-Taking Apps: No Thanks&lt;/h2&gt;

&lt;p&gt;One solution would have been to adopt a modern cloud-based note-taking
application such as Microsoft OneNote, Evernote, or similar. Unfortunately,
these systems typically result in vendor lock-in due to proprietary storage
formats. In addition, there are some serious concerns about data privacy and
security. To me, all of the above simply does not sound quite right for
something that is supposed to last and be accessible for years to come.
Alternatives such as setting up my own system to keep all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.org&lt;/code&gt; files in sync
did not seem very appealing, either.&lt;/p&gt;

&lt;h2 id=&quot;bullet-journal-to-the-rescue&quot;&gt;Bullet Journal to the Rescue&lt;/h2&gt;

&lt;p&gt;Roughly a year ago, I stumbled upon a different approach at handling tasks and
notes: The &lt;a href=&quot;https://www.bulletjournal.com/&quot;&gt;Bullet Journal&lt;/a&gt; method
originally introduced by &lt;a href=&quot;https://www.rydercarroll.com/&quot;&gt;Ryder Carroll&lt;/a&gt;.
This simple technique is completely analog and does not require any
sophisticated digital tools. All you need is this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/task-tracking/notebook_and_pen.jpg&quot; alt=&quot;Notebook and Pen&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A notebook and a pen. That’s it. Plus a few simple guidelines how to organize
your tasks and notes. The following gives you a glimpse of the method.&lt;/p&gt;

&lt;h2 id=&quot;bullet-journal-basics&quot;&gt;Bullet Journal Basics&lt;/h2&gt;

&lt;p&gt;The core of the method is something called &lt;em&gt;rapid logging&lt;/em&gt;, which introduces a
short-form notation for quickly adding different types of entries to your
notebook. The basic entries are tasks, events, and notes:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/task-tracking/rapid_logging.jpg&quot; alt=&quot;Rapid Logging&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once you are finished with a task you simply mark it with a cross:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/task-tracking/completed_task.jpg&quot; alt=&quot;Completed Task&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A dedicated &lt;em&gt;index&lt;/em&gt; allows you to quickly look up entries later on. Specific
&lt;em&gt;logs&lt;/em&gt; gather tasks you need to accomplish in a certain time frame such as the
current month. On top of that, &lt;em&gt;collections&lt;/em&gt; help you organize your entries into
related categories. Finally, &lt;em&gt;migration&lt;/em&gt; is the process of moving incomplete
tasks to a future log so that they remain visible. A migrated task gets an arrow
to signify that it is taken care of somewhere else:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/task-tracking/migrated_task.jpg&quot; alt=&quot;Completed Task&quot; /&gt;&lt;/p&gt;

&lt;p&gt;An important aspect of manual task migration is that it helps you to identify
which tasks really matter to you. Before migrating a task, take a moment and
think about whether it really is still relevant. If not, simply cross it out. If
you already migrated a task several times, chances are high that it is not
really that important or urgent. Or, you are just very good at procrastinating.
In any case: Consider manual task migration as a chance for simplification. The
effort it takes is an incentive to get things done and focus on the essential.&lt;/p&gt;

&lt;p&gt;Got interested? Take a minute or two and checkout Ryder Carroll’s original
introduction to the technique:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GfRf43JTqY4&quot;&gt;&lt;img src=&quot;/images/task-tracking/youtube-bujo.jpg&quot; alt=&quot;Bullet Journal video on YouTube&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;I quickly adopted this simple low-tech approach for pretty much everything I
want to track: Tasks, notes, ideas, meeting minutes, important dates, habits,
stuff to read, sketches, and whatever else comes to my mind.&lt;/p&gt;

&lt;p&gt;After more than one year of intensive usage I’m still amazed by the system’s
simplicity, flexibility, and effectiveness. Of course, there are some rough
edges as well, especially when it comes to bridging the gap to other (online)
systems. Overall, however, I’m pretty satisfied with the system and I don’t see
myself switching to anything else anytime soon.&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Want to know more? Checkout the
&lt;a href=&quot;https://www.bulletjournal.com&quot;&gt;official website&lt;/a&gt; and the
&lt;a href=&quot;https://www.youtube.com/watch?v=fm15cmYU0IM&quot;&gt;updated video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you like what you see, just give it a try! I hope it will help you getting
more organized and maybe even more focused on what really matters to you.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Ironically, I &lt;em&gt;was&lt;/em&gt; using analog calendars &lt;em&gt;before&lt;/em&gt; Org-mode. I guess it was the lack of flexibility of traditional calendars and the general lack of a system that made me switch to Org-mode in the first place. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>PMP Library Version 1.2 Released</title>
   <link href="https://danielsieger.com/blog/2020/03/15/pmp-library-version-1.2.html"/>
   <updated>2020-03-15T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2020/03/15/pmp-library-version-1.2</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We just released a new minor release of the Polygon Mesh Processing Library,
version 1.2. This release includes a couple new features, enhancements, bug
fixes, and updates to third-party libraries. Highlights include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Improved rendering of general polygons, avoiding erroneous tessellation into
overlapping/flipped triangles in case of non-convex polygons.&lt;/li&gt;
  &lt;li&gt;Added support for rendering using matcaps.&lt;/li&gt;
  &lt;li&gt;Eigen interoperability: Matrix and vector classes can now be assigned and cast
from Eigen matrices and vectors.&lt;/li&gt;
  &lt;li&gt;Matrix and vector classes can now be constructed using initializer lists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the official
&lt;a href=&quot;https://www.pmp-library.org/version-1-2-released-2020-03-15.html&quot;&gt;release announcement&lt;/a&gt; as
well as the full
&lt;a href=&quot;https://github.com/pmp-library/pmp-library/blob/master/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt;.
for details.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>PMP Library Version 1.1 Released</title>
   <link href="https://danielsieger.com/blog/2019/05/30/pmp-library-version-1.1.html"/>
   <updated>2019-05-30T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/05/30/pmp-library-version-1.1</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We just released the new version 1.1 of the Polygon Mesh Processing
Library. This release includes a couple new features, enhancements, bug fixes,
and updates to third-party libraries. Highlights include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;An implementation of the hole filling algorithm by Liepa&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;An improved &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceSmoothing&lt;/code&gt; algorithm avoiding model shrinking&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;A new compile-time switch to choose between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;double&lt;/code&gt; as default
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Scalar&lt;/code&gt; type&lt;/li&gt;
  &lt;li&gt;Native support for high-DPI displays on all supported operating systems and
browsers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the
official
&lt;a href=&quot;https://www.pmp-library.org/version-1-1-released-2019-05-30.html&quot;&gt;release announcement&lt;/a&gt; as
well as the
full
&lt;a href=&quot;https://github.com/pmp-library/pmp-library/blob/master/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt;.
for details.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Peter Liepa. Filling holes in meshes. In &lt;em&gt;Proceedings of Eurographics Symposium on Geometry Processing&lt;/em&gt;, pages 200–205, 2003. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Misha Kazhdan, Justin Solomon, and Mirela Ben-Chen. &lt;em&gt;Can mean‐curvature flow be modified to be non‐singular?&lt;/em&gt; Computer Graphics Forum, 31(5), 2012. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Publication Pages Using Jekyll Collections</title>
   <link href="https://danielsieger.com/blog/2019/03/03/publication-pages-using-jekyll-collections.html"/>
   <updated>2019-03-03T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/03/03/publication-pages-using-jekyll-collections</id>
   <content type="html">&lt;p&gt;Jekyll &lt;a href=&quot;https://jekyllrb.com/docs/collections/&quot;&gt;collections&lt;/a&gt; are a great way to
group and process pages of related content. I’m currently using collections to
build my &lt;a href=&quot;/publications.html&quot;&gt;publications page&lt;/a&gt; and associated project
pages. This post provides a short rundown how to implement something like this.&lt;/p&gt;

&lt;h2 id=&quot;add-a-collection&quot;&gt;Add a Collection&lt;/h2&gt;

&lt;p&gt;First of all, you need to add a collection to your Jekyll configuration file,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;. In this case, I aptly name it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publications&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;publications&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/:collection/:name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;output: true&lt;/code&gt; option configures Jekyll to write a rendered page for each
document in the collection. This will be the project page associated to each
publication. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;permalink&lt;/code&gt; option configures the output path based on the base
name of the document.&lt;/p&gt;

&lt;h2 id=&quot;create-an-example-document&quot;&gt;Create an Example Document&lt;/h2&gt;

&lt;p&gt;Next, create a directory named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_publications&lt;/code&gt; to store one Markdown file for
each publication. Each of these files will hold the publication meta-data such
as title, authors, or where the work was published. In this example, I’m using
the following dummy content and save it in a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mypub19.md&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-md highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;A New Method for Fancy Research&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;authors&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;John Doe and Mary Jane&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;publication&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Journal of Fancy Research&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2019&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;doi&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://dx.doi.org/XX.XXX/&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;add-a-publications-page&quot;&gt;Add a Publications Page&lt;/h2&gt;

&lt;p&gt;The next step is to create an overview page that lists all your publications. In
my example, I simply call it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publications.html&lt;/code&gt; and use some
basic &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; loop to list all publications in reverse chronological
order:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
layout: default
title: Publications
---

&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mt-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Publications&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
{% assign publications = site.publications | sort: &quot;year&quot; | reverse %}
{% for pub in publications %}
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pubitem&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pubtitle&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ pub.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pubauthors&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ pub.authors }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pubinfo&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ pub.publication }}, {{ pub.year}}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
{% endfor %}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Integrating this into my minimal &lt;a href=&quot;/blog/2019/01/12/creating-jekyll-bootstrap-template.html&quot;&gt;jekyll-bootstrap-template&lt;/a&gt; will give you
something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/publication-pages/publist_basic.jpg&quot; alt=&quot;publist basic&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Admittedly, this looks rather dull, so let’s add at least &lt;em&gt;some&lt;/em&gt; minimal CSS
styling:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.pubitem&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2em&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1em&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.pubtitle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.5em&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1.2em&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.pubauthors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.pubinfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;75%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.75em&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This produces:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/publication-pages/publist_style.jpg&quot; alt=&quot;publist with style&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;adding-teaser-images&quot;&gt;Adding Teaser Images&lt;/h2&gt;

&lt;p&gt;Next up, a proper publication entry needs a teaser image, isn’t it? By
convention, I keep a small teaser image using a name based on&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;the base name of the publication file&lt;/li&gt;
  &lt;li&gt;plus a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_small&lt;/code&gt; suffix&lt;/li&gt;
  &lt;li&gt;plus the file extension&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The base name can be accessed in &lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;Liquid&lt;/a&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slug&lt;/code&gt; variable. Add
the following code to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pubitem&lt;/code&gt; element, just before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pubtitle&lt;/code&gt; element:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pubteaser&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{pub.url}}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/images/publication-pages/{{ pub.slug }}_small.jpg&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{pub.slug}} publication teaser&quot;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add some CSS for it:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.pubteaser&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;both&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.pubteaser&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;margin-right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2em&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.pubteaser&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The result already looks much closer to something acceptable:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/publication-pages/publist_teaser.jpg&quot; alt=&quot;publist with teaser&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;adding-links&quot;&gt;Adding Links&lt;/h2&gt;

&lt;p&gt;In order to keep the overview page clear and concise, I only include two links
per publication:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A download link for the PDF&lt;/li&gt;
  &lt;li&gt;A link to the project page providing more details&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By convention, I keep a PDF file using the same base name as the publication
file in my downloads folder. The following snippet adds the corresponding links
to the overview page. Just add it at the end of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pubitem&lt;/code&gt; element:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;publinks&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/download/{{ pub.slug}}.pdf&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;far fa-file-pdf&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt; PDF&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{pub.url}}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fas fa-link&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt; Project Page&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add some more CSS:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.publinks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;75%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the result looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/publication-pages/publist_links.jpg&quot; alt=&quot;publist with links&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;project-pages&quot;&gt;Project Pages&lt;/h2&gt;

&lt;p&gt;Now, the final missing piece is a proper project page providing supplementary
information and additional downloads. I’m controlling what this page looks like
using a custom layout named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publication&lt;/code&gt;. I’m providing a sample layout below,
simply add it as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publication.html&lt;/code&gt; to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_layouts&lt;/code&gt; directory and replace the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; layout in your publication meta-data file with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publication&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
layout: default
---

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;page&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mt-4 publication-title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ page.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;publication-authors&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ page.authors }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;publication-info&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ page.publication }}, {{ page.year}}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;publication-teaser&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/images/publication-pages/{{ page.slug }}.jpg&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;project teaser&quot;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  {{ content }}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;downloads&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Downloads&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/download/{{ page.slug }}.pdf&quot;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;far fa-file-pdf&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt; PDF&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt; {% if page.slides %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/download/{{ page.slug }}_slides.pdf&quot;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;far fa-file-pdf&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt; Slides&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt; {% endif %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/download/{{ page.slug }}.bib&quot;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;far fa-file-alt&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt; BibTex&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt; {% if page.doi %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ page.doi }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fas fa-external-link-alt&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt; DOI&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;nbsp;&amp;amp;nbsp;&lt;/span&gt; {% endif %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After adding some dummy abstract to the publication file this results in the
following page:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/publication-pages/publist_page.jpg&quot; alt=&quot;publication page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The above layout assumes a two additional files to be present:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A full size teaser image named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{{ page.slug }}.jpg&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;A BibTex file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{{ page.slug }}.bib&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Presentation slides and DOI links are optional and only included if you specify
the corresponding keys in the publication file preamble. Add additional links as
needed, e.g., for downloading example code, data, or links to a repository.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;That’s all there is to it. For your convenience, I set up
a &lt;a href=&quot;https://github.com/dsieger/jekyll-collections-example&quot;&gt;repository&lt;/a&gt; providing
a complete minimal working example. You’ll probably want to modify and adjust
this to your needs, but hopefully this will help to get you started.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>PMP Library Version 1.0 Released</title>
   <link href="https://danielsieger.com/blog/2019/02/18/pmp-library-version-one.html"/>
   <updated>2019-02-18T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/02/18/pmp-library-version-one</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After years of contemplation, vivid discussion, crazy experimentation, and lots
of hard work, we finally released the first official version of the Polygon Mesh
Processing Library. Highlights include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A simple and efficient mesh data structure for storing and processing
polygonal surface meshes&lt;/li&gt;
  &lt;li&gt;Canonical geometry processing algorithms such as simplification, remeshing,
subdivision, smoothing, or curvature computation&lt;/li&gt;
  &lt;li&gt;Ready-to-use visualization tools to build your own mesh processing
applications&lt;/li&gt;
  &lt;li&gt;Compilation into JavaScript to build browser-based apps (&lt;a href=&quot;https://www.pmp-library.org/demos/mpview.html&quot;&gt;demo&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information visit &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;pmp-library.org&lt;/a&gt;. See the
&lt;a href=&quot;https://github.com/pmp-library/pmp-library/blob/master/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt;
for a high-level summary of changes.&lt;/p&gt;

&lt;p&gt;Get your own copy by cloning:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone --recursive https://github.com/pmp-library/pmp-library.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Checkout the release tag:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd pmp-library &amp;amp;&amp;amp; git checkout 1.0.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Configure and build:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir build &amp;amp;&amp;amp; cd build &amp;amp;&amp;amp; cmake .. &amp;amp;&amp;amp; make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run the mesh processing app&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./mpview ../external/pmp-data/off/bunny.off
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you encounter any glitches or problems
please &lt;a href=&quot;https://github.com/pmp-library/pmp-library/issues&quot;&gt;report the issue&lt;/a&gt; on
our GitHub issue tracker.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>SGP Summer School Presentations Online</title>
   <link href="https://danielsieger.com/blog/2019/01/28/sgp-summer-school-presentations.html"/>
   <updated>2019-01-28T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/01/28/sgp-summer-school-presentations</id>
   <content type="html">&lt;p&gt;The &lt;a href=&quot;http://www.geometryprocessing.org&quot;&gt;Symposium on Geometry Processing (SGP)&lt;/a&gt; is one of the premier
conferences for publishing cutting-edge research in—hold your
breath—geometry processing.&lt;/p&gt;

&lt;p&gt;The conference also hosts a pre-conference graduate school every year, during
which well-known researchers in the field present their perspective on
fundamentals and current research trends.&lt;/p&gt;

&lt;p&gt;Starting from 2016, the organizers have recorded these presentations. They are
now available online at&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://school.geometryprocessing.org/&quot;&gt;http://school.geometryprocessing.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;for everyone to watch and enjoy. That’s a &lt;em&gt;ton&lt;/em&gt; of great material. So, next time
you can’t decide what to watch in the evening simply try one of these!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Ray Tracing Books Online for Free</title>
   <link href="https://danielsieger.com/blog/2019/01/25/ray-tracing-books-online.html"/>
   <updated>2019-01-25T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/01/25/ray-tracing-books-online</id>
   <content type="html">&lt;p&gt;Two standard books on ray tracing are now available online for free:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Matt Pharr &lt;a href=&quot;https://pharr.org/matt/blog/2018/10/15/pbr-online.html&quot;&gt;announced&lt;/a&gt; the
availability of &lt;a href=&quot;https://www.pbr-book.org/&quot;&gt;“Physically Based Rendering”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Eric Haines
&lt;a href=&quot;https://www.realtimerendering.com/blog/an-introduction-to-ray-tracing-is-now-free-for-download/&quot;&gt;announced&lt;/a&gt; the
availability
of
&lt;a href=&quot;https://www.realtimerendering.com/raytracing/An-Introduction-to-Ray-Tracing-The-Morgan-Kaufmann-Series-in-Computer-Graphics-.pdf&quot;&gt;“An Introduction to Ray Tracing”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though personally I prefer reading such content on plain old paper, this is
still great news for anyone interested in the subject. I can only congratulate
the authors for taking this step.&lt;/p&gt;

&lt;p&gt;In case of “Physically Based Rendering”, part of their motivation seems to be
due to the low printing quality of the second printing of the third edition. I
can only confirm this. I recently bought the 3rd edition and I was &lt;em&gt;really&lt;/em&gt;
disappointed by the lack of quality. Hopefully some publishers will learn a
lesson or two from this, although I’m not too optimistic in this regard.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Unit Testing File I/O</title>
   <link href="https://danielsieger.com/blog/2019/01/20/unit-testing-file-io.html"/>
   <updated>2019-01-20T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/01/20/unit-testing-file-io</id>
   <content type="html">&lt;p&gt;A somewhat tricky question when it comes to unit testing is how to test
components involving file I/O. &lt;a href=&quot;/blog/2018/09/11/unit-testing-geometric-algorithms.html&quot;&gt;Recall&lt;/a&gt; that a good unit tests should run
fast and independent of its execution environment. A test involving file I/O
inevitably breaks these rules, which is why some people don’t even consider such
a test a unit test.&lt;/p&gt;

&lt;p&gt;Whatever your definition of a unit test is: There &lt;em&gt;is&lt;/em&gt; a need for testing I/O
components. Almost every moderately complex software system will involve some
form of file I/O, e.g., for data exchange, &lt;a href=&quot;https://en.wikipedia.org/wiki/Serialization&quot;&gt;serialization&lt;/a&gt;, or
debugging. In other words: If you take software testing seriously, you’ll
probably need to deal with testing I/O components at some point.&lt;/p&gt;

&lt;h2 id=&quot;testing-strategies&quot;&gt;Testing Strategies&lt;/h2&gt;

&lt;p&gt;In the following, I’ll briefly outline some testing strategies that I’ve come
across so far and highlight their strengths and weaknesses. The main use case
I’ve got in mind is the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;Polygon Mesh Processing Library&lt;/a&gt;, in which we
support numerous mesh file formats for reading and writing. Therefore, my
selection of strategies might be a bit biased towards this use case.&lt;/p&gt;

&lt;h3 id=&quot;checksums&quot;&gt;Checksums&lt;/h3&gt;

&lt;p&gt;The basic idea is to check the output files (or input objects) for equality
using previously computed checksums. This is probably one of the simplest tests
to implement. It basically only requires some baseline data and a checksum
function, and it will ensure correctness for known inputs or outputs. However,
the simplicity comes at a cost. The resulting test will be highly fragile, i.e.,
the slightest change in the code or the input data requires a baseline
update. This in turn can drastically slow down your development speed when using
&lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;test-driven development&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;round-trip&quot;&gt;Round-Trip&lt;/h3&gt;

&lt;p&gt;A slightly more advanced strategy is to do a round-trip: Generate some test
data, write it to a file, read the contents back in, and make sure that the
resulting object is (approximately) identical to the baseline. This approach is
still rather simple and straightforward to implement. It also gives you much
more flexibility in how strict you want your comparisons to be. However, it also
requires code for both reading and writing a particular format, which might not
always be feasible.&lt;/p&gt;

&lt;h3 id=&quot;formal-verification&quot;&gt;Formal Verification&lt;/h3&gt;

&lt;p&gt;An even more sophisticated approach would be to parse the file and verify that
it conforms to a formal specification of the file format, e.g., by using a
formal grammar. This strategy eventually results in a high level of correctness
and comprehensive test coverage. At the same time, the implementation effort
might be considerable. In case of missing or incomplete specifications it might
be difficult if not impossible to realize.&lt;/p&gt;

&lt;h3 id=&quot;image-based-comparisons&quot;&gt;Image-Based Comparisons&lt;/h3&gt;

&lt;p&gt;Sometimes, a picture is worth a thousand words. The same applies to a rendered
image of your data. Similar to the checksum-based method mentioned above, you
can use image-based comparisons to test for strict equality. In addition, this
approach opens up the possibility to test within a certain tolerance. It can
also help to spot visual artifacts that are not easily captured by a numeric
characteristic. A main drawback of this strategy is that it requires a certain
amount of infrastructure, i.e., to do off-screen rendering and to read and
compare image data. However, it might come in handy for general testing as well,
so it might be well worth the effort.&lt;/p&gt;

&lt;h2 id=&quot;file-system-independence&quot;&gt;File System Independence&lt;/h2&gt;

&lt;p&gt;The strategies outlined above should give you some ideas how to write tests for
components involving file I/O. However, they do not yet help with the dependence
on the file system itself and the problems associated with this. Therefore, a
major goal should be to break this dependence so that the unit test runs fast
and independent of the execution environment.&lt;/p&gt;

&lt;p&gt;One possible way to achieve this is to apply
the &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_responsibility_principle&quot;&gt;Single Responsibility Principle&lt;/a&gt; (SRP), one of the &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt;
principles of object-oriented software design. It basically states that every
module or class should only be responsible for a single functionality.&lt;/p&gt;

&lt;p&gt;Let’s consider a simplistic writer function as an example:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// additional checks on filename omitted for brevity&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ofstream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/tmp/test.txt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Usually, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write()&lt;/code&gt; function would take care of checking the file specified
in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filename&lt;/code&gt; for readability, open it, write the contents to disk, and finally
close the file again. This means, however, that the function has more than one
responsibility:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;File handling &lt;em&gt;and&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Data conversion to the disk format&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whenever you can describe the responsibility of a class or function with an
&lt;em&gt;and&lt;/em&gt;, this should give you a hint that this part of the code eventually
violates the SRP principle.&lt;/p&gt;

&lt;p&gt;The obvious solution is to split the responsibility so that the file handling is
not part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write()&lt;/code&gt; function. Instead, it should only handle the
conversion of the data to the desired file format.&lt;/p&gt;

&lt;p&gt;In C++, we can achieve this rather easily by using the output stream class
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::ostream&lt;/code&gt;. Using this interface allows for both output to an actual file
using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::ofstream&lt;/code&gt; as well as output to a string buffer using
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::ostringstream&lt;/code&gt; for unit testing.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write()&lt;/code&gt; function simply would become:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ostream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The regular invocation would pass an already opened &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::ofstream&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ofstream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/tmp/test.txt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In contrast, the unit test invocation would pass an instance of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::ostringstream&lt;/code&gt; and then validate the resulting contents of the string
stream for correctness:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ostringstream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cerr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test failed&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course, the above is only a totally simplistic and fictitious example, but it
should be sufficient to get the idea of separating responsibilities across so
that you can make your tests independent of the file system.&lt;/p&gt;

&lt;p&gt;For a real-world application you’d probably add some intermediate class to
handle the actual file system interactions such as checking for existence,
permissions, opening, and closing. You could then test this abstraction layer
even further by
using &lt;a href=&quot;https://en.wikipedia.org/wiki/Mock_object&quot;&gt;mock objects&lt;/a&gt;. For now,
however, that’s way out of scope for this post.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;In this post, I outlined basic strategies for unit testing software components
involving file I/O as well as a concrete way to refactor your I/O functions to
have clearer responsibilities and to be less dependent on the underlying file
system.&lt;/p&gt;

&lt;p&gt;My current strategy of choice for validating I/O results is to do a round trip
of export and re-import. It’s not perfect, that’s for sure, but it offers a good
compromise between correctness, completeness, flexibility, and implementation
effort.&lt;/p&gt;

&lt;p&gt;In case &lt;em&gt;you&lt;/em&gt; are aware of any additional testing strategies for file I/O, I’d
be glad to &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;hear&lt;/a&gt;!&lt;/p&gt;

&lt;h2 id=&quot;references-and-further-reading&quot;&gt;References and Further Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://legalizeadulthood.wordpress.com/2008/04/07/how-do-i-unit-test-something-that-writes-to-a-file/&quot;&gt;How Do I Unit Test Something That Writes To A File?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20250813201041/https://dzone.com/articles/unit-testing-file-io&quot;&gt;Unit Testing File I/O Operations&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://softwareengineering.stackexchange.com/questions/258246/tdd-how-to-test-file-outputs&quot;&gt;TDD: how to test file outputs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Creating a Jekyll Bootstrap Template</title>
   <link href="https://danielsieger.com/blog/2019/01/12/creating-jekyll-bootstrap-template.html"/>
   <updated>2019-01-12T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/01/12/creating-jekyll-bootstrap-template</id>
   <content type="html">&lt;p&gt;I recently rewrote this site to use a custom &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;
theme based on &lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt;
and &lt;a href=&quot;https://en.wikipedia.org/wiki/Sass_(stylesheet_language)&quot;&gt;Sass&lt;/a&gt;. I kept
some notes during the process, and now I reworked them into this short guide on
building a bare-bones Jekyll Bootstrap template.&lt;/p&gt;

&lt;p&gt;The following assumes you’re already somewhat familiar with Jekyll. If this is
not the case, I’d recommend to head over to
the &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll homepage&lt;/a&gt; first in order to learn some
basics.&lt;/p&gt;

&lt;p&gt;For the impatient: The
complete &lt;a href=&quot;https://github.com/dsieger/jekyll-bootstrap-minimal&quot;&gt;code&lt;/a&gt; is
available on GitHub. However, I’m sure you’ll get more out of this if you follow
along and try the steps for yourself.&lt;/p&gt;

&lt;h2 id=&quot;creating-the-skeleton&quot;&gt;Creating the Skeleton&lt;/h2&gt;

&lt;p&gt;We begin by creating a fresh Jekyll skeleton:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;jekyll new jekyll-bootstrap-minimal --blank
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, add a directory to contain the Bootstrap Sass distribution:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;cd jekyll-bootstrap-minimal
mkdir -p css/bootstrap
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Get the latest version of Bootstrap from
their &lt;a href=&quot;https://getbootstrap.com/&quot;&gt;website&lt;/a&gt;. Be sure to download the source
distribution. Unzip the downloaded file and copy the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scss&lt;/code&gt; directory into the
skeleton:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;cp -r ~/Downloads/bootstrap-4.2.1/scss/* css/bootstrap/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the main Sass file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;css/style.scss&lt;/code&gt; and import Bootstrap:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/* modify Bootstrap variables here */&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;bootstrap/bootstrap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/* add additional CSS rules below */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt; file telling Jekyll where to search for Sass
files:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;sass&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;sass_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;css&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;compressed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I added the compression option so that the resulting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.css&lt;/code&gt; files are smaller
and load faster.&lt;/p&gt;

&lt;p&gt;The last thing to do is to import the jQuery and Bootstrap JavaScript libraries:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;mkdir js
wget https://code.jquery.com/jquery-3.3.1.min.js -P js
cp ~/Downloads/bootstrap-4.2.1/dist/js/* js/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s all there is for the &lt;em&gt;absolute&lt;/em&gt; minimum. However, this will not yet give
you any useful site template. The following section describes how to add a
default layout in order to get a minimal site up and running.&lt;/p&gt;

&lt;h2 id=&quot;adding-a-minimal-layout&quot;&gt;Adding a Minimal Layout&lt;/h2&gt;

&lt;p&gt;Create a default layout file as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_layouts/default.html&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  {% include header.html %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    {% include navbar.html %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ content }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    {% include footer.html %}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/js/jquery-3.3.1.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/js/bootstrap.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_includes&lt;/code&gt; directory:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;mkdir _includes
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the content of the include files I borrow bits and pieces from
the
&lt;a href=&quot;https://startbootstrap.com/snippets/portfolio-item/&quot;&gt;Portfolio Item&lt;/a&gt;
template made by &lt;a href=&quot;https://startbootstrap.com/&quot;&gt;Start Bootstrap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Start with the header in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_includes/header.html&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://gmpg.org/xfn/11&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;profile&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;http-equiv=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;X-UA-Compatible&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;IE=edge&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;http-equiv=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;content-type&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/html; charset=utf-8&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width=device-width, initial-scale=1.0&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ page.title }} - {{ site.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/css/style.css&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add a navbar in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_includes/navbar.html&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;nav&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar navbar-expand-lg navbar-dark bg-dark&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar-brand&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ site.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar-toggler&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;button&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;data-toggle=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;collapse&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;data-target=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#navbarResponsive&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;aria-controls=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbarResponsive&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;aria-expanded=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;aria-label=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Toggle navigation&quot;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar-toggler-icon&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;collapse navbar-collapse&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbarResponsive&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar-nav ml-auto&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-item active&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-link&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Home
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sr-only&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;(current)&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-item&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-link&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;About&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-item&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-link&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Services&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-item&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-link&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Contact&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add the footer to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_includes/footer.html&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;footer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;py-2 bg-dark&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;m-0 text-center text-white&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      Copyright &lt;span class=&quot;ni&quot;&gt;&amp;amp;copy;&lt;/span&gt; {{ site.time | date: &apos;%Y&apos; }}
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now it’s time to add some content to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.html&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
layout: default
title: Home
---

&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  Page Heading
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;small&amp;gt;&lt;/span&gt;Secondary Text&lt;span class=&quot;nt&quot;&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-md-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;img-fluid&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://placehold.it/750x500&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-md-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Project Description&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam viverra
      euismod odio, gravida pellentesque urna varius vitae. Sed dui lorem,
      adipiscing in adipiscing et, interdum nec metus. Mauris ultricies, justo
      eu convallis placerat, felis enim.
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Project Details&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Lorem Ipsum&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Dolor Sit Amet&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Consectetur&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Adipiscing Elit&lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Related Projects&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-md-3 col-sm-6 mb-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;img-fluid&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://placehold.it/500x300&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-md-3 col-sm-6 mb-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;img-fluid&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://placehold.it/500x300&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-md-3 col-sm-6 mb-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;img-fluid&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://placehold.it/500x300&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-md-3 col-sm-6 mb-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;img-fluid&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://placehold.it/500x300&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;site.title&lt;/code&gt; Liquid variable in the above includes. Therefore, we
need to add it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Jekyll Bootstrap&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;sass&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;sass_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;css&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;compressed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s it. Kick off Jekyll to build and serve your site:&lt;/p&gt;

&lt;div class=&quot;language-terminal highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;jekyll serve
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The result should look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/jekyll-bootstrap/template_page_screenshot.jpg&quot; alt=&quot;Screenshot showing a landing page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Not too bad, ain’t it? In any case, the resulting template should provide you
with a good starting point for building whatever website you have in
mind. Checkout
the &lt;a href=&quot;https://github.com/dsieger/jekyll-bootstrap-minimal&quot;&gt;repository&lt;/a&gt; for the
full source code and feel free to fork and modify to suit your needs. Hope this
helps!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>On Software Testing in Research</title>
   <link href="https://danielsieger.com/blog/2019/01/05/software-testing-in-research.html"/>
   <updated>2019-01-05T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2019/01/05/software-testing-in-research</id>
   <content type="html">&lt;p&gt;Extensive software testing is not a wide-spread practice in academic
research. In this short argumentative post, I’ll outline some of the negative
consequences this entails. In the end, I hope to convince you that testing is
not only something for industrial software development but that it is also
essential for doing research using software prototypes.&lt;/p&gt;

&lt;h2 id=&quot;from-bugs-to-false-results&quot;&gt;From Bugs to False Results&lt;/h2&gt;

&lt;p&gt;People with an academic background often have no or little exposure to the
practice of software testing. This is unfortunate, because if you want to make
sure your software behaves correctly there is practically no way around
comprehensive software testing.&lt;/p&gt;

&lt;p&gt;While recent developments such as
the &lt;a href=&quot;http://www.replicabilitystamp.org/&quot;&gt;Graphics Replicability Stamp Initiative&lt;/a&gt; are a step in the right
direction, I’m convinced that this is not yet sufficient. Assuring the
reproducibility of the results simply means reproducibility of the bugs. And I’m
sure there are plenty of them out there, especially considering how a typical
research prototype usually comes into existence, i.e., written in a rush to meet
the next paper deadline.&lt;/p&gt;

&lt;p&gt;Of course, there’s also the possibility you’re a rock star developer, and your
software never contains a bug. But what about your collaborators? Your students?
The third-party libraries you’re depending on? The industry average defect rate
is around 1–25 bugs per 1000 lines of code&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. And that’s &lt;em&gt;industry&lt;/em&gt; average
and not &lt;em&gt;research&lt;/em&gt; average. Do the math.&lt;/p&gt;

&lt;p&gt;The consequence of those undiscovered bugs are scientific publications including
false results. Nobody really needs that.&lt;/p&gt;

&lt;h2 id=&quot;validate-hypotheses-on-a-solid-basis&quot;&gt;Validate Hypotheses on a Solid Basis&lt;/h2&gt;

&lt;p&gt;You might argue that testing is a waste of time when writing throw-away research
prototypes. I think this is wrong. You write your prototype for obtaining
results, that’s for sure. More importantly, however, the prototype is your
central tool for validating—or falsifying—your hypotheses. This is at the
very core of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Scientific_method&quot;&gt;scientific method&lt;/a&gt;. If you do not relentlessly test
your prototype, the results you obtain can be completely misleading. Eventually,
you assume your hypothesis is correct while it’s not. Or, you might discard your
hypothesis because your results are unsatisfactory. And so a potentially
brilliant idea goes down the drain.&lt;/p&gt;

&lt;h2 id=&quot;untested-prototypes-are-wasteful&quot;&gt;Untested Prototypes Are Wasteful&lt;/h2&gt;

&lt;p&gt;The bad consequences do not stop here. Untested code is legacy code. The
untested prototype will silently bit-rot either in some online repository or—
even worse—just on some department server or backup disk. A few years down the
line nobody will remember how to get things working or how to make changes. In
other words, the code becomes practically useless. Given the fact that a large
part of research is publicly funded, one could consider this a rather direct
waste of public money.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;To make a long story short: Stop using excuses. Software testing is an essential
tool for making sure your research prototype produces correct results. Get
familiar with it and use it extensively the next time you develop a
prototype. Consider even using &lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;test-driven development&lt;/a&gt; (TDD) to make sure
you test things right from the start.&lt;/p&gt;

&lt;p&gt;Now I’m going back to my corner and feel ashamed of all the untested research
prototypes I have written!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;McConnell, Steve. &lt;em&gt;Code Complete&lt;/em&gt;, Microsoft Press, 2004. Page 521. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Blog Comments Using GitHub</title>
   <link href="https://danielsieger.com/blog/2018/10/23/blog-comments-using-github.html"/>
   <updated>2018-10-23T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/10/23/blog-comments-using-github</id>
   <content type="html">&lt;p&gt;I’m building this site using &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, the simple,
blog-aware, static site generator. While it’s a great tool overall, it comes
with a major drawback when it comes to blogging: There’s no out-of-the-box
support for comments. Some folks even maintain the view
that &lt;a href=&quot;https://blog.codinghorror.com/a-blog-without-comments-is-not-a-blog/&quot;&gt;a blog without comments is not a blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve been searching for a reasonable comment system for a while. The most
wide-spread solution seems to be to use a third-party service
like &lt;a href=&quot;https://disqus.com/&quot;&gt;Disqus&lt;/a&gt;. However, this approach is not really an option for me,
mostly due to data protection and privacy concerns.&lt;/p&gt;

&lt;p&gt;Don Williamson put up a short &lt;a href=&quot;https://donw.io/post/github-comments/&quot;&gt;investigation&lt;/a&gt; on how much tracking the
use of Disqus involves. Luckily, he directly proposes an enticingly simple
solution based on the &lt;a href=&quot;https://docs.github.com/en/rest/issues&quot;&gt;GitHub issues API&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Each post gets an associated issue on GitHub&lt;/li&gt;
  &lt;li&gt;Users can leave comments on the post/issue&lt;/li&gt;
  &lt;li&gt;Some JavaScript pulls the comments from GitHub&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The advantages are compelling:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;No tracking&lt;/li&gt;
  &lt;li&gt;Users keep control over their comments&lt;/li&gt;
  &lt;li&gt;Moderation&lt;/li&gt;
  &lt;li&gt;Markdown support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are some obvious drawbacks as well. Users need to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Leave the site&lt;/li&gt;
  &lt;li&gt;Have a GitHub account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this certainly raises the entry burden, it also provides some protection
against comment spam. Anyway, I’m gonna give it a try.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;https://davecompton.net/&quot;&gt;Dave Compton&lt;/a&gt; for &lt;a href=&quot;https://davecompton.net/2017/06/24/using-github-comments-in-a-jekyll-blog.html&quot;&gt;providing&lt;/a&gt; a
Jekyll &lt;a href=&quot;https://github.com/dc25/minimaWithGithubComments&quot;&gt;reference implementation&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>The Feynman Problem-Solving Algorithm</title>
   <link href="https://danielsieger.com/blog/2018/10/21/feynman-problem-solving-algorithm.html"/>
   <updated>2018-10-21T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/10/21/feynman-problem-solving-algorithm</id>
   <content type="html">&lt;p&gt;The Feynman Problem-Solving Algorithm:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Write down the problem&lt;/li&gt;
  &lt;li&gt;Think real hard&lt;/li&gt;
  &lt;li&gt;Write down the solution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it. As simple as it gets, yet so difficult.&lt;/p&gt;

&lt;p&gt;Rumor has it that this was more of an &lt;a href=&quot;https://wiki.c2.com/?FeynmanAlgorithm&quot;&gt;allusion&lt;/a&gt;
to &lt;a href=&quot;https://en.wikipedia.org/wiki/Richard_Feynman&quot;&gt;Richard Feynman&lt;/a&gt;’s legendary problem solving skills. Nevertheless,
I find it highly useful for a couple of reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;It reminds us that writing down a precise yet comprehensive problem
definition is a key step towards a solution. Often enough, this actually &lt;em&gt;is&lt;/em&gt;
the most difficult part.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The thinking really hard part remains what it is—hard. The good news is:
There are some methods and tools to help: &lt;a href=&quot;https://en.wikipedia.org/wiki/George_P%C3%B3lya&quot;&gt;George Pólya&lt;/a&gt; describes a
set of heuristics for solving mathematical problems in his
book &lt;a href=&quot;https://www.goodreads.com/book/show/192221.How_to_Solve_It&quot;&gt;&lt;em&gt;How to Solve It&lt;/em&gt;&lt;/a&gt;. Along similar
lines, &lt;a href=&quot;https://www.goodreads.com/book/show/11644480-introduction-to-the-design-and-analysis-of-algorithms&quot;&gt;&lt;em&gt;Introduction to the Design and Analysis of Algorithms&lt;/em&gt;&lt;/a&gt;
by &lt;a href=&quot;https://web.archive.org/web/20230211171712/http://www.csc.villanova.edu/~levitin/&quot;&gt;Anany Levitin&lt;/a&gt; contains an introduction to algorithmic problem
solving.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finally, I consider step 3 as a reminder that formulating the solution
requires at least as much care and attention as the previous steps.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hope this helps.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Practical Test Improvement</title>
   <link href="https://danielsieger.com/blog/2018/10/07/practical-test-improvement.html"/>
   <updated>2018-10-07T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/10/07/practical-test-improvement</id>
   <content type="html">&lt;p&gt;Time to put some of the unit testing guidelines I described &lt;a href=&quot;/blog/2018/09/11/unit-testing-geometric-algorithms.html&quot;&gt;last time&lt;/a&gt;
into practice. In this post, I’ll go through some concrete examples improving
the overall quality of a unit test suite.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;pmp-library&lt;/a&gt; will serve as a practical example: Its current test
suite is reasonably comprehensive, amounting to a &lt;a href=&quot;https://coveralls.io/github/pmp-library/pmp-library?branch=master&quot;&gt;test coverage&lt;/a&gt; of
around 96%. Most of the tests, however, have been written&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;in a rush,&lt;/li&gt;
  &lt;li&gt;without too much thought,&lt;/li&gt;
  &lt;li&gt;to cover as much code as possible, and&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;long&lt;/em&gt; after the original code was written&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yours truly is partially responsible for that, so it’s only fair enough I spend
some time cleaning things up.&lt;/p&gt;

&lt;p&gt;Before starting, recall the two fundamental qualities of a unit test:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It runs fast.&lt;/li&gt;
  &lt;li&gt;It helps to localize problems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’ll focus on performance first.&lt;/p&gt;

&lt;h2 id=&quot;assessing-performance&quot;&gt;Assessing Performance&lt;/h2&gt;

&lt;p&gt;We can run the full pmp-library test suite through a simple call to&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This reports a run-time of approximately 1.72 seconds on my Dell XPS 13 with a
Intel Core i7-7560 CPU running at 2.4 GHz. That’s not too bad, but I’m sure we
can do better. We’re currently using &lt;a href=&quot;https://github.com/google/googletest&quot;&gt;Google Test&lt;/a&gt; for unit testing. In
order to get a more detailed picture, we can run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gtest_runner&lt;/code&gt; directly:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;tests
./gtest_runner
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will report individual run times for each test and test case&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Skimming
through the results quickly reveals the most offending test:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;...
[----------] 1 test from PointSetAlgorithmsTest
[ RUN      ] PointSetAlgorithmsTest.smoothing
[       OK ] PointSetAlgorithmsTest.smoothing (1270 ms)
[----------] 1 test from PointSetAlgorithmsTest (1270 ms total)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Turns out the biggest time eater right now is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PointSetAlgorithmsTest&lt;/code&gt;. This
case alone takes up almost 75% of the run time of the entire test suite. The
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PointSetAlgorithmsTest&lt;/code&gt; currently contains only a single test for point set
smoothing using iterated Moving Least Squares projection. Given the limited
scope of the test it’s hardly justified that it takes up so much of our precious
testing time.&lt;/p&gt;

&lt;h2 id=&quot;improving-performance&quot;&gt;Improving Performance&lt;/h2&gt;

&lt;p&gt;Although it is a bit embarrassing, here’s the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PointSetAlgorithmsTest&lt;/code&gt; test case
in all its glory:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PointSetAlgorithmsTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PointSetAlgorithmsTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pmp-data/xyz/armadillo_low.xyz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PointSet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;TEST_F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PointSetAlgorithmsTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origBounds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PointSetSmoothing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;smooth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newBounds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;EXPECT_LT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newBounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;origBounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For now I’m ignoring the fact that checking for shrinking model bounds is not
really a meaningful test and concentrate on performance instead. The biggest
performance impact comes from&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;using an unnecessarily large model and&lt;/li&gt;
  &lt;li&gt;loading the model from a file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This has not only performance implications, but also directly violates two
criteria of a &lt;a href=&quot;/blog/2018/09/11/unit-testing-geometric-algorithms.html&quot;&gt;good unit test&lt;/a&gt;: The test touches the file system and
therefore depends on the execution environment. This applies to other cases in
the test suite as well, but I’ll stick to this one for now.&lt;/p&gt;

&lt;p&gt;A faster and more self-contained way to obtain a test model is to generate a
synthetic model on the fly. This also helps to concentrate on a model that is as
simple as possible. For this particular case generating a simple unit sphere
will be fully sufficient&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. Here’s a little helper function for doing that:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Randomly generate nPoints on the unit sphere.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Stores the resulting points and normals in ps.&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;generateRandomSphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nPoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PointSet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// normal distribution random number generator&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_random_engine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal_distribution&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distribution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;normals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertexProperty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Normal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;v:normal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// generate points and add to point set&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nPoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distribution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distribution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distribution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// reject if all zero&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// normalize&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// add point and normal&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addVertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;normals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using this function to generate the test model and removing the unnecessary test
fixture setup leads to a simple and self-contained test:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;TEST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PointSetAlgorithmsTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PointSet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;generateRandomSphere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;origBounds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;PointSetSmoothing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;smooth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;Scalar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newBounds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;EXPECT_LT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newBounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;origBounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This change brings down the run-time for this test down to a bare 5ms:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;...
[----------] 1 test from PointSetAlgorithmsTest
[ RUN      ] PointSetAlgorithmsTest.smoothing
[       OK ] PointSetAlgorithmsTest.smoothing (5 ms)
[----------] 1 test from PointSetAlgorithmsTest (5 ms total)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the full test suite this change reduces the run time from 1.72s to 0.44s,
almost a factor of 4. Good enough for now.&lt;/p&gt;

&lt;h2 id=&quot;improving-localization&quot;&gt;Improving Localization&lt;/h2&gt;

&lt;p&gt;Originally, I introduced &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PointSetAlgorithmsTest&lt;/code&gt; following the model of its
counterpart for surface meshes, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceMeshAlgorithmsTest&lt;/code&gt;. The latter contains
the tests for &lt;em&gt;all&lt;/em&gt; higher level surface mesh processing algorithms in the
library. This strategy, obviously, does not provide proper localization, i.e.,
in case a test fails it is not really straightforward to find out which part of
the code is causing trouble.&lt;/p&gt;

&lt;p&gt;In retrospect, it would have been more coherent to have separate cases for each
of the algorithms under test. After all, the classes and functions implementing
the algorithms are our basic units of code.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PointSetAlgorithmsTest&lt;/code&gt; only contains the smoothing test, so this is
quickly refactored into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PointSetSmoothingTest&lt;/code&gt;. In case of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceMeshAlgorithmsTest&lt;/code&gt; the situation is slightly more complex because we’ve
got more algorithms and scenarios to test. Despite, refactoring the test case is
still worth the effort: It not only provides better localization but also
provides opportunity to clean up redundant code by using algorithm-specific test
fixtures.&lt;/p&gt;

&lt;p&gt;To provide a concrete example: All of the curvature computation tests contained
the following lines in order to load a mesh of a hemisphere:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pmp-data/off/hemisphere.off&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;SurfaceCurvature&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;curvature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;curvature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;analyze&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Grouping all curvature tests in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SurfaceCurvatureTest&lt;/code&gt; case allows to simply
use a single test fixture for setup:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SurfaceCurvatureTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SurfaceCurvatureTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;EXPECT_TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pmp-data/off/hemisphere.off&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;curvature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SurfaceCurvature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;curvature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;analyze&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SurfaceCurvatureTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;curvature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;SurfaceMesh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mesh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SurfaceCurvature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;curvature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Obviously, the test case still relies on loading data from a file, which is bad,
and I’m gonna change it at some point.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;By applying some of the basic guidelines for good and clean unit tests the
pmp-library test suite now runs as fast as lightning and more properly covers
individual units of code.&lt;/p&gt;

&lt;p&gt;However, there’s still room for improvement. Especially when it comes to the
concepts we are actually testing for I’m far from satisfied with what we’ve got
so far.&lt;/p&gt;

&lt;p&gt;A whole different problem is how to properly test file I/O and file
formats. While there seem to be some strategies out there, I’m not yet sure
what’s the right way to go for the &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;pmp-library&lt;/a&gt;. In case you have a
suggestion, I’d be glad to &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;hear&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Note that Google Test uses a slightly confusing terminology for what is a &lt;em&gt;test&lt;/em&gt;, and what is a &lt;em&gt;test case&lt;/em&gt;. Basically a &lt;em&gt;test&lt;/em&gt; is a single test and a &lt;em&gt;test case&lt;/em&gt; is a group of tests. See the &lt;a href=&quot;https://google.github.io/googletest/primer.html#beware-of-the-nomenclature&quot;&gt;Google Test Primer&lt;/a&gt; for details. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;In a first attempt I used a small sphere point set floating around on my machine. Much to my surprise, this caused the test to fail. Turned out the file had all zero normals, essentially making the algorithm doing nothing. A perfect reminder to harden algorithms against degenerate inputs! &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Unit Testing Geometric Algorithms</title>
   <link href="https://danielsieger.com/blog/2018/09/11/unit-testing-geometric-algorithms.html"/>
   <updated>2018-09-11T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/09/11/unit-testing-geometric-algorithms</id>
   <content type="html">&lt;p&gt;Comprehensive testing is a key aspect of developing high-quality software
solutions. In this article, I’ll briefly motivate the use of testing, summarize
what makes up a good unit test, and finally dive into some of the challenges
when it comes to unit testing geometric algorithms.&lt;/p&gt;

&lt;h2 id=&quot;the-importance-of-testing&quot;&gt;The Importance of Testing&lt;/h2&gt;

&lt;p&gt;Over the last couple of years, extensive software testing has become a
cornerstone of high-quality software development. First of all,
industrial-strength, production-ready code requires testing in order to make
sure the software behaves correctly. Beyond that, having an extensive test suite
is the key ingredient to evolve a code base over time as requirements, features,
and people working on the code change. As &lt;a href=&quot;https://michaelfeathers.silvrback.com/&quot;&gt;Michael Feathers&lt;/a&gt; puts it
in his book &lt;a href=&quot;https://www.goodreads.com/book/show/44919.Working_Effectively_with_Legacy_Code&quot;&gt;&lt;em&gt;Working Effectively With Legacy Code&lt;/em&gt;&lt;/a&gt;: A code base
without proper test coverage is legacy code, i.e., a code base that is extremely
difficult to work with. There’s practically no way to change the code without
risking to break some part of the software’s functionality. Often enough, subtle
bugs can be introduced and go unnoticed until the software goes into
production—something you definitely want to avoid. In case you’re not yet
convinced or you’re all new to software testing, I highly recommend
reading &lt;a href=&quot;https://en.wikipedia.org/wiki/Kent_Beck&quot;&gt;Kent Beck’s&lt;/a&gt; seminal
book &lt;a href=&quot;https://www.goodreads.com/book/show/387190.Test_Driven_Development&quot;&gt;&lt;em&gt;Test-Driven Development: By Example&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that for the most part of this article, I’ll focus on &lt;a href=&quot;https://en.wikipedia.org/wiki/Unit_testing&quot;&gt;unit tests&lt;/a&gt;,
i.e., the type of tests used to assure the correctness of an individual unit of
code such as a class or a function. To be more precise, I’m following Michael
Feathers’ unit testing rules stating that a test is &lt;em&gt;not&lt;/em&gt; a unit test if:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It talks to a database&lt;/li&gt;
  &lt;li&gt;It communicates across the network&lt;/li&gt;
  &lt;li&gt;It touches the file system&lt;/li&gt;
  &lt;li&gt;You have to do special things to your environment to run it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-is-a-good-unit-test&quot;&gt;What Is a Good Unit Test?&lt;/h2&gt;

&lt;p&gt;Unfortunately, not all tests are created equal. A good test suite allows you to
change and evolve your code while assuring correctness. In contrast, a sloppily
done test suite can get in your way all too often, thereby significantly slowing
down your development speed. While it is trivial to come up with &lt;em&gt;a&lt;/em&gt; test, it is
much more difficult to come up with a &lt;em&gt;good&lt;/em&gt; test. In the extreme case, you
could just write one big test function exercising all of your code and simply
check for successful execution. Such a test, however, would not fulfill two of
the most basic and important characteristics of high-quality unit tests:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;They run fast.&lt;/li&gt;
  &lt;li&gt;They help to localize problems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Obviously, the one big test function won’t be fast as the code base grows and it
won’t help to localize problems due to its monolithic nature. In contrast, a
suite of individual test cases that can be run in isolation will allow you to
track down problems much faster. Beyond the two basic criteria of speed and
localization, a good test suite will exhibit the following properties:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Independent:&lt;/em&gt; The tests should not depend on each other. You should be able
to run the tests individually and in any order.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Repeatable:&lt;/em&gt; The tests should be repeatable and independent of the
environment being used.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Self-Validating:&lt;/em&gt; Tests should either pass or fail and not require any
additional manual inspection.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Timely:&lt;/em&gt; Test should be written just before the production code to ensure a
testable design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The excellent book &lt;a href=&quot;https://www.goodreads.com/book/show/3735293-clean-code&quot;&gt;&lt;em&gt;Clean Code&lt;/em&gt;&lt;/a&gt; from &lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_C._Martin&quot;&gt;Robert C. Martin&lt;/a&gt;
contains a full chapter on clean unit tests, and I can only recommend to read
it.&lt;/p&gt;

&lt;p&gt;Another major aspect is the stability of a test over time. A test that
frequently fails upon minor changes is likely to produce lots of false
positives. Keeping such a test up-to-date can be a real time sink. Some people
refer to such a test as being &lt;em&gt;brittle&lt;/em&gt; or &lt;em&gt;flaky&lt;/em&gt;. As it turns out, this aspect
can be a major challenge when testing geometric algorithms.&lt;/p&gt;

&lt;h2 id=&quot;unit-testing-geometric-algorithms&quot;&gt;Unit Testing Geometric Algorithms&lt;/h2&gt;

&lt;p&gt;Now, why should unit testing geometric algorithms be any different from other
types of algorithms? At a first glance, one might think everything is relatively
easy and straightforward. After all, it’s basically just math, so you should be
able to calculate the correct outcome of your algorithm, right? Well, this is
not quite true. In fact, even for basic operations such as determining whether a
point is inside a sphere or not we have to take into account potential floating
point precision issues. The folks from the &lt;a href=&quot;https://www.cgal.org&quot;&gt;CGAL&lt;/a&gt; project made a huge
effort in building a library that robustly deals with such precision issues.&lt;/p&gt;

&lt;p&gt;Aside from precision issues, for more complex algorithms—such as those
encountered in real-world geometry processing tasks—it becomes increasingly
difficult to exactly specify what the correct output of an algorithm is. The
notion of &lt;em&gt;correctness&lt;/em&gt; is no longer as easy to define. Instead, we gradually
move to test for &lt;em&gt;acceptable&lt;/em&gt; output, i.e., we consider the output to be correct
within a certain &lt;em&gt;tolerance&lt;/em&gt;. Note the connection to the self-validity criteria
mentioned above: Testing for a tolerance does not directly map to a simple
&lt;em&gt;pass&lt;/em&gt; or &lt;em&gt;fail&lt;/em&gt;. Even worse, when we hit the boundaries of the tolerance and
the test begins to fail, we eventually need to resort to time-consuming and
error-prone manual inspection.&lt;/p&gt;

&lt;p&gt;The problem gets aggravated even more when we need to test for multiple
tolerances. Let’s consider mesh simplification as an example. For such an
algorithm we typically don’t care about individual resulting vertex positions
but about more global properties such as the number of resulting triangles as
well as deviation from the initial surface. This is, however, not the only
criterion we might need to consider. If the resulting mesh is meant to be used
in downstream applications for which mesh element quality is relevant—such as
finite element simulations—we also need to make sure that the algorithm does
not generate degenerate mesh elements. So in this example we eventually need to
test for at least three different criteria:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Element count reduction&lt;/li&gt;
  &lt;li&gt;Distance to the initial surface&lt;/li&gt;
  &lt;li&gt;Mesh element quality&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Obviously, coming up with good default values and tolerances for such an
algorithm is not completely straightforward. The next section outlines some
strategies and guidelines I found to be useful in the past.&lt;/p&gt;

&lt;h2 id=&quot;testing-strategies&quot;&gt;Testing Strategies&lt;/h2&gt;

&lt;p&gt;So how do we come up with a good test for our geometry processing algorithm?
Sorry to disappoint, but there’s not a single definite answer to that. To some
extend, this will always require experimentation and previous experience. If you
happen to have found the silver bullet for this problem, I’d be glad
to &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;hear&lt;/a&gt;. In the meantime, however, there are still
some guidelines we can follow.&lt;/p&gt;

&lt;p&gt;The goal is to have a good and clean test. Recall the localization criterion
from above: A good test should help to localize problems. Therefore, it is only
natural to concentrate on a single concept per test. An ideal test would only
have a couple of lines of code: a setup function, a call to the algorithm, and a
set of assertions. Even if you need to test for multiple criteria as in the mesh
simplification example above, I recommend to create separate test cases for each
of the criteria. Now when writing the test case we basically need to answer
three questions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;What exactly is the property I want to test?&lt;/li&gt;
  &lt;li&gt;What is a reasonable default value?&lt;/li&gt;
  &lt;li&gt;What is an acceptable tolerance?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By applying the single-concept-per-test strategy you should already have
sufficient clarity about the property under test. The only thing you need is
some way to compute that property, e.g., a function to compute the minimum
element quality in a mesh. Next, to come up with a good default value, I
typically start by searching for cases with known outcome. Consider curvature
computation as an example. In this case, we know what the curvature should be
for certain surfaces such as a plane or a sphere. If there is no such known or
obvious case, I tend to think about the minimum viable application scenario of
the algorithm and start with the value computed for this case. Finally, unless
you already have some knowledge about a reasonable tolerance range, go ahead,
vary the input parameters of the algorithm, slightly change the input model,
check how sensible the test is to this variation, and adjust the tolerance
accordingly.&lt;/p&gt;

&lt;p&gt;When you’re done with testing the primary functionality of the algorithm, I
recommend not to stop there. Nasty bugs and odd behavior frequently occur for
borderline cases. Take some time to think about these and write a test for each
one of them. Use a &lt;a href=&quot;https://en.wikipedia.org/wiki/Code_coverage&quot;&gt;code coverage&lt;/a&gt; tool to identify cases not yet
covered by your test suite. Finally, it’s always a good practice to make sure
your algorithm gracefully handles invalid input. Write a test for it.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;Time to wrap up, this article already got much longer than expected. In any
case, I hope I could somewhat convince you that comprehensive testing is
important and that having a high quality test suite will help you to write more
clean and robust code in the long run. As for testing geometric algorithms, I
hope that the above guidelines will come in handy if you ever need to write a
test for a geometry processing algorithm. In case you already have experience in
this area, I’d be more than glad to hear any insights or recommendations. Simply
drop me a &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;mail&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Markdown Cheat Sheet</title>
   <link href="https://danielsieger.com/blog/2018/09/02/markdown-cheat-sheet.html"/>
   <updated>2018-09-02T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/09/02/markdown-cheat-sheet</id>
   <content type="html">&lt;p&gt;A minimal Markdown cheat sheet I keep around for reference. Only contains the
elements I most frequently use. See John
Gruber’s &lt;a href=&quot;https://daringfireball.net/projects/markdown/&quot;&gt;original spec&lt;/a&gt; for plain
Markdown and
this &lt;a href=&quot;https://kramdown.gettalong.org/quickref.html&quot;&gt;quick reference&lt;/a&gt;
for &lt;a href=&quot;https://kramdown.gettalong.org/index.html&quot;&gt;kramdown&lt;/a&gt;, the
default &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; Markdown parser.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Element&lt;/th&gt;
      &lt;th&gt;Syntax&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Headings&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;# Level 1&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;## Level 2&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;### Level 3&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Bold&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;**bold text**&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;em&gt;Italic&lt;/em&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_italic text_&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Monospace&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;`monospace text`&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Unordered List&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;- First Item&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;- Second Item&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;- Third Item&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Ordered List&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1. First Item&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2. Second Item&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3. Third Item&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Inline Link&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[Link Title](http://url.com)&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Reference Link&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[Link Title][id]&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;...&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[id]: http://url.com&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Image&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;![alt text](path_to_image.jpg)&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Blockquote&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt; quote text&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fenced Code Block&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;```&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include &amp;lt;iostream&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int main() {}&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;```&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tables&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;| Element | Syntax |&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;| ------ | ------------- |&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;| Item 1 | Description 1 |&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;| Item 2 | Description 2 |&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Footnote&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Text with a footnote[^1].&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;...&lt;/code&gt;&lt;br /&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[^1]: The footnote text.&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</content>
 </entry>
 
 <entry>
   <title>Heilmeier's Catechism</title>
   <link href="https://danielsieger.com/blog/2018/09/01/heilmeiers-catechism.html"/>
   <updated>2018-09-01T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/09/01/heilmeiers-catechism</id>
   <content type="html">&lt;p&gt;Heilmeier’s Catechism is a set of questions credited
to &lt;a href=&quot;https://en.wikipedia.org/wiki/George_H._Heilmeier&quot;&gt;George H. Heilmeier&lt;/a&gt; that
anyone proposing a research project or product development effort should be able
to answer.&lt;!--break--&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What are you trying to do? Articulate your objectives using no jargon.&lt;/li&gt;
  &lt;li&gt;How is it done today, and what are the limits of current practice?&lt;/li&gt;
  &lt;li&gt;What’s new in your approach and why do you think it will be successful?&lt;/li&gt;
  &lt;li&gt;Who cares? If you’re successful, what difference will it make?&lt;/li&gt;
  &lt;li&gt;What are the risks and the payoffs?&lt;/li&gt;
  &lt;li&gt;How much will it cost?&lt;/li&gt;
  &lt;li&gt;How long will it take?&lt;/li&gt;
  &lt;li&gt;What are the midterm and final “exams” to check for success?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I came across these a couple of times. While there surely is nothing special or
extraordinary about them, I still find them highly useful to assess the value
and feasibility of a research or development project.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Polishing the pmp-library Documentation</title>
   <link href="https://danielsieger.com/blog/2018/08/26/polishing-pmp-library-documentation.html"/>
   <updated>2018-08-26T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/08/26/polishing-pmp-library-documentation</id>
   <content type="html">&lt;p&gt;High-quality and easily accessible documentation is a key feature of an
easy-to-use software library. Since ease of use is a primary design goal of the
pmp-library, I recently spent some time polishing up the pmp-library
documentation.&lt;/p&gt;

&lt;p&gt;We currently use &lt;a href=&quot;https://www.doxygen.org&quot;&gt;Doxygen&lt;/a&gt; to build the full
&lt;a href=&quot;https://www.pmp-library.org&quot;&gt;pmp-library.org&lt;/a&gt; website, including the user guide
and reference documentation. As it stands today, Doxygen is &lt;em&gt;the&lt;/em&gt; standard tool
for C++ library documentation and comes with a whole bunch of powerful features
such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Auto-generated API documentation from annotated sources&lt;/li&gt;
  &lt;li&gt;Support of Markdown pages for higher-level documentation&lt;/li&gt;
  &lt;li&gt;Automatic cross-linking between pages and reference docs&lt;/li&gt;
  &lt;li&gt;Proper citation and bibliography handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all well and good, but Doxygen also comes with a number of drawbacks. In
my humble opinion, one of the most significant issues is the poor quality of the
generated HTML output. First of all, the default output is rather cluttered,
overly verbose, and not exactly clear and concise. There’s a plethora of index
pages and menus so that it is not really straightforward to retrieve the
information you are searching for. Furthermore, the HTML is not at all suitable
for mobile devices. While this might not be too much of an issue for pure API
reference docs, in our case this also means the the project homepage and user
guide are not really accessible on a wide range of devices.&lt;/p&gt;

&lt;p&gt;Being unsatisfied with the current state of affairs, I started to look around
for alternative documentation generators. In particular, I
investigated &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt;, &lt;a href=&quot;https://www.mkdocs.org&quot;&gt;MkDocs&lt;/a&gt;
and &lt;a href=&quot;https://www.sphinx-doc.org&quot;&gt;Sphinx&lt;/a&gt;
plus &lt;a href=&quot;https://breathe.readthedocs.org/&quot;&gt;Breathe&lt;/a&gt;. However, each of these
alternatives comes with its own drawbacks, e.g., lack of auto-generated API docs
and automatic cross-references in case of Jekyll and MkDocs, or a rather
complicated toolchain in case of Sphinx.&lt;/p&gt;

&lt;p&gt;Thus, I decided to see how far I can push a Doxygen-based solution by cleaning
up and fine-tuning the HTML output. Checkout the latest version of the
pmp-library &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;website&lt;/a&gt; for results. I don’t think it
is really worthwhile to go through all the modifications in detail. Instead, I’m
just providing some pointers to the most important changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Disable the overly verbose navigation tabs (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DISABLE_INDEX=YES&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;Enable the flexible tree view navigation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GENERATE_TREEVIEW=YES&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;Use a
&lt;a href=&quot;https://www.doxygen.nl/manual/customize.html#layout&quot;&gt;custom page layout&lt;/a&gt;
to change the structure of the output&lt;/li&gt;
  &lt;li&gt;Include custom HTML headers and footers&lt;/li&gt;
  &lt;li&gt;Customize the CSS to provide a more clean and minimalist appearance&lt;/li&gt;
  &lt;li&gt;Change the overall color theme to match our logo&lt;/li&gt;
  &lt;li&gt;Consistently use a few selected fonts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, one particular annoying behavior on mobile devices is the messed up
rendering of the split bar separating the tree view and the main content. I
ended up modifying the the background image (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;splitbar.png&lt;/code&gt;) used for this
component and copying it over using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTML_EXTRA_FILES&lt;/code&gt; tag. Definitely not
an elegant solution, but hey, it works for now.&lt;/p&gt;

&lt;p&gt;So, even though I’m quite convinced that the customized HTML output represents a
significant improvement compared to the standard one, there’s definitely lots of
room for further improvement. In case you have any suggestions or spot any
issues, please drop me a &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;mail&lt;/a&gt; or directly submit
an &lt;a href=&quot;https://github.com/pmp-library/pmp-library/issues&quot;&gt;issue&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Glimpse of a Library</title>
   <link href="https://danielsieger.com/blog/2018/01/10/glimpse-of-a-library.html"/>
   <updated>2018-01-10T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/01/10/glimpse-of-a-library</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/images/pmp-logo.svg&quot; alt=&quot;PMP Logo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’m currently working with the
venerable &lt;a href=&quot;https://ls7-gv.cs.tu-dortmund.de/people/botsch_mario.html&quot;&gt;Prof. Botsch&lt;/a&gt; on
&lt;em&gt;The Polygon Mesh Processing Library&lt;/em&gt;, an improved and extended version our
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Surface_mesh&lt;/code&gt; data structure including a more versatile geometry representation
as well as a collection of canonical geometry processing algorithms. Highlights
include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Flexible data structures for point sets, edge sets, and surface meshes
including dynamic property handling and topological changes.&lt;/li&gt;
  &lt;li&gt;Implementations of classical geometry processing algorithms such as surface
remeshing, simplification, or smoothing.&lt;/li&gt;
  &lt;li&gt;Visualization utilities based on OpenGL® for rapid prototyping.&lt;/li&gt;
  &lt;li&gt;A liberal 3-clause BSD license allowing for academic, open-source, and
commercial usage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of this, the library can be easily compiled into JavaScript™
using &lt;a href=&quot;https://github.com/kripken/emscripten&quot;&gt;emscripten&lt;/a&gt; and can be used to
create browser-based applications as
demonstrated &lt;a href=&quot;https://www.pmp-library.org/demos/mpview.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are curious, check out the homepage
at &lt;a href=&quot;https://www.pmp-library.org&quot;&gt;www.pmp-library.org&lt;/a&gt; and the corresponding
GitHub &lt;a href=&quot;https://github.com/pmp-library/pmp-library/&quot;&gt;project&lt;/a&gt;. Keep in mind,
however, there’s no official release yet. Things are still in flux and might
change quite a bit. Early feedback is more than welcome. If you’ve got any
comments or suggestions, please drop me a &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;mail&lt;/a&gt; or submit
an &lt;a href=&quot;https://github.com/pmp-library/pmp-library/issues&quot;&gt;issue&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Jekyll Migration</title>
   <link href="https://danielsieger.com/blog/2018/01/09/hello-world.html"/>
   <updated>2018-01-09T00:00:00+00:00</updated>
   <id>https://danielsieger.com/blog/2018/01/09/hello-world</id>
   <content type="html">&lt;p&gt;I finally took the time to migrate and upgrade my old university homepage
something slightly more modern, namely &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;. Hope
you’ll find what you came here for—if not, &lt;a href=&quot;mailto:hello@danielsieger.com&quot;&gt;let me
know&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 

</feed>
