<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Roy Triesscheijn&apos;s Blog</title>
    <description>Tech Lead at bol.com - Game Technology Enthusiast</description>
    <link>https://roy-t.nl/</link>
    <atom:link href="https://roy-t.nl/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 03 Oct 2025 10:10:56 +0000</pubDate>
    <lastBuildDate>Fri, 03 Oct 2025 10:10:56 +0000</lastBuildDate>
    <generator>Jekyll v4.3.2</generator>
    
      <item>
        <title>Generating Asteroids</title>
        <description>&lt;!-- Import required for XPlot.Plotly to work correctly --&gt;
&lt;script src=&quot;https://roy-t.nl/files/require.min.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;After watching &lt;a href=&quot;https://www.youtube.com/watch?v=lctXaT9pxA0&quot;&gt;this video&lt;/a&gt; I’ve become inspired to procedurally generate my own asteroids. I became even more intrigued when the video showed me how to combine functions to give such interesting results. However explaining how it works to friends and colleagues proved to be difficult. That’s why I’ve decided to compile the technique in a Juypter Notebook. You can find the original notebook at &lt;a href=&quot;https://github.com/roy-t/MiniRTS/tree/master/Notebooks&quot;&gt;github&lt;/a&gt; as well as compute shaders in which I have implemented these techniques.&lt;/p&gt;

&lt;h2 id=&quot;first-things-first&quot;&gt;First things first&lt;/h2&gt;
&lt;p&gt;Before generating asteroids I need several helper functions to plot the data. The main idea is that we have a line made up of many points, and we’re going to write and combine functions that alter the height of each point based on their distance from the origin. We then generalize this idea to a circle. Here altering the height means placing the point further away from the center in the direction of the normal.&lt;/p&gt;

&lt;p&gt;The implementation of these helper functions is not important right now, as long as you get the idea of what we’re trying to accomplish.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;using XPlot.Plotly;
using System.Numerics;

public XPlot.Plotly.PlotlyChart LinearPlotChart(Func&amp;lt;float, float&amp;gt; function, string title, string xaxis, string yaxis)
{
    var data = new Graph.Scatter()
    {    
        x = Enumerable.Range(0, 500).Select(xv =&amp;gt; xv / 100.0f),
        y = Enumerable.Range(0, 500).Select(yv =&amp;gt; function(yv / 100.0f))        
    };    
    return Plot(data, 0.0f, 5.0f, -2.0f, 2.0f, title, xaxis, yaxis);
}

public XPlot.Plotly.PlotlyChart Plot(Graph.Scatter data, float minX, float maxX, float minY, float maxY, string title, string xaxis, string yaxis)
{
    var layout = new Layout.Layout();
    layout.xaxis = new Graph.Xaxis() { range = new float[] { minX, maxX } };
    layout.yaxis = new Graph.Yaxis() { range = new float[] { minY, maxY } };

    var chart = Chart.Plot(data, layout);
    chart.WithTitle(title);    
    chart.WithXTitle(xaxis);
    chart.WithYTitle(yaxis);
    chart.WithWidth(400);
    chart.WithHeight(400);
    
    return chart;
}

public XPlot.Plotly.PlotlyChart PlotAsteroid(Func&amp;lt;float, float&amp;gt; craterShape, string title, params Crater[] craters)
{    
    var xs = new List&amp;lt;float&amp;gt;();
    var ys = new List&amp;lt;float&amp;gt;();
    
    for(float i = 0; i &amp;lt; (float)Math.PI * 2.0f; i += (float)Math.PI / 100.0f)
    {
        ComputeVertex(xs, ys, i, craterShape, craters);
    }
    ComputeVertex(xs, ys, 0, craterShape, craters);
                               
    var data = new Graph.Scatter() {x = xs, y = ys };       
    return Plot(data, -1.2f, 1.2f, -1.2f, 1.2f, title, &quot;&quot;, &quot;&quot;);
}

public float CalculateCraterDepth(Crater[] craters, Vector2 vertex, Func&amp;lt;float, float&amp;gt; craterShape)
{
    var craterHeight = 0.0f;
    for(var i = 0; i &amp;lt; craters.Length; i++)
    {
        var crater = craters[i];
        var x = Vector2.Distance(crater.Position, vertex) / Math.Max(crater.Radius, 0.0001f);
        craterHeight += craterShape(x);
    }    
    return craterHeight;
}

public void ComputeVertex(List&amp;lt;float&amp;gt; xs, List&amp;lt;float&amp;gt; ys, float i, Func&amp;lt;float, float&amp;gt; craterShape, Crater[] craters)
{
    var x = (float)Math.Cos(i);
    var y = (float)Math.Sin(i);

    var vertex = new Vector2(x, y);
    var height = 1.0f + CalculateCraterDepth(craters, vertex, craterShape);        
    vertex *= height;

    xs.Add(vertex.X);
    ys.Add(vertex.Y);
}

public struct Crater
{
    public Crater(Vector2 position, float radius)
    {
        this.Position = position;
        this.Radius = radius;        
    }
    
    public Vector2 Position {get;set;}
    public float Radius {get;set;}    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;generate-the-cavity&quot;&gt;Generate the cavity&lt;/h2&gt;

&lt;p&gt;The main ingredient in a crater is the cavity (hole). The lowest point is at the origin of the crater. So I’ve chosen a square function as our basis.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;display(LinearPlotChart(x =&amp;gt; x * x - 1, &quot;Basis function for cavity&quot;, &quot;Distance&quot;, &quot;Height&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;7237a768-b38f-4f34-977f-61d4ee198251&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0,1.01,1.02,1.03,1.04,1.05,1.06,1.07,1.08,1.09,1.1,1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19,1.2,1.21,1.22,1.23,1.24,1.25,1.26,1.27,1.28,1.29,1.3,1.31,1.32,1.33,1.34,1.35,1.36,1.37,1.38,1.39,1.4,1.41,1.42,1.43,1.44,1.45,1.46,1.47,1.48,1.49,1.5,1.51,1.52,1.53,1.54,1.55,1.56,1.57,1.58,1.59,1.6,1.61,1.62,1.63,1.64,1.65,1.66,1.67,1.68,1.69,1.7,1.71,1.72,1.73,1.74,1.75,1.76,1.77,1.78,1.79,1.8,1.81,1.82,1.83,1.84,1.85,1.86,1.87,1.88,1.89,1.9,1.91,1.92,1.93,1.94,1.95,1.96,1.97,1.98,1.99,2.0,2.01,2.02,2.03,2.04,2.05,2.06,2.07,2.08,2.09,2.1,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.2,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.3,2.31,2.32,2.33,2.34,2.35,2.36,2.37,2.38,2.39,2.4,2.41,2.42,2.43,2.44,2.45,2.46,2.47,2.48,2.49,2.5,2.51,2.52,2.53,2.54,2.55,2.56,2.57,2.58,2.59,2.6,2.61,2.62,2.63,2.64,2.65,2.66,2.67,2.68,2.69,2.7,2.71,2.72,2.73,2.74,2.75,2.76,2.77,2.78,2.79,2.8,2.81,2.82,2.83,2.84,2.85,2.86,2.87,2.88,2.89,2.9,2.91,2.92,2.93,2.94,2.95,2.96,2.97,2.98,2.99,3.0,3.01,3.02,3.03,3.04,3.05,3.06,3.07,3.08,3.09,3.1,3.11,3.12,3.13,3.14,3.15,3.16,3.17,3.18,3.19,3.2,3.21,3.22,3.23,3.24,3.25,3.26,3.27,3.28,3.29,3.3,3.31,3.32,3.33,3.34,3.35,3.36,3.37,3.38,3.39,3.4,3.41,3.42,3.43,3.44,3.45,3.46,3.47,3.48,3.49,3.5,3.51,3.52,3.53,3.54,3.55,3.56,3.57,3.58,3.59,3.6,3.61,3.62,3.63,3.64,3.65,3.66,3.67,3.68,3.69,3.7,3.71,3.72,3.73,3.74,3.75,3.76,3.77,3.78,3.79,3.8,3.81,3.82,3.83,3.84,3.85,3.86,3.87,3.88,3.89,3.9,3.91,3.92,3.93,3.94,3.95,3.96,3.97,3.98,3.99,4.0,4.01,4.02,4.03,4.04,4.05,4.06,4.07,4.08,4.09,4.1,4.11,4.12,4.13,4.14,4.15,4.16,4.17,4.18,4.19,4.2,4.21,4.22,4.23,4.24,4.25,4.26,4.27,4.28,4.29,4.3,4.31,4.32,4.33,4.34,4.35,4.36,4.37,4.38,4.39,4.4,4.41,4.42,4.43,4.44,4.45,4.46,4.47,4.48,4.49,4.5,4.51,4.52,4.53,4.54,4.55,4.56,4.57,4.58,4.59,4.6,4.61,4.62,4.63,4.64,4.65,4.66,4.67,4.68,4.69,4.7,4.71,4.72,4.73,4.74,4.75,4.76,4.77,4.78,4.79,4.8,4.81,4.82,4.83,4.84,4.85,4.86,4.87,4.88,4.89,4.9,4.91,4.92,4.93,4.94,4.95,4.96,4.97,4.98,4.99],&quot;y&quot;:[-1.0,-0.9999,-0.9996,-0.9991,-0.9984,-0.9975,-0.9964,-0.9951,-0.9936,-0.9919,-0.99,-0.9879,-0.9856,-0.9831,-0.9804,-0.9775,-0.9744,-0.9711,-0.9676,-0.96389997,-0.96,-0.9559,-0.9516,-0.9471,-0.9424,-0.9375,-0.9324,-0.9271,-0.9216,-0.9159,-0.90999997,-0.9039,-0.8976,-0.8911,-0.8844,-0.8775,-0.8704,-0.8631,-0.8556,-0.84790003,-0.84,-0.8319,-0.8236,-0.8151,-0.8064,-0.7975,-0.7884,-0.7791,-0.76960003,-0.7599,-0.75,-0.7399,-0.7296,-0.7191,-0.7084,-0.6975,-0.6864,-0.67509997,-0.6636,-0.65190005,-0.64,-0.6279,-0.6156,-0.6031,-0.5904,-0.57750005,-0.56439996,-0.5511,-0.5376,-0.52390003,-0.51,-0.49590003,-0.4816,-0.46709996,-0.45239997,-0.4375,-0.4224,-0.40710002,-0.39160007,-0.37589997,-0.35999995,-0.34390002,-0.3276,-0.3111,-0.29440004,-0.27749997,-0.2604,-0.24309999,-0.2256,-0.20790005,-0.19000006,-0.17189997,-0.15359998,-0.1351,-0.1164,-0.097500026,-0.078400016,-0.059099972,-0.039599955,-0.019899964,0.0,0.020099998,0.04039991,0.060899973,0.08159995,0.10249984,0.12359989,0.14490008,0.16640007,0.1881001,0.21000004,0.23210001,0.2544,0.27689993,0.2996,0.3225,0.3455999,0.36889994,0.3923999,0.41610014,0.44000006,0.46410012,0.4884001,0.5129,0.53760004,0.5625,0.5876,0.6128999,0.63839996,0.66409993,0.6899998,0.71609986,0.74240017,0.76890016,0.79560006,0.8225001,0.8496001,0.87689996,0.9044,0.93209994,0.9599999,0.98809993,1.0163999,1.0449,1.0736,1.1025002,1.1316001,1.1609001,1.1904001,1.2200999,1.25,1.2800999,1.3104,1.3409,1.3715999,1.4024999,1.4335997,1.4649003,1.4964001,1.5281,1.5600002,1.5921001,1.6243999,1.6568999,1.6896,1.7224998,1.7556,1.7888999,1.8223999,1.8561001,1.8900001,1.9241002,1.9584,1.9929001,2.0276,2.0625,2.0976,2.1329,2.1683998,2.2041,2.2399998,2.2760997,2.3124,2.3489,2.3856,2.4225001,2.4596,2.4969,2.5344,2.5721,2.61,2.6481,2.6864,2.7248998,2.7636,2.8025002,2.8416002,2.8809001,2.9204001,2.9601,3.0,3.0401,3.0804,3.1208997,3.1615996,3.2024999,3.2436,3.2848997,3.3263998,3.3680997,3.4099994,3.4520993,3.4943995,3.5369005,3.5796003,3.6225004,3.6656003,3.7089005,3.7524004,3.7961001,3.8400002,3.8841,3.9284,3.9729,4.0176,4.0625,4.1075997,4.1528997,4.1984,4.2440996,4.29,4.3360996,4.3823996,4.4289,4.4756,4.5224996,4.5695996,4.6168995,4.6644006,4.7121005,4.76,4.8081,4.8564005,4.9049006,4.9536004,5.0025,5.0516,5.1009,5.1504,5.2001,5.25,5.3001,5.3504,5.4009,5.4515996,5.5024996,5.5536,5.6049,5.6563997,5.7080994,5.7599993,5.8120995,5.8643994,5.9169006,5.9696007,6.0225005,6.0756006,6.1289005,6.1824,6.2361,6.2900004,6.3441,6.3984003,6.4529,6.5076,6.5625,6.6176,6.6728997,6.7283998,6.7840996,6.8399997,6.8960996,6.9523997,7.0088997,7.0655994,7.1224995,7.1796,7.2368994,7.2944,7.3521004,7.410001,7.4681005,7.5264006,7.584901,7.6436005,7.7025003,7.7616005,7.8209,7.8803997,7.9400997,8.0,8.0601,8.120399,8.1809,8.2416,8.3025,8.3636,8.4249,8.4864,8.5480995,8.61,8.672099,8.734399,8.796901,8.859601,8.922501,8.9856,9.048901,9.1124,9.176101,9.240001,9.3041,9.368401,9.4329,9.4976,9.5625,9.6276,9.6929,9.7584,9.8241,9.889999,9.9560995,10.0224,10.0889,10.1556,10.222499,10.289599,10.356899,10.4244,10.492101,10.56,10.6281,10.696401,10.7649,10.8336,10.9025,10.971601,11.0409,11.1104,11.1801,11.25,11.3201,11.3904,11.460899,11.5316,11.6025,11.673599,11.7449,11.8164,11.8881,11.959999,12.032099,12.104399,12.176901,12.2496,12.3225,12.3956,12.468901,12.5424,12.6161,12.690001,12.7641,12.8384,12.9129,12.9876,13.0625,13.1376,13.2129,13.2884,13.3640995,13.44,13.5161,13.5924,13.6689,13.7456,13.822499,13.899599,13.976899,14.0544,14.132101,14.210001,14.2881,14.366401,14.4449005,14.523601,14.6025,14.681601,14.7609005,14.8404,14.9201,15.0,15.080101,15.1604,15.240902,15.3216,15.402502,15.483599,15.564901,15.646399,15.728102,15.809999,15.892101,15.9744,16.0569,16.139599,16.2225,16.3056,16.3889,16.472399,16.5561,16.639997,16.7241,16.808397,16.8929,16.977598,17.0625,17.147602,17.2329,17.318401,17.4041,17.490002,17.5761,17.662401,17.7489,17.835602,17.922499,18.009602,18.096899,18.1844,18.272099,18.36,18.4481,18.5364,18.624899,18.7136,18.802498,18.8916,18.980898,19.0704,19.160097,19.25,19.340101,19.430399,19.520903,19.611599,19.702501,19.7936,19.884901,19.976398,20.068102,20.16,20.252102,20.344398,20.436901,20.529598,20.622501,20.7156,20.8089,20.9024,20.996101,21.089998,21.184101,21.278399,21.3729,21.467598,21.5625,21.657602,21.7529,21.848402,21.9441,22.04,22.136099,22.2324,22.3289,22.425602,22.5225,22.619602,22.716898,22.814402,22.912098,23.01,23.108099,23.2064,23.3049,23.4036,23.502499,23.6016,23.700897,23.8004,23.900097]}];
            var layout = {&quot;title&quot;:&quot;Basis function for cavity&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;Distance&quot;,&quot;range&quot;:[0.0,5.0],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;Height&quot;,&quot;range&quot;:[-2.0,2.0],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;7237a768-b38f-4f34-977f-61d4ee198251&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;p&gt;We can combine this function with the, quite boring, function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y = 0&lt;/code&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt; operator to get something that already looks a lot like a crater&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;display(LinearPlotChart(x =&amp;gt; Math.Min(x * x - 1, 0.0f), &quot;First combination&quot;, &quot;Distance&quot;, &quot;Height&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;88a6a357-5af4-4ff9-a7fc-ceb70469fdc6&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0,1.01,1.02,1.03,1.04,1.05,1.06,1.07,1.08,1.09,1.1,1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19,1.2,1.21,1.22,1.23,1.24,1.25,1.26,1.27,1.28,1.29,1.3,1.31,1.32,1.33,1.34,1.35,1.36,1.37,1.38,1.39,1.4,1.41,1.42,1.43,1.44,1.45,1.46,1.47,1.48,1.49,1.5,1.51,1.52,1.53,1.54,1.55,1.56,1.57,1.58,1.59,1.6,1.61,1.62,1.63,1.64,1.65,1.66,1.67,1.68,1.69,1.7,1.71,1.72,1.73,1.74,1.75,1.76,1.77,1.78,1.79,1.8,1.81,1.82,1.83,1.84,1.85,1.86,1.87,1.88,1.89,1.9,1.91,1.92,1.93,1.94,1.95,1.96,1.97,1.98,1.99,2.0,2.01,2.02,2.03,2.04,2.05,2.06,2.07,2.08,2.09,2.1,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.2,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.3,2.31,2.32,2.33,2.34,2.35,2.36,2.37,2.38,2.39,2.4,2.41,2.42,2.43,2.44,2.45,2.46,2.47,2.48,2.49,2.5,2.51,2.52,2.53,2.54,2.55,2.56,2.57,2.58,2.59,2.6,2.61,2.62,2.63,2.64,2.65,2.66,2.67,2.68,2.69,2.7,2.71,2.72,2.73,2.74,2.75,2.76,2.77,2.78,2.79,2.8,2.81,2.82,2.83,2.84,2.85,2.86,2.87,2.88,2.89,2.9,2.91,2.92,2.93,2.94,2.95,2.96,2.97,2.98,2.99,3.0,3.01,3.02,3.03,3.04,3.05,3.06,3.07,3.08,3.09,3.1,3.11,3.12,3.13,3.14,3.15,3.16,3.17,3.18,3.19,3.2,3.21,3.22,3.23,3.24,3.25,3.26,3.27,3.28,3.29,3.3,3.31,3.32,3.33,3.34,3.35,3.36,3.37,3.38,3.39,3.4,3.41,3.42,3.43,3.44,3.45,3.46,3.47,3.48,3.49,3.5,3.51,3.52,3.53,3.54,3.55,3.56,3.57,3.58,3.59,3.6,3.61,3.62,3.63,3.64,3.65,3.66,3.67,3.68,3.69,3.7,3.71,3.72,3.73,3.74,3.75,3.76,3.77,3.78,3.79,3.8,3.81,3.82,3.83,3.84,3.85,3.86,3.87,3.88,3.89,3.9,3.91,3.92,3.93,3.94,3.95,3.96,3.97,3.98,3.99,4.0,4.01,4.02,4.03,4.04,4.05,4.06,4.07,4.08,4.09,4.1,4.11,4.12,4.13,4.14,4.15,4.16,4.17,4.18,4.19,4.2,4.21,4.22,4.23,4.24,4.25,4.26,4.27,4.28,4.29,4.3,4.31,4.32,4.33,4.34,4.35,4.36,4.37,4.38,4.39,4.4,4.41,4.42,4.43,4.44,4.45,4.46,4.47,4.48,4.49,4.5,4.51,4.52,4.53,4.54,4.55,4.56,4.57,4.58,4.59,4.6,4.61,4.62,4.63,4.64,4.65,4.66,4.67,4.68,4.69,4.7,4.71,4.72,4.73,4.74,4.75,4.76,4.77,4.78,4.79,4.8,4.81,4.82,4.83,4.84,4.85,4.86,4.87,4.88,4.89,4.9,4.91,4.92,4.93,4.94,4.95,4.96,4.97,4.98,4.99],&quot;y&quot;:[-1.0,-0.9999,-0.9996,-0.9991,-0.9984,-0.9975,-0.9964,-0.9951,-0.9936,-0.9919,-0.99,-0.9879,-0.9856,-0.9831,-0.9804,-0.9775,-0.9744,-0.9711,-0.9676,-0.96389997,-0.96,-0.9559,-0.9516,-0.9471,-0.9424,-0.9375,-0.9324,-0.9271,-0.9216,-0.9159,-0.90999997,-0.9039,-0.8976,-0.8911,-0.8844,-0.8775,-0.8704,-0.8631,-0.8556,-0.84790003,-0.84,-0.8319,-0.8236,-0.8151,-0.8064,-0.7975,-0.7884,-0.7791,-0.76960003,-0.7599,-0.75,-0.7399,-0.7296,-0.7191,-0.7084,-0.6975,-0.6864,-0.67509997,-0.6636,-0.65190005,-0.64,-0.6279,-0.6156,-0.6031,-0.5904,-0.57750005,-0.56439996,-0.5511,-0.5376,-0.52390003,-0.51,-0.49590003,-0.4816,-0.46709996,-0.45239997,-0.4375,-0.4224,-0.40710002,-0.39160007,-0.37589997,-0.35999995,-0.34390002,-0.3276,-0.3111,-0.29440004,-0.27749997,-0.2604,-0.24309999,-0.2256,-0.20790005,-0.19000006,-0.17189997,-0.15359998,-0.1351,-0.1164,-0.097500026,-0.078400016,-0.059099972,-0.039599955,-0.019899964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]}];
            var layout = {&quot;title&quot;:&quot;First combination&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;Distance&quot;,&quot;range&quot;:[0.0,5.0],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;Height&quot;,&quot;range&quot;:[-2.0,2.0],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;88a6a357-5af4-4ff9-a7fc-ceb70469fdc6&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;p&gt;We then comebine this function on more time, now with the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y = - 0.2&lt;/code&gt;, to limit the depth of the crater&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;const float depth = -0.2f;
display(LinearPlotChart(x =&amp;gt; Math.Max(Math.Min(x * x - 1, 0.0f), depth), &quot;Final cavity function&quot;, &quot;Distance&quot;, &quot;Height&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;a7336a0e-a9fb-47ad-86b8-eaf03b3bf516&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0,1.01,1.02,1.03,1.04,1.05,1.06,1.07,1.08,1.09,1.1,1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19,1.2,1.21,1.22,1.23,1.24,1.25,1.26,1.27,1.28,1.29,1.3,1.31,1.32,1.33,1.34,1.35,1.36,1.37,1.38,1.39,1.4,1.41,1.42,1.43,1.44,1.45,1.46,1.47,1.48,1.49,1.5,1.51,1.52,1.53,1.54,1.55,1.56,1.57,1.58,1.59,1.6,1.61,1.62,1.63,1.64,1.65,1.66,1.67,1.68,1.69,1.7,1.71,1.72,1.73,1.74,1.75,1.76,1.77,1.78,1.79,1.8,1.81,1.82,1.83,1.84,1.85,1.86,1.87,1.88,1.89,1.9,1.91,1.92,1.93,1.94,1.95,1.96,1.97,1.98,1.99,2.0,2.01,2.02,2.03,2.04,2.05,2.06,2.07,2.08,2.09,2.1,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.2,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.3,2.31,2.32,2.33,2.34,2.35,2.36,2.37,2.38,2.39,2.4,2.41,2.42,2.43,2.44,2.45,2.46,2.47,2.48,2.49,2.5,2.51,2.52,2.53,2.54,2.55,2.56,2.57,2.58,2.59,2.6,2.61,2.62,2.63,2.64,2.65,2.66,2.67,2.68,2.69,2.7,2.71,2.72,2.73,2.74,2.75,2.76,2.77,2.78,2.79,2.8,2.81,2.82,2.83,2.84,2.85,2.86,2.87,2.88,2.89,2.9,2.91,2.92,2.93,2.94,2.95,2.96,2.97,2.98,2.99,3.0,3.01,3.02,3.03,3.04,3.05,3.06,3.07,3.08,3.09,3.1,3.11,3.12,3.13,3.14,3.15,3.16,3.17,3.18,3.19,3.2,3.21,3.22,3.23,3.24,3.25,3.26,3.27,3.28,3.29,3.3,3.31,3.32,3.33,3.34,3.35,3.36,3.37,3.38,3.39,3.4,3.41,3.42,3.43,3.44,3.45,3.46,3.47,3.48,3.49,3.5,3.51,3.52,3.53,3.54,3.55,3.56,3.57,3.58,3.59,3.6,3.61,3.62,3.63,3.64,3.65,3.66,3.67,3.68,3.69,3.7,3.71,3.72,3.73,3.74,3.75,3.76,3.77,3.78,3.79,3.8,3.81,3.82,3.83,3.84,3.85,3.86,3.87,3.88,3.89,3.9,3.91,3.92,3.93,3.94,3.95,3.96,3.97,3.98,3.99,4.0,4.01,4.02,4.03,4.04,4.05,4.06,4.07,4.08,4.09,4.1,4.11,4.12,4.13,4.14,4.15,4.16,4.17,4.18,4.19,4.2,4.21,4.22,4.23,4.24,4.25,4.26,4.27,4.28,4.29,4.3,4.31,4.32,4.33,4.34,4.35,4.36,4.37,4.38,4.39,4.4,4.41,4.42,4.43,4.44,4.45,4.46,4.47,4.48,4.49,4.5,4.51,4.52,4.53,4.54,4.55,4.56,4.57,4.58,4.59,4.6,4.61,4.62,4.63,4.64,4.65,4.66,4.67,4.68,4.69,4.7,4.71,4.72,4.73,4.74,4.75,4.76,4.77,4.78,4.79,4.8,4.81,4.82,4.83,4.84,4.85,4.86,4.87,4.88,4.89,4.9,4.91,4.92,4.93,4.94,4.95,4.96,4.97,4.98,4.99],&quot;y&quot;:[-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.19000006,-0.17189997,-0.15359998,-0.1351,-0.1164,-0.097500026,-0.078400016,-0.059099972,-0.039599955,-0.019899964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]}];
            var layout = {&quot;title&quot;:&quot;Final cavity function&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;Distance&quot;,&quot;range&quot;:[0.0,5.0],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;Height&quot;,&quot;range&quot;:[-2.0,2.0],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;a7336a0e-a9fb-47ad-86b8-eaf03b3bf516&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;p&gt;When we visualize this shape on a circle it already looks quite good, but we’re not there yet.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;Func&amp;lt;float, float&amp;gt; craterShape = x =&amp;gt;
{
    var cavity  = x * x - 1;    
    var combined = Math.Min(cavity, 0.0f);
    return Math.Max(depth, combined);
};

var radians = 0.4f;
display(PlotAsteroid(craterShape, &quot;A circle with cavities&quot;, new Crater(Vector2.UnitY, 0.2f), new Crater(new Vector2((float)Math.Cos(radians), (float)Math.Sin(radians)), 0.1f)));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;53c0792f-1b54-4e97-947b-00ac1d68716e&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[1.0,0.99950653,0.9980267,0.99556196,0.9921147,0.98768836,0.9822872,0.97591674,0.96858317,0.96029365,0.7608452,0.7527046,0.7438212,0.7342037,0.72386163,0.7128052,0.87630665,0.860742,0.84432787,0.8270805,0.80901694,0.79015493,0.7705131,0.7501109,0.7289685,0.70710665,0.68454695,0.6613117,0.6374238,0.6129069,0.58778507,0.5620831,0.53582656,0.50904113,0.4817534,0.45399022,0.42577899,0.39714757,0.36812422,0.33873758,0.30901662,0.27899072,0.24868949,0.21814282,0.16595073,0.12514721,0.10026622,0.07528627,0.050232023,0.0251282,-4.1643884E-07,-0.025129035,-0.050232854,-0.075287096,-0.100267045,-0.12514804,-0.16595349,-0.21814384,-0.24869049,-0.27899173,-0.3090176,-0.33873853,-0.36812517,-0.39714852,-0.42577982,-0.45399103,-0.4817542,-0.50904197,-0.53582734,-0.5620839,-0.5877858,-0.6129076,-0.6374245,-0.6613124,-0.6845476,-0.7071073,-0.72896916,-0.7501116,-0.7705137,-0.7901555,-0.8090175,-0.827081,-0.84432834,-0.86074245,-0.8763071,-0.8910069,-0.9048274,-0.91775495,-0.9297768,-0.9408811,-0.9510568,-0.96029395,-0.9685834,-0.975917,-0.9822874,-0.9876885,-0.99211484,-0.9955621,-0.9980268,-0.9995066,-1.0,-0.99950653,-0.99802667,-0.99556184,-0.99211454,-0.9876882,-0.98228705,-0.9759165,-0.96858287,-0.96029335,-0.9510562,-0.94088036,-0.9297761,-0.9177542,-0.9048265,-0.891006,-0.87630606,-0.8607414,-0.8443273,-0.82707983,-0.8090162,-0.7901542,-0.7705124,-0.7501102,-0.7289677,-0.7071058,-0.6845461,-0.66131085,-0.6374231,-0.6129061,-0.5877843,-0.5620824,-0.5358258,-0.50904036,-0.4817526,-0.4539894,-0.42577815,-0.39714673,-0.36812335,-0.33873668,-0.30901575,-0.27898982,-0.2486886,-0.21814193,-0.18737997,-0.1564331,-0.12533185,-0.09410691,-0.062789105,-0.03140933,1.4424363E-06,0.031412214,0.06279199,0.09410979,0.12533471,0.15643595,0.1873828,0.21814473,0.24869138,0.2789926,0.3090185,0.3387394,0.36812603,0.39714935,0.42578077,0.45399195,0.4817551,0.50904286,0.53582823,0.5620848,0.5877866,0.6129084,0.6374253,0.6613132,0.6845484,0.707108,0.7289699,0.75011224,0.77051437,0.7901561,0.8090181,0.8270816,0.84432894,0.860743,0.8763076,0.89100736,0.90482783,0.91775537,0.9297772,0.94088143,0.95105714,0.96029425,0.96858364,0.9759172,0.98228765,0.98768866,0.99211496,0.99556214,0.99802685,0.99950665,1.0],&quot;y&quot;:[0.0,0.03141076,0.06279052,0.09410832,0.12533323,0.15643448,0.18738131,0.21814324,0.2486899,0.27899113,0.24721363,0.27099037,0.2944997,0.31771836,0.3406235,0.36319247,0.48175374,0.5090415,0.53582686,0.5620835,0.58778536,0.6129072,0.6374241,0.661312,0.68454725,0.70710695,0.7289688,0.7501112,0.7705134,0.7901552,0.8090171,0.8270807,0.8443281,0.86074215,0.87630683,0.89100665,0.9048272,0.91775477,0.9297766,0.9408809,0.95105666,0.96029377,0.9685833,0.97591686,0.8699463,0.79015076,0.7936918,0.7964496,0.79842144,0.7996053,0.8,0.79960525,0.7984213,0.79644954,0.7936917,0.7901506,0.86995584,0.9759166,0.968583,0.96029353,0.9510563,0.94088054,0.92977625,0.91775435,0.9048268,0.89100623,0.8763064,0.86074173,0.84432757,0.8270802,0.8090166,0.7901546,0.7705128,0.7501106,0.72896814,0.7071063,0.6845466,0.6613113,0.6374234,0.61290646,0.5877846,0.5620827,0.5358261,0.5090407,0.48175293,0.45398974,0.4257785,0.3971471,0.36812374,0.33873707,0.30901614,0.2789902,0.24868898,0.21814232,0.18738037,0.1564335,0.12533225,0.094107315,0.06278951,0.031409733,-1.0410971E-06,-0.03141181,-0.062791586,-0.094109386,-0.12533432,-0.15643555,-0.18738241,-0.21814434,-0.248691,-0.2789922,-0.3090181,-0.33873904,-0.36812568,-0.397149,-0.4257804,-0.4539916,-0.48175478,-0.5090425,-0.5358279,-0.56208444,-0.5877863,-0.61290807,-0.637425,-0.6613129,-0.6845481,-0.7071077,-0.7289696,-0.750112,-0.770514,-0.7901557,-0.8090177,-0.82708126,-0.8443286,-0.8607426,-0.87630725,-0.89100707,-0.9048276,-0.9177551,-0.92977697,-0.9408812,-0.9510569,-0.96029407,-0.96858346,-0.97591704,-0.9822875,-0.98768854,-0.9921149,-0.9955621,-0.9980268,-0.9995066,-1.0,-0.99950653,-0.9980266,-0.99556184,-0.99211454,-0.9876881,-0.982287,-0.97591645,-0.96858275,-0.96029323,-0.951056,-0.94088024,-0.9297759,-0.917754,-0.90482634,-0.89100575,-0.8763059,-0.8607412,-0.84432703,-0.82707965,-0.809016,-0.790154,-0.77051216,-0.7501099,-0.7289674,-0.7071055,-0.6845458,-0.66131055,-0.6374226,-0.6129056,-0.58778375,-0.5620819,-0.53582525,-0.5090398,-0.48175204,-0.45398882,-0.42577758,-0.39714614,-0.36812276,-0.3387361,-0.30901513,-0.27898923,-0.24868797,-0.2181413,-0.18737935,-0.15643246,-0.12533122,-0.09410628,-0.062788464,-0.03140869,0.0]}];
            var layout = {&quot;title&quot;:&quot;A circle with cavities&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;&quot;,&quot;range&quot;:[-1.2,1.2],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;&quot;,&quot;range&quot;:[-1.2,1.2],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;53c0792f-1b54-4e97-947b-00ac1d68716e&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;h2 id=&quot;generate-the-rim&quot;&gt;Generate the Rim&lt;/h2&gt;
&lt;p&gt;If you look at images of craters you see that they have a cavity, but also a rim around them, that is higher than the ground that is a bit further away. So we choose a function that starts high and slowly lowers.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;const float rimWidth = 3.0f;
const float rimSteepness = 0.02f;
display(LinearPlotChart(x =&amp;gt; ((x - rimWidth) * (x - rimWidth)) * rimSteepness, &quot;Basis function for rim&quot;, &quot;Distance&quot;, &quot;Height&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;ba84cb74-4a7d-48e6-a4e9-8da8d783a66f&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0,1.01,1.02,1.03,1.04,1.05,1.06,1.07,1.08,1.09,1.1,1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19,1.2,1.21,1.22,1.23,1.24,1.25,1.26,1.27,1.28,1.29,1.3,1.31,1.32,1.33,1.34,1.35,1.36,1.37,1.38,1.39,1.4,1.41,1.42,1.43,1.44,1.45,1.46,1.47,1.48,1.49,1.5,1.51,1.52,1.53,1.54,1.55,1.56,1.57,1.58,1.59,1.6,1.61,1.62,1.63,1.64,1.65,1.66,1.67,1.68,1.69,1.7,1.71,1.72,1.73,1.74,1.75,1.76,1.77,1.78,1.79,1.8,1.81,1.82,1.83,1.84,1.85,1.86,1.87,1.88,1.89,1.9,1.91,1.92,1.93,1.94,1.95,1.96,1.97,1.98,1.99,2.0,2.01,2.02,2.03,2.04,2.05,2.06,2.07,2.08,2.09,2.1,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.2,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.3,2.31,2.32,2.33,2.34,2.35,2.36,2.37,2.38,2.39,2.4,2.41,2.42,2.43,2.44,2.45,2.46,2.47,2.48,2.49,2.5,2.51,2.52,2.53,2.54,2.55,2.56,2.57,2.58,2.59,2.6,2.61,2.62,2.63,2.64,2.65,2.66,2.67,2.68,2.69,2.7,2.71,2.72,2.73,2.74,2.75,2.76,2.77,2.78,2.79,2.8,2.81,2.82,2.83,2.84,2.85,2.86,2.87,2.88,2.89,2.9,2.91,2.92,2.93,2.94,2.95,2.96,2.97,2.98,2.99,3.0,3.01,3.02,3.03,3.04,3.05,3.06,3.07,3.08,3.09,3.1,3.11,3.12,3.13,3.14,3.15,3.16,3.17,3.18,3.19,3.2,3.21,3.22,3.23,3.24,3.25,3.26,3.27,3.28,3.29,3.3,3.31,3.32,3.33,3.34,3.35,3.36,3.37,3.38,3.39,3.4,3.41,3.42,3.43,3.44,3.45,3.46,3.47,3.48,3.49,3.5,3.51,3.52,3.53,3.54,3.55,3.56,3.57,3.58,3.59,3.6,3.61,3.62,3.63,3.64,3.65,3.66,3.67,3.68,3.69,3.7,3.71,3.72,3.73,3.74,3.75,3.76,3.77,3.78,3.79,3.8,3.81,3.82,3.83,3.84,3.85,3.86,3.87,3.88,3.89,3.9,3.91,3.92,3.93,3.94,3.95,3.96,3.97,3.98,3.99,4.0,4.01,4.02,4.03,4.04,4.05,4.06,4.07,4.08,4.09,4.1,4.11,4.12,4.13,4.14,4.15,4.16,4.17,4.18,4.19,4.2,4.21,4.22,4.23,4.24,4.25,4.26,4.27,4.28,4.29,4.3,4.31,4.32,4.33,4.34,4.35,4.36,4.37,4.38,4.39,4.4,4.41,4.42,4.43,4.44,4.45,4.46,4.47,4.48,4.49,4.5,4.51,4.52,4.53,4.54,4.55,4.56,4.57,4.58,4.59,4.6,4.61,4.62,4.63,4.64,4.65,4.66,4.67,4.68,4.69,4.7,4.71,4.72,4.73,4.74,4.75,4.76,4.77,4.78,4.79,4.8,4.81,4.82,4.83,4.84,4.85,4.86,4.87,4.88,4.89,4.9,4.91,4.92,4.93,4.94,4.95,4.96,4.97,4.98,4.99],&quot;y&quot;:[0.17999999,0.17880198,0.17760798,0.17641799,0.17523201,0.17405,0.172872,0.17169802,0.17052801,0.16936201,0.16820002,0.167042,0.165888,0.16473798,0.163592,0.16244999,0.16131198,0.16017799,0.15904799,0.15792198,0.15679999,0.15568198,0.15456799,0.15345798,0.15235199,0.15124999,0.150152,0.149058,0.14796801,0.146882,0.14580001,0.144722,0.143648,0.142578,0.141512,0.14045,0.13939199,0.13833801,0.13728799,0.13624202,0.13519998,0.13416198,0.13312799,0.13209799,0.131072,0.13004999,0.12903199,0.12801799,0.12700799,0.126002,0.125,0.124001995,0.123008,0.122018,0.121032,0.12005,0.119072005,0.118098006,0.11712801,0.116162,0.115200005,0.11424199,0.11328801,0.112337984,0.11139201,0.11044999,0.109511994,0.108578,0.107647985,0.10672199,0.105799995,0.10488199,0.103967994,0.103057995,0.10215199,0.10125,0.100352,0.099457994,0.098568,0.097682,0.0968,0.095922,0.095048,0.094178006,0.093312,0.09245001,0.091591984,0.090738006,0.08988799,0.089042015,0.08819999,0.08736199,0.086527996,0.08569799,0.08487199,0.08404999,0.08323199,0.082417995,0.081608,0.080802,0.08,0.079202,0.078408,0.077618,0.076832004,0.076050006,0.075272,0.07449799,0.073727995,0.07296199,0.07219999,0.071442,0.070688,0.069938,0.069192,0.068450004,0.067712,0.066978,0.066248,0.06552199,0.064799994,0.064082,0.06336799,0.062658,0.061952,0.061249997,0.060552,0.059858,0.059168,0.058482002,0.057800002,0.057122,0.056447998,0.055777997,0.055111997,0.054449994,0.053792,0.053138,0.052487995,0.051842,0.051200002,0.050561998,0.049928002,0.049298003,0.048671994,0.048049998,0.047431998,0.046818,0.046207998,0.045601998,0.044999998,0.044401996,0.043808002,0.043218,0.042632002,0.042050004,0.041472,0.040898,0.040327996,0.039761998,0.039199997,0.038641997,0.038087998,0.037538,0.036992002,0.036450002,0.035912,0.035378,0.034848,0.034321997,0.033799995,0.033281997,0.032768,0.032257996,0.031751998,0.03125,0.030752,0.030258,0.029768001,0.029282002,0.028800001,0.028322002,0.027847998,0.027377998,0.026911996,0.026449999,0.025991999,0.025537997,0.025088,0.024642,0.0242,0.023762,0.023328,0.022898002,0.022471998,0.022049997,0.021631999,0.021217998,0.020807998,0.020402,0.02,0.019602,0.019208001,0.018818,0.018432,0.018050002,0.017672002,0.017298002,0.016928002,0.016562002,0.016200004,0.015842004,0.015488003,0.015137996,0.014791996,0.014449997,0.014111997,0.013777997,0.013447997,0.013121998,0.012799998,0.012481998,0.012167999,0.0118579995,0.0115519995,0.0112499995,0.0109520005,0.010658001,0.010368,0.010082,0.009800001,0.009522001,0.0092480015,0.008978002,0.008712002,0.008450002,0.008192003,0.007938003,0.007687997,0.0074419975,0.0071999975,0.0069619976,0.006727998,0.0064979983,0.006271999,0.006049999,0.0058319992,0.0056179995,0.0054079997,0.0052019996,0.005,0.0048020002,0.004608,0.0044180006,0.0042320006,0.004050001,0.0038720008,0.0036980012,0.0035280013,0.0033620014,0.0032000013,0.0030420017,0.0028880017,0.0027379983,0.0025919985,0.0024499986,0.0023119987,0.002177999,0.002047999,0.0019219993,0.0017999994,0.0016819995,0.0015679997,0.0014579998,0.0013519999,0.00125,0.001152,0.0010580001,0.0009680002,0.0008820003,0.0008000003,0.00072200043,0.00064800045,0.0005780005,0.0005120005,0.00045000057,0.0003920006,0.00033800057,0.00028799946,0.00024199953,0.00019999962,0.00016199969,0.00012799975,9.7999815E-05,7.1999864E-05,4.9999904E-05,3.1999938E-05,1.7999966E-05,7.9999845E-06,1.9999961E-06,0.0,1.9999961E-06,7.9999845E-06,1.7999966E-05,3.1999938E-05,4.9999904E-05,7.1999864E-05,9.7999815E-05,0.00012799975,0.00016199969,0.00019999962,0.00024199953,0.00028799946,0.00033800057,0.0003920006,0.00045000057,0.0005120005,0.0005780005,0.00064800045,0.00072200043,0.0008000003,0.0008820003,0.0009680002,0.0010580001,0.001152,0.00125,0.0013519999,0.0014579998,0.0015679997,0.0016819995,0.0017999994,0.0019219993,0.002047999,0.002177999,0.0023119987,0.0024499986,0.0025919985,0.0027379983,0.0028880017,0.0030420017,0.0032000013,0.0033620014,0.0035280013,0.0036980012,0.0038720008,0.004050001,0.0042320006,0.0044180006,0.004608,0.0048020002,0.005,0.0052019996,0.0054079997,0.0056179995,0.0058319992,0.006049999,0.006271999,0.0064979983,0.006727998,0.0069619976,0.0071999975,0.0074419975,0.007687997,0.007938003,0.008192003,0.008450002,0.008712002,0.008978002,0.0092480015,0.009522001,0.009800001,0.010082,0.010368,0.010658001,0.0109520005,0.0112499995,0.0115519995,0.0118579995,0.012167999,0.012481998,0.012799998,0.013121998,0.013447997,0.013777997,0.014111997,0.014449997,0.014791996,0.015137996,0.015488003,0.015842004,0.016200004,0.016562002,0.016928002,0.017298002,0.017672002,0.018050002,0.018432,0.018818,0.019208001,0.019602,0.02,0.020402009,0.020807998,0.02121801,0.021631999,0.022050008,0.022471998,0.022898005,0.023327997,0.023762006,0.024199996,0.024642004,0.025087995,0.025538005,0.025991993,0.026450004,0.026911993,0.027378002,0.02784799,0.028322002,0.02879999,0.029282002,0.02976799,0.030258,0.030751988,0.03125,0.031752013,0.032257996,0.03276801,0.033281997,0.03380001,0.034321997,0.03484801,0.035377994,0.035912007,0.036449995,0.036992006,0.037537992,0.038088005,0.03864199,0.039200004,0.03976199,0.040328,0.040897988,0.041472,0.04204999,0.042632002,0.043217987,0.043808002,0.044401985,0.044999998,0.045602012,0.046207998,0.04681801,0.047431998,0.048050012,0.048671994,0.049298007,0.04992799,0.05056201,0.05119999,0.051842008,0.05248799,0.053138006,0.05379199,0.054450005,0.05511199,0.055778,0.056447987,0.057122,0.057799987,0.058482002,0.059167985,0.059858,0.060551982,0.061249997,0.061952014,0.062658,0.063368015,0.064082,0.06480002,0.06552199,0.06624801,0.06697799,0.06771201,0.06844999,0.06919201,0.06993799,0.07068801,0.071441986,0.07220001,0.072961986,0.073728,0.07449798,0.075272,0.07604998,0.076832004,0.07761798,0.078408,0.07920198]}];
            var layout = {&quot;title&quot;:&quot;Basis function for rim&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;Distance&quot;,&quot;range&quot;:[0.0,5.0],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;Height&quot;,&quot;range&quot;:[-2.0,2.0],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;ba84cb74-4a7d-48e6-a4e9-8da8d783a66f&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;p&gt;Combining this function with the cavity function using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt; operator gives us a pleasing shape.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;Func&amp;lt;float, float&amp;gt; craterShape = x =&amp;gt;
{
    var cavity  = x * x - 1;
    var rimX = Math.Min(x - rimWidth, 0);
    var rim = (rimX * rimX) * rimSteepness;
    var combined = Math.Min(cavity, rim);
    return Math.Max(depth, combined);
};

var radians = 0.4f;
display(LinearPlotChart(craterShape, &quot;Combined cavity and rim function&quot;, &quot;Distance&quot;, &quot;Height&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;24627a8c-4d1f-4664-b233-bf1dcc3d1f04&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0,1.01,1.02,1.03,1.04,1.05,1.06,1.07,1.08,1.09,1.1,1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19,1.2,1.21,1.22,1.23,1.24,1.25,1.26,1.27,1.28,1.29,1.3,1.31,1.32,1.33,1.34,1.35,1.36,1.37,1.38,1.39,1.4,1.41,1.42,1.43,1.44,1.45,1.46,1.47,1.48,1.49,1.5,1.51,1.52,1.53,1.54,1.55,1.56,1.57,1.58,1.59,1.6,1.61,1.62,1.63,1.64,1.65,1.66,1.67,1.68,1.69,1.7,1.71,1.72,1.73,1.74,1.75,1.76,1.77,1.78,1.79,1.8,1.81,1.82,1.83,1.84,1.85,1.86,1.87,1.88,1.89,1.9,1.91,1.92,1.93,1.94,1.95,1.96,1.97,1.98,1.99,2.0,2.01,2.02,2.03,2.04,2.05,2.06,2.07,2.08,2.09,2.1,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.2,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.3,2.31,2.32,2.33,2.34,2.35,2.36,2.37,2.38,2.39,2.4,2.41,2.42,2.43,2.44,2.45,2.46,2.47,2.48,2.49,2.5,2.51,2.52,2.53,2.54,2.55,2.56,2.57,2.58,2.59,2.6,2.61,2.62,2.63,2.64,2.65,2.66,2.67,2.68,2.69,2.7,2.71,2.72,2.73,2.74,2.75,2.76,2.77,2.78,2.79,2.8,2.81,2.82,2.83,2.84,2.85,2.86,2.87,2.88,2.89,2.9,2.91,2.92,2.93,2.94,2.95,2.96,2.97,2.98,2.99,3.0,3.01,3.02,3.03,3.04,3.05,3.06,3.07,3.08,3.09,3.1,3.11,3.12,3.13,3.14,3.15,3.16,3.17,3.18,3.19,3.2,3.21,3.22,3.23,3.24,3.25,3.26,3.27,3.28,3.29,3.3,3.31,3.32,3.33,3.34,3.35,3.36,3.37,3.38,3.39,3.4,3.41,3.42,3.43,3.44,3.45,3.46,3.47,3.48,3.49,3.5,3.51,3.52,3.53,3.54,3.55,3.56,3.57,3.58,3.59,3.6,3.61,3.62,3.63,3.64,3.65,3.66,3.67,3.68,3.69,3.7,3.71,3.72,3.73,3.74,3.75,3.76,3.77,3.78,3.79,3.8,3.81,3.82,3.83,3.84,3.85,3.86,3.87,3.88,3.89,3.9,3.91,3.92,3.93,3.94,3.95,3.96,3.97,3.98,3.99,4.0,4.01,4.02,4.03,4.04,4.05,4.06,4.07,4.08,4.09,4.1,4.11,4.12,4.13,4.14,4.15,4.16,4.17,4.18,4.19,4.2,4.21,4.22,4.23,4.24,4.25,4.26,4.27,4.28,4.29,4.3,4.31,4.32,4.33,4.34,4.35,4.36,4.37,4.38,4.39,4.4,4.41,4.42,4.43,4.44,4.45,4.46,4.47,4.48,4.49,4.5,4.51,4.52,4.53,4.54,4.55,4.56,4.57,4.58,4.59,4.6,4.61,4.62,4.63,4.64,4.65,4.66,4.67,4.68,4.69,4.7,4.71,4.72,4.73,4.74,4.75,4.76,4.77,4.78,4.79,4.8,4.81,4.82,4.83,4.84,4.85,4.86,4.87,4.88,4.89,4.9,4.91,4.92,4.93,4.94,4.95,4.96,4.97,4.98,4.99],&quot;y&quot;:[-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.19000006,-0.17189997,-0.15359998,-0.1351,-0.1164,-0.097500026,-0.078400016,-0.059099972,-0.039599955,-0.019899964,0.0,0.020099998,0.04039991,0.060899973,0.076832004,0.076050006,0.075272,0.07449799,0.073727995,0.07296199,0.07219999,0.071442,0.070688,0.069938,0.069192,0.068450004,0.067712,0.066978,0.066248,0.06552199,0.064799994,0.064082,0.06336799,0.062658,0.061952,0.061249997,0.060552,0.059858,0.059168,0.058482002,0.057800002,0.057122,0.056447998,0.055777997,0.055111997,0.054449994,0.053792,0.053138,0.052487995,0.051842,0.051200002,0.050561998,0.049928002,0.049298003,0.048671994,0.048049998,0.047431998,0.046818,0.046207998,0.045601998,0.044999998,0.044401996,0.043808002,0.043218,0.042632002,0.042050004,0.041472,0.040898,0.040327996,0.039761998,0.039199997,0.038641997,0.038087998,0.037538,0.036992002,0.036450002,0.035912,0.035378,0.034848,0.034321997,0.033799995,0.033281997,0.032768,0.032257996,0.031751998,0.03125,0.030752,0.030258,0.029768001,0.029282002,0.028800001,0.028322002,0.027847998,0.027377998,0.026911996,0.026449999,0.025991999,0.025537997,0.025088,0.024642,0.0242,0.023762,0.023328,0.022898002,0.022471998,0.022049997,0.021631999,0.021217998,0.020807998,0.020402,0.02,0.019602,0.019208001,0.018818,0.018432,0.018050002,0.017672002,0.017298002,0.016928002,0.016562002,0.016200004,0.015842004,0.015488003,0.015137996,0.014791996,0.014449997,0.014111997,0.013777997,0.013447997,0.013121998,0.012799998,0.012481998,0.012167999,0.0118579995,0.0115519995,0.0112499995,0.0109520005,0.010658001,0.010368,0.010082,0.009800001,0.009522001,0.0092480015,0.008978002,0.008712002,0.008450002,0.008192003,0.007938003,0.007687997,0.0074419975,0.0071999975,0.0069619976,0.006727998,0.0064979983,0.006271999,0.006049999,0.0058319992,0.0056179995,0.0054079997,0.0052019996,0.005,0.0048020002,0.004608,0.0044180006,0.0042320006,0.004050001,0.0038720008,0.0036980012,0.0035280013,0.0033620014,0.0032000013,0.0030420017,0.0028880017,0.0027379983,0.0025919985,0.0024499986,0.0023119987,0.002177999,0.002047999,0.0019219993,0.0017999994,0.0016819995,0.0015679997,0.0014579998,0.0013519999,0.00125,0.001152,0.0010580001,0.0009680002,0.0008820003,0.0008000003,0.00072200043,0.00064800045,0.0005780005,0.0005120005,0.00045000057,0.0003920006,0.00033800057,0.00028799946,0.00024199953,0.00019999962,0.00016199969,0.00012799975,9.7999815E-05,7.1999864E-05,4.9999904E-05,3.1999938E-05,1.7999966E-05,7.9999845E-06,1.9999961E-06,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]}];
            var layout = {&quot;title&quot;:&quot;Combined cavity and rim function&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;Distance&quot;,&quot;range&quot;:[0.0,5.0],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;Height&quot;,&quot;range&quot;:[-2.0,2.0],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;24627a8c-4d1f-4664-b233-bf1dcc3d1f04&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;p&gt;And it looks even better when applied to a circle!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;display(PlotAsteroid(craterShape, &quot;Combined function to generate craters&quot;, new Crater(Vector2.UnitY, 0.1f), new Crater(new Vector2((float)Math.Cos(radians), (float)Math.Sin(radians)), 0.1f)));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;7ccdb1c7-a024-41a5-948c-a62d558c5a8b&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[1.0,0.99950653,0.9980267,0.99556196,0.99351054,0.99425966,0.99781007,1.0040957,1.0130244,1.024479,0.7608452,0.7527046,0.7438212,0.7342037,0.72386163,0.7128052,0.9226437,0.9081961,0.8749679,0.8447712,0.8174461,0.79281074,0.7706635,0.7501109,0.7289685,0.70710665,0.68454695,0.6613117,0.6374238,0.6129069,0.58778507,0.5620831,0.53582656,0.50904113,0.4817534,0.45399022,0.42577899,0.39714757,0.36812422,0.33873758,0.30901662,0.2791755,0.24990003,0.22097228,0.19206376,0.16283922,0.13295856,0.08352993,0.050232023,0.0251282,-4.1643884E-07,-0.025129035,-0.050232854,-0.0835327,-0.13295956,-0.16284019,-0.19206473,-0.22097325,-0.24990097,-0.27917647,-0.3090176,-0.33873853,-0.36812517,-0.39714852,-0.42577982,-0.45399103,-0.4817542,-0.50904197,-0.53582734,-0.5620839,-0.5877858,-0.6129076,-0.6374245,-0.6613124,-0.6845476,-0.7071073,-0.72896916,-0.7501116,-0.7705137,-0.7901555,-0.8090175,-0.827081,-0.84432834,-0.86074245,-0.8763071,-0.8910069,-0.9048274,-0.91775495,-0.9297768,-0.9408811,-0.9510568,-0.96029395,-0.9685834,-0.975917,-0.9822874,-0.9876885,-0.99211484,-0.9955621,-0.9980268,-0.9995066,-1.0,-0.99950653,-0.99802667,-0.99556184,-0.99211454,-0.9876882,-0.98228705,-0.9759165,-0.96858287,-0.96029335,-0.9510562,-0.94088036,-0.9297761,-0.9177542,-0.9048265,-0.891006,-0.87630606,-0.8607414,-0.8443273,-0.82707983,-0.8090162,-0.7901542,-0.7705124,-0.7501102,-0.7289677,-0.7071058,-0.6845461,-0.66131085,-0.6374231,-0.6129061,-0.5877843,-0.5620824,-0.5358258,-0.50904036,-0.4817526,-0.4539894,-0.42577815,-0.39714673,-0.36812335,-0.33873668,-0.30901575,-0.27898982,-0.2486886,-0.21814193,-0.18737997,-0.1564331,-0.12533185,-0.09410691,-0.062789105,-0.03140933,1.4424363E-06,0.031412214,0.06279199,0.09410979,0.12533471,0.15643595,0.1873828,0.21814473,0.24869138,0.2789926,0.3090185,0.3387394,0.36812603,0.39714935,0.42578077,0.45399195,0.4817551,0.50904286,0.53582823,0.5620848,0.5877866,0.6129084,0.6374253,0.6613132,0.6845484,0.707108,0.7289699,0.75011224,0.77051437,0.7901561,0.8090181,0.8270816,0.84432894,0.860743,0.8763076,0.89100736,0.90482783,0.91775537,0.9297772,0.94088143,0.95105714,0.96029425,0.96858364,0.9759172,0.98228765,0.98768866,0.99211496,0.99556214,0.99802685,0.99950665,1.0],&quot;y&quot;:[0.0,0.03141076,0.06279052,0.09410832,0.12550956,0.15747526,0.19034246,0.22444198,0.2601005,0.2976387,0.24721363,0.27099037,0.2944997,0.31771836,0.3406235,0.36319247,0.5072278,0.5371058,0.5552716,0.5741061,0.5939095,0.6149672,0.6375485,0.661312,0.68454725,0.70710695,0.7289688,0.7501112,0.7705134,0.7901552,0.8090171,0.8270807,0.8443281,0.86074215,0.87630683,0.89100665,0.9048272,0.91775477,0.9297766,0.9408809,0.95105666,0.9609298,0.973298,0.98857516,1.0068359,1.0281293,1.0524793,0.8836588,0.79842144,0.7996053,0.8,0.79960525,0.7984213,0.8836783,1.0524784,1.0281286,1.0068353,0.9885747,0.9732975,0.96092945,0.9510563,0.94088054,0.92977625,0.91775435,0.9048268,0.89100623,0.8763064,0.86074173,0.84432757,0.8270802,0.8090166,0.7901546,0.7705128,0.7501106,0.72896814,0.7071063,0.6845466,0.6613113,0.6374234,0.61290646,0.5877846,0.5620827,0.5358261,0.5090407,0.48175293,0.45398974,0.4257785,0.3971471,0.36812374,0.33873707,0.30901614,0.2789902,0.24868898,0.21814232,0.18738037,0.1564335,0.12533225,0.094107315,0.06278951,0.031409733,-1.0410971E-06,-0.03141181,-0.062791586,-0.094109386,-0.12533432,-0.15643555,-0.18738241,-0.21814434,-0.248691,-0.2789922,-0.3090181,-0.33873904,-0.36812568,-0.397149,-0.4257804,-0.4539916,-0.48175478,-0.5090425,-0.5358279,-0.56208444,-0.5877863,-0.61290807,-0.637425,-0.6613129,-0.6845481,-0.7071077,-0.7289696,-0.750112,-0.770514,-0.7901557,-0.8090177,-0.82708126,-0.8443286,-0.8607426,-0.87630725,-0.89100707,-0.9048276,-0.9177551,-0.92977697,-0.9408812,-0.9510569,-0.96029407,-0.96858346,-0.97591704,-0.9822875,-0.98768854,-0.9921149,-0.9955621,-0.9980268,-0.9995066,-1.0,-0.99950653,-0.9980266,-0.99556184,-0.99211454,-0.9876881,-0.982287,-0.97591645,-0.96858275,-0.96029323,-0.951056,-0.94088024,-0.9297759,-0.917754,-0.90482634,-0.89100575,-0.8763059,-0.8607412,-0.84432703,-0.82707965,-0.809016,-0.790154,-0.77051216,-0.7501099,-0.7289674,-0.7071055,-0.6845458,-0.66131055,-0.6374226,-0.6129056,-0.58778375,-0.5620819,-0.53582525,-0.5090398,-0.48175204,-0.45398882,-0.42577758,-0.39714614,-0.36812276,-0.3387361,-0.30901513,-0.27898923,-0.24868797,-0.2181413,-0.18737935,-0.15643246,-0.12533122,-0.09410628,-0.062788464,-0.03140869,0.0]}];
            var layout = {&quot;title&quot;:&quot;Combined function to generate craters&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;&quot;,&quot;range&quot;:[-1.2,1.2],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;&quot;,&quot;range&quot;:[-1.2,1.2],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;7ccdb1c7-a024-41a5-948c-a62d558c5a8b&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;h1 id=&quot;smooth-the-functions&quot;&gt;Smooth the functions&lt;/h1&gt;
&lt;p&gt;Using the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt; operators gives a few quite abrubt transitions. We can smooth these transitions using the techniques described &lt;a href=&quot;https://iquilezles.org/www/articles/smin/smin.htm&quot;&gt;here&lt;/a&gt;. Note that beacuse we use a polynomal smoothing algorithm there’s no beginning or end to the smoothing (as you would have with a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lerp&lt;/code&gt;) so our whole circle becomes slightly larger as a result.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;const float smoothing = 0.5f;

public float SmoothMin(float a, float b, float k) 
{
    k = Math.Max(0, k);
    float h = Math.Max(0, Math.Min(1, (b - a + k) / (2 * k)));
    return a * h + b * (1 - h) - k * h * (1 - h);
}

public float SmoothMax(float a, float b, float k) 
{
    k = Math.Min(0, -k);
    float h = Math.Max(0, Math.Min(1, (b - a + k) / (2 * k)));
    return a * h + b * (1 - h) - k * h * (1 - h);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;Func&amp;lt;float, float&amp;gt; craterShape = x =&amp;gt;
{
    var cavity  = x * x - 1;
    var rimX = Math.Min(x - rimWidth, 0);
    var rim = (rimX * rimX) * rimSteepness;
    var combined = SmoothMin(cavity, rim, smoothing);        
    return SmoothMax(depth, combined, smoothing);
};

var radians = 0.4f;
display(LinearPlotChart(craterShape, &quot;Function&quot;, &quot;Distance&quot;, &quot;Height&quot;));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;5eb1494f-48e6-4f1d-aae1-5ee6461e6e54&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[0.0,0.01,0.02,0.03,0.04,0.05,0.06,0.07,0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,0.19,0.2,0.21,0.22,0.23,0.24,0.25,0.26,0.27,0.28,0.29,0.3,0.31,0.32,0.33,0.34,0.35,0.36,0.37,0.38,0.39,0.4,0.41,0.42,0.43,0.44,0.45,0.46,0.47,0.48,0.49,0.5,0.51,0.52,0.53,0.54,0.55,0.56,0.57,0.58,0.59,0.6,0.61,0.62,0.63,0.64,0.65,0.66,0.67,0.68,0.69,0.7,0.71,0.72,0.73,0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83,0.84,0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94,0.95,0.96,0.97,0.98,0.99,1.0,1.01,1.02,1.03,1.04,1.05,1.06,1.07,1.08,1.09,1.1,1.11,1.12,1.13,1.14,1.15,1.16,1.17,1.18,1.19,1.2,1.21,1.22,1.23,1.24,1.25,1.26,1.27,1.28,1.29,1.3,1.31,1.32,1.33,1.34,1.35,1.36,1.37,1.38,1.39,1.4,1.41,1.42,1.43,1.44,1.45,1.46,1.47,1.48,1.49,1.5,1.51,1.52,1.53,1.54,1.55,1.56,1.57,1.58,1.59,1.6,1.61,1.62,1.63,1.64,1.65,1.66,1.67,1.68,1.69,1.7,1.71,1.72,1.73,1.74,1.75,1.76,1.77,1.78,1.79,1.8,1.81,1.82,1.83,1.84,1.85,1.86,1.87,1.88,1.89,1.9,1.91,1.92,1.93,1.94,1.95,1.96,1.97,1.98,1.99,2.0,2.01,2.02,2.03,2.04,2.05,2.06,2.07,2.08,2.09,2.1,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.2,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.3,2.31,2.32,2.33,2.34,2.35,2.36,2.37,2.38,2.39,2.4,2.41,2.42,2.43,2.44,2.45,2.46,2.47,2.48,2.49,2.5,2.51,2.52,2.53,2.54,2.55,2.56,2.57,2.58,2.59,2.6,2.61,2.62,2.63,2.64,2.65,2.66,2.67,2.68,2.69,2.7,2.71,2.72,2.73,2.74,2.75,2.76,2.77,2.78,2.79,2.8,2.81,2.82,2.83,2.84,2.85,2.86,2.87,2.88,2.89,2.9,2.91,2.92,2.93,2.94,2.95,2.96,2.97,2.98,2.99,3.0,3.01,3.02,3.03,3.04,3.05,3.06,3.07,3.08,3.09,3.1,3.11,3.12,3.13,3.14,3.15,3.16,3.17,3.18,3.19,3.2,3.21,3.22,3.23,3.24,3.25,3.26,3.27,3.28,3.29,3.3,3.31,3.32,3.33,3.34,3.35,3.36,3.37,3.38,3.39,3.4,3.41,3.42,3.43,3.44,3.45,3.46,3.47,3.48,3.49,3.5,3.51,3.52,3.53,3.54,3.55,3.56,3.57,3.58,3.59,3.6,3.61,3.62,3.63,3.64,3.65,3.66,3.67,3.68,3.69,3.7,3.71,3.72,3.73,3.74,3.75,3.76,3.77,3.78,3.79,3.8,3.81,3.82,3.83,3.84,3.85,3.86,3.87,3.88,3.89,3.9,3.91,3.92,3.93,3.94,3.95,3.96,3.97,3.98,3.99,4.0,4.01,4.02,4.03,4.04,4.05,4.06,4.07,4.08,4.09,4.1,4.11,4.12,4.13,4.14,4.15,4.16,4.17,4.18,4.19,4.2,4.21,4.22,4.23,4.24,4.25,4.26,4.27,4.28,4.29,4.3,4.31,4.32,4.33,4.34,4.35,4.36,4.37,4.38,4.39,4.4,4.41,4.42,4.43,4.44,4.45,4.46,4.47,4.48,4.49,4.5,4.51,4.52,4.53,4.54,4.55,4.56,4.57,4.58,4.59,4.6,4.61,4.62,4.63,4.64,4.65,4.66,4.67,4.68,4.69,4.7,4.71,4.72,4.73,4.74,4.75,4.76,4.77,4.78,4.79,4.8,4.81,4.82,4.83,4.84,4.85,4.86,4.87,4.88,4.89,4.9,4.91,4.92,4.93,4.94,4.95,4.96,4.97,4.98,4.99],&quot;y&quot;:[-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.2,-0.19999689,-0.19990753,-0.19969,-0.19933753,-0.19884321,-0.19820002,-0.19740078,-0.19643831,-0.1953052,-0.19399393,-0.1924969,-0.19080633,-0.18891439,-0.18681312,-0.18449439,-0.18194999,-0.17917162,-0.17615071,-0.1728788,-0.1693471,-0.1655469,-0.16146913,-0.15710479,-0.15245962,-0.1475926,-0.14251682,-0.13723955,-0.13176876,-0.126113,-0.12028148,-0.11428397,-0.10813095,-0.10183337,-0.09540284,-0.08885157,-0.0821923,-0.075438306,-0.06860357,-0.061702445,-0.054749846,-0.04776127,-0.040752552,-0.033740066,-0.026740685,-0.019771583,-0.012850389,-0.0059950054,0.0007762164,0.0074448064,0.013991833,0.020398296,0.026644997,0.032712623,0.038581587,0.04423246,0.049645733,0.05480198,0.059681877,0.06426621,0.06853609,0.07247279,0.076058015,0.079273894,0.082102954,0.08452842,0.08653395,0.088104114,0.08922416,0.08988026,0.09005954,0.08975078,0.089219674,0.088692084,0.08816803,0.08764747,0.08713042,0.086616874,0.08610679,0.0856002,0.08509706,0.084597394,0.084101185,0.08360842,0.083119094,0.0826332,0.08215072,0.081671655,0.081196,0.08072374,0.08025488,0.079789385,0.07932729,0.07886857,0.07841319,0.07796117,0.077512495,0.07706717,0.07662518,0.07618649,0.07575115,0.075319104,0.07489036,0.07446492,0.07404277,0.07362391,0.07320832,0.07279599,0.07238695,0.07198114,0.07157861,0.07117931,0.07078323,0.0703904,0.07000079,0.069614395,0.06923121,0.06885123,0.06847447,0.068100885,0.067730494,0.06736328,0.06699924,0.06663838,0.06628068,0.06592612,0.06557472,0.06522647,0.064881355,0.06453937,0.064200535,0.0638648,0.06353219,0.063202694,0.06287631,0.06255302,0.062232822,0.06191572,0.0616017,0.061290756,0.060982894,0.060678095,0.060376376,0.060077704,0.059782088,0.059489522,0.059200007,0.05891352,0.05863007,0.05834966,0.058072265,0.0577979,0.057526555,0.05725822,0.056992877,0.056730554,0.05647122,0.056214884,0.055961538,0.05571118,0.055463802,0.0552194,0.054977972,0.054739513,0.054504022,0.054271493,0.054041926,0.053815294,0.05359162,0.05337091,0.053153127,0.052938282,0.052726373,0.05251739,0.052311353,0.052108224,0.051908016,0.051710732,0.051516365,0.051324904,0.051136345,0.0509507,0.05076796,0.050588105,0.050411146,0.050237086,0.050065916,0.04989763,0.04973223,0.049569715,0.049410067,0.049253307,0.049099404,0.048948385,0.04880022,0.048654933,0.048512496,0.048372936,0.048236217,0.04810236,0.047971353,0.0478432,0.04771789,0.047595445,0.047475822,0.04735905,0.047245115,0.047134034,0.047025766,0.046920344,0.046817757,0.046718,0.046621077,0.046526972,0.046435695,0.046347246,0.04626162,0.046178807,0.046098832,0.04602166,0.04594731,0.04587578,0.04580706,0.04574116,0.04567807,0.04561779,0.045560323,0.045505658,0.045453805,0.045404766,0.04535853,0.0453151,0.045274474,0.045236655,0.04520164,0.04516943,0.045140017,0.04511341,0.045089606,0.04506861,0.045050405,0.045035,0.045022395,0.0450126,0.0450056,0.0450014,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045,0.045]}];
            var layout = {&quot;title&quot;:&quot;Function&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;Distance&quot;,&quot;range&quot;:[0.0,5.0],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;Height&quot;,&quot;range&quot;:[-2.0,2.0],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;5eb1494f-48e6-4f1d-aae1-5ee6461e6e54&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;p&gt;Applying this function to our circle gives our final result.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C#&quot;&gt;display(PlotAsteroid(craterShape, &quot;Asteroid&quot;, new Crater(Vector2.UnitY, 0.1f), new Crater(new Vector2((float)Math.Cos(radians), (float)Math.Sin(radians)), 0.1f)));
&lt;/code&gt;&lt;/pre&gt;

&lt;div id=&quot;a57d11bb-bab7-4936-a875-dc50da22ef4c&quot; style=&quot;width: 400px; height: 400px;&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;

var renderPlotly = function() {
    var xplotRequire = require.config({context:&apos;xplot-3.0.1&apos;,paths:{plotly:&apos;https://roy-t.nl/files/plotly&apos;}}) || require;
    xplotRequire([&apos;plotly&apos;], function(Plotly) {

            var data = [{&quot;type&quot;:&quot;scatter&quot;,&quot;x&quot;:[1.09,1.0894622,1.0878491,1.0851625,1.0823832,1.081202,1.0816817,1.0838813,1.0878842,1.0801768,0.88991815,0.7950443,0.78566116,0.7755027,0.7645788,0.7720424,0.9199961,0.97273475,0.94232136,0.91409045,0.8877728,0.8631324,0.8399645,0.81762093,0.7945757,0.7707463,0.7461562,0.7208298,0.694792,0.6680685,0.64068574,0.6126706,0.58405095,0.55485487,0.52511126,0.49484935,0.4640991,0.43289086,0.4012554,0.36922398,0.3368281,0.3042293,0.27192187,0.23977466,0.2075817,0.17512785,0.14218275,0.09332977,0.05333882,0.026541663,-4.3986356E-07,-0.026542544,-0.05333978,-0.09333148,-0.14218387,-0.17512892,-0.20758277,-0.23977572,-0.27192292,-0.30423036,-0.3368292,-0.369225,-0.40125644,-0.4328919,-0.4641,-0.49485022,-0.5251121,-0.55485576,-0.5840518,-0.6126715,-0.6406865,-0.6680693,-0.69479275,-0.72083056,-0.74615693,-0.770747,-0.7945764,-0.81762165,-0.83985996,-0.8612695,-0.8818291,-0.90151834,-0.92031795,-0.9382093,-0.95517474,-0.97119755,-0.9862619,-1.000353,-1.0134567,-1.0255604,-1.036652,-1.0467204,-1.055756,-1.0637496,-1.0706933,-1.0765805,-1.0814052,-1.0851626,-1.0878493,-1.0894622,-1.09,-1.0894622,-1.0878491,-1.0851624,-1.0814049,-1.0765802,-1.0706929,-1.0637491,-1.0557554,-1.0467198,-1.0366513,-1.0255597,-1.013456,-1.000352,-0.98626095,-0.97119653,-0.9551736,-0.9382081,-0.92031676,-0.90151703,-0.8818277,-0.8612681,-0.83985853,-0.81762016,-0.79457486,-0.77074534,-0.74615526,-0.72082883,-0.6947912,-0.6680677,-0.6406849,-0.6126698,-0.5840501,-0.554854,-0.52511036,-0.49484846,-0.4640982,-0.43288994,-0.40125448,-0.369223,-0.3368272,-0.3040989,-0.27107057,-0.23777471,-0.20424418,-0.1705121,-0.13661171,-0.10257654,-0.068440124,-0.03423617,1.5722557E-06,0.034239314,0.06844327,0.102579676,0.13661484,0.1705152,0.20424727,0.23777777,0.2710736,0.30410194,0.33683017,0.36922595,0.4012574,0.4328928,0.46410105,0.49485123,0.5251131,0.5548567,0.5840528,0.61267245,0.6406874,0.6680702,0.6947936,0.7208314,0.74615777,0.7707478,0.7945772,0.81762236,0.8398607,0.8612702,0.88182974,0.901519,0.92031854,0.9382099,0.95517534,0.9711981,0.9862624,1.0003533,1.0134572,1.0255607,1.0366523,1.0467207,1.0557562,1.0637498,1.0706936,1.0765806,1.0814053,1.0851628,1.0878493,1.0894623,1.09],&quot;y&quot;:[0.0,0.03423773,0.06844167,0.102578074,0.1367368,0.17124559,0.20634182,0.24227618,0.2793212,0.31382042,0.289152,0.2862336,0.3110653,0.33559003,0.3597836,0.39337534,0.5057722,0.5752739,0.5980154,0.6212154,0.64500487,0.66951436,0.6948793,0.7208301,0.7461565,0.7707466,0.794576,0.81762123,0.83985966,0.8612692,0.88182867,0.90151805,0.92031765,0.938209,0.9551745,0.97119725,0.98626167,1.0003527,1.0134566,1.0255603,1.0366518,1.0471656,1.0590676,1.0726924,1.088184,1.105717,1.1254966,0.9873309,0.84780294,0.8445831,0.845,0.84458303,0.84780407,0.987338,1.125496,1.1057163,1.0881835,1.0726918,1.0590671,1.0471653,1.0366514,1.0255598,1.0134561,1.0003523,0.98626125,0.97119683,0.955174,0.9382085,0.92031705,0.90151745,0.8818281,0.8612685,0.839859,0.81762064,0.7945753,0.7707459,0.7461558,0.72082937,0.6947915,0.66806805,0.6406852,0.6126702,0.5840505,0.5548544,0.5251107,0.49484885,0.4640986,0.43289033,0.4012549,0.36922342,0.3368276,0.30409935,0.271071,0.23777513,0.20424461,0.17051251,0.13661216,0.10257698,0.068440564,0.03423661,-1.1347959E-06,-0.034238875,-0.06844283,-0.102579236,-0.13661441,-0.17051475,-0.20424683,-0.23777734,-0.2710732,-0.30410153,-0.33682975,-0.36922556,-0.401257,-0.4328924,-0.46410063,-0.49485084,-0.52511275,-0.55485636,-0.5840524,-0.61267203,-0.6406871,-0.66806984,-0.6947933,-0.72083104,-0.7461574,-0.7707474,-0.7945769,-0.8176221,-0.8398603,-0.8612698,-0.8818293,-0.9015186,-0.9203182,-0.9382095,-0.9551749,-0.9711977,-0.9862621,-1.0003531,-1.013457,-1.0255605,-1.0366521,-1.0467206,-1.055756,-1.0637496,-1.0706935,-1.0765805,-1.0814053,-1.0851626,-1.0878493,-1.0894622,-1.09,-1.0894622,-1.087849,-1.0851624,-1.0814049,-1.07658,-1.0706929,-1.063749,-1.0557553,-1.0467197,-1.0366511,-1.0255595,-1.0134557,-1.0003519,-0.9862608,-0.9711963,-0.95517343,-0.9382079,-0.9203165,-0.90151685,-0.8818275,-0.86126786,-0.8398583,-0.8176198,-0.7945745,-0.77074504,-0.74615496,-0.72082853,-0.69479066,-0.66806716,-0.6406843,-0.6126693,-0.5840495,-0.55485344,-0.5251097,-0.49484783,-0.4640976,-0.4328893,-0.40125382,-0.36922234,-0.3368265,-0.30409828,-0.27106988,-0.23777403,-0.2042435,-0.1705114,-0.13661104,-0.102575846,-0.06843943,-0.034235474,0.0]}];
            var layout = {&quot;title&quot;:&quot;Asteroid&quot;,&quot;xaxis&quot;:{&quot;title&quot;:&quot;&quot;,&quot;range&quot;:[-1.2,1.2],&quot;_isSubplotObj&quot;:true},&quot;yaxis&quot;:{&quot;title&quot;:&quot;&quot;,&quot;range&quot;:[-1.2,1.2],&quot;_isSubplotObj&quot;:true}};
            Plotly.newPlot(&apos;a57d11bb-bab7-4936-a875-dc50da22ef4c&apos;, data, layout);
        
});
};
if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {
    var script = document.createElement(&quot;script&quot;); 
    script.setAttribute(&quot;src&quot;, &quot;https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js&quot;);
    script.onload = function(){
        renderPlotly();
    };
    document.getElementsByTagName(&quot;head&quot;)[0].appendChild(script); 
}
else {
    renderPlotly();
}
&lt;/script&gt;

&lt;p&gt;I’ve used this technique in my open-source &lt;a href=&quot;https://github.com/roy-t/MiniRTS&quot;&gt;3D Engine&lt;/a&gt; where it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://roy-t.nl/files/crater.PNG&quot; alt=&quot;Sample&quot; /&gt;&lt;/p&gt;

</description>
        <pubDate>Sun, 09 Aug 2020 11:28:00 +0000</pubDate>
        <link>https://roy-t.nl/2020/08/09/Asteroids.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2020/08/09/Asteroids.html</guid>
        
        
      </item>
    
      <item>
        <title>The magic of real-time rendering in games</title>
        <description>&lt;p&gt;I’ve now been working at Bol.com (basically the Dutch version of Amazon) for 18 months. In that time I’ve not worked professionally on games. But in my spare time I’ve been tinkering on a game engine &lt;a href=&quot;https://github.com/roy-t/MiniRTS&quot;&gt;Check it out on GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Working on the back-end systems of an e-tailer is a very different experience than work on games. At our yearly conference, Spaces Summit, I talked to my colleagues about how games work, and what the differences are with the work I do daily. I’m very proud of this talk. I think it was both very informative, technical and relatively easy to follow. Definitely watch it if you’re interested in games, but haven’t worked professionally on them (yet)!&lt;/p&gt;

&lt;p&gt;Below you can find the abstract and the actual talk! You can also download the slides &lt;a href=&quot;https://t.co/zq1PZLGahN&quot;&gt;from my OneDrive&lt;/a&gt;. There was also an interview after the talk, which you can find on &lt;a href=&quot;https://open.spotify.com/episode/4SzHlBqNXkkzqOZh54GEgt&quot;&gt;Spotify&lt;/a&gt;. The intro starts at 3:00, the actually interview starts at 3:50).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Modern game engines render almost photo realistic images 60 times per second on €300,- game consoles. Meanwhile, at bol.com, it takes a €10.000 server a whole second to retrieve a customer’s stored order information. How do game engines do this? It almost sounds like magic!&lt;/p&gt;

  &lt;p&gt;Though very impressive, I will show you that game engines definitely do not perform magic. But that they accomplish their goal using deceit and trickery. To prove this I will take on the role of the masked magician, using the game engine I created.&lt;/p&gt;

  &lt;p&gt;At the end of this talk you will have a high-level understanding of the steps and tricks involved in real-time rendering. You will also have a better understanding of the very parallel, pipelined, approach used in real-time rendering, which will make you think differently about the code you write for bol.com.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;iframe width=&quot;750&quot; height=&quot;421&quot; src=&quot;https://www.youtube-nocookie.com/embed/l9Mx67fCr5I&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</description>
        <pubDate>Tue, 02 Jul 2019 11:28:00 +0000</pubDate>
        <link>https://roy-t.nl/2019/07/02/Presentation.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2019/07/02/Presentation.html</guid>
        
        
      </item>
    
      <item>
        <title>Text rendering in MonoGame</title>
        <description>&lt;p&gt;Recently I’ve put two text-rendering related repositories online. My &lt;a href=&quot;https://github.com/roy-t/TrueType&quot;&gt;TrueType parser&lt;/a&gt; which you can use to get meta data from any .ttf font. And a multi-spectrum signed distance field font &lt;a href=&quot;https://github.com/roy-t/MSDF&quot;&gt;sample&lt;/a&gt; for MonoGame.&lt;/p&gt;

&lt;p&gt;Especially the later is interesting if you would like to render text in your games!&lt;/p&gt;

&lt;h1 id=&quot;msdf&quot;&gt;MSDF&lt;/h1&gt;
&lt;p&gt;A signed distance field font sample for monogame. Available at &lt;a href=&quot;https://github.com/roy-t/MSDF&quot;&gt;GitHub&lt;/a&gt;. As usual the code is available under the &lt;a href=&quot;https://github.com/roy-t/MSDF/blob/master/LICENSE&quot;&gt;MIT license&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://roy-t.nl/files/msdf.png&quot; alt=&quot;Sample&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-content-pipeline-project&quot;&gt;The content pipeline project&lt;/h2&gt;
&lt;p&gt;The sample includes a content pipeline project compatible with Monogame 3.0+. The content processor requires you set the path to the msdfgen binary. I recommend you generate it from &lt;a href=&quot;https://github.com/ckohnert/msdfgen&quot;&gt;this fork&lt;/a&gt; as it fixes many issues with complicated fonts.&lt;/p&gt;

&lt;h2 id=&quot;the-game-project&quot;&gt;The game project&lt;/h2&gt;
&lt;p&gt;The game project contains a simple utility class and shader to draw 3D moving text.&lt;/p&gt;

&lt;h1 id=&quot;why-multi-channel-signed-distance-fields&quot;&gt;Why (multi-channel) signed distance fields?&lt;/h1&gt;

&lt;p&gt;Signed distance fields are a technique first described by Valve in &lt;a href=&quot;https://steamcdn-a.akamaihd.net/apps/valve/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf&quot;&gt;this paper&lt;/a&gt;. In short a signed distance field is a sort-of height map. Where sea-level are the actually boundaries of the glyph. Everything above sea level is outside the glyph, and everything below sea level is inside the glyph. When a height map is upscaled the GPU fills in the gaps using linear interpolation. The linear interpolation of the height map introduces less noise/faults than interpolating a sharp boundary would do, but we still get the same information.&lt;/p&gt;

&lt;p&gt;Traditional signed distance fields only use one channel, but they sometimes have trouble representing sharp corners. Multi-channel signed distance fields solve this problem by using three color channels to store slope information.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;High quality text rendering&lt;/li&gt;
  &lt;li&gt;Low memory usage&lt;/li&gt;
  &lt;li&gt;Fast rendering (the shader is very simple)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
  &lt;li&gt;No automatic mechanism to determine the right signed distance field size to capture all details&lt;/li&gt;
  &lt;li&gt;No multi-color glyphs (like emoji)&lt;/li&gt;
  &lt;li&gt;Straight lines might look slightly wavery sometimes&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;alternatives&quot;&gt;Alternatives&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;SpriteFonts, the standard in XNA and MonoGame, look good when rendered at the same size as the sprites were saved, but upscaling and downscaling quickly leads to a serious degradation in quality.&lt;/li&gt;
  &lt;li&gt;A library like &lt;a href=&quot;http://sluglibrary.com/&quot;&gt;slug&lt;/a&gt; which renders text directly from the outline data in the font. So no details are missed and no manual configuration is required.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 04 Jul 2018 11:32:00 +0000</pubDate>
        <link>https://roy-t.nl/2018/07/04/Text-Rendering.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2018/07/04/Text-Rendering.html</guid>
        
        
      </item>
    
      <item>
        <title>Roy-T.AStar, a NuGet package for A* path finding</title>
        <description>&lt;p&gt;Over the years I’ve made many improvements to my A* implementation. I believe its currently one of the fastest implemenations for C# out there. However, it was really hard to update to my latest and greatest version. So I present to you a completely new implementation, even faster. Which I’ve released as a NuGet package and have made available on GitHub.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Get the &lt;a href=&quot;https://www.nuget.org/packages/RoyT.AStar/&quot;&gt;NuGet package&lt;/a&gt;. Learn &lt;a href=&quot;https://docs.microsoft.com/en-us/nuget/quickstart/use-a-package&quot;&gt;how to use NuGet&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Browse the &lt;a href=&quot;https://github.com/roy-t/AStar&quot;&gt;source code&lt;/a&gt;, contributions are welcome.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;tutorial&quot;&gt;Tutorial&lt;/h2&gt;

&lt;p&gt;Below I give a textual explanation of this library and how to use it. If you are more interested in a code sample you can find it right after the next section.&lt;/p&gt;

&lt;h3 id=&quot;usage-in-text&quot;&gt;Usage in text&lt;/h3&gt;
&lt;p&gt;Your agent might be able to move fluently through a world with hills and water but that representation is too complex for the A* algorithm. 
So the first thing you need to do is to is to create an abstract representation of your world that is simple enough for the path finding algorithm to understand.
In this library we use a grid to represent the traversable, and intraversable, space in your world.&lt;/p&gt;

&lt;p&gt;You can instantiate a grid using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Grid&lt;/code&gt; class. If you have a world that is a 100 by a 100 meters large, and you
create a grid of 100x100, each cell will represent a patch of land of 1x1 meters.&lt;/p&gt;

&lt;p&gt;Experiment with the size of the grid, a larger grid
will give you more fine grained control but it will also make the path finding algorithm slower.&lt;/p&gt;

&lt;p&gt;Once you have a grid you need to configure which cells represent obstacles. Some obstacles, like a high wall, are intraversable. Use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlockCell&lt;/code&gt; method to prevent the path finding algorithm from planning paths through that cell.
Other obstacles, like dense shrubbery, take more time to traverse. In that case give the cell a higher cost using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetCellCost&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Once you’ve configured your grid its time to start planning paths. Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetPath&lt;/code&gt; method you can immidately search for a path between two cells for an agent that can move in all directions. 
You can also plan paths for agents that are more limited in their movent using the overload of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetPath&lt;/code&gt; that takes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;movementPattern&lt;/code&gt; parameter. In that case you can either select one of the predefined ranges of motion from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MovementPatterns&lt;/code&gt; class or you can configure yourself what kind of steps an agent can make.&lt;/p&gt;

&lt;p&gt;You can define your own patterns for your agents. Below I have defined the movement pattern for an agent that can only move diagonally. (This movement pattern is included in the library as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MovementPatterns.DiagonalOnly&lt;/code&gt;).&lt;/p&gt;

&lt;div class=&quot;language-csharp 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;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diagonalOnlyMovementPattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&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;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(-&lt;/span&gt;&lt;span class=&quot;m&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;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&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;m&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&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;h3 id=&quot;usage-example-in-code&quot;&gt;Usage example in code&lt;/h3&gt;
&lt;p&gt;You can easily search for the lowest cost path for an agent that can move in all directions.&lt;/p&gt;

&lt;div class=&quot;language-csharp 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;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;RoyT.AStar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Create a new grid and let each cell have a default traversal cost of 1.0&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1.0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Block some cells (for example walls)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BlockCell&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Make other cells harder to traverse (for example water)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetCellCost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3.0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// And finally start the search for the shortest path form start to end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;IList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;99&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;It is also posssible to define the agent’s movement pattern.&lt;/p&gt;

&lt;div class=&quot;language-csharp 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;// Use one of the built-in ranges of motion&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MovementPatterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DiagonalOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Or define the movement pattern of an agent yourself&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// For example, here is an agent that can only move left and up&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;movementPattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&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;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)};&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;movementPattern&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;implementation-details&quot;&gt;Implementation details&lt;/h2&gt;
&lt;p&gt;While making this library I was mostly concerned with performance (how long does it take to find a path) and ease of use.
I use a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MinHeap&lt;/code&gt; data structure to keep track of the best candidates for the shortest path. I’ve experimented with other data structures, like the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SortedSet&lt;/code&gt; but they were consistently slower. 
Other small tricks I’ve used is using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bool[]&lt;/code&gt; to keep track of checked cells and to only compute the squared distance in my heuristic. (Which helped a surprising amount).&lt;/p&gt;

&lt;p&gt;While micro-optimizing the code I’ve used the handy &lt;a href=&quot;https://github.com/dotnet/BenchmarkDotNet&quot;&gt;BenchMark.Net&lt;/a&gt; library to see if my changes had any effect. The benchmark suite is included in the source code here. So if you would like to try to make this implemention faster you can use the same benchmark and performance metrics I did.&lt;/p&gt;

&lt;p&gt;For version 1.0 I got the following numbers for a 100x100 grid (10000 cells) filled with a gradient.&lt;/p&gt;

&lt;div class=&quot;language-ini 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;py&quot;&gt;BenchmarkDotNet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;v0.10.8, OS=Windows 10 Redstone 2 (10.0.15063)&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Processor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Intel Core i5-4690 CPU 3.50GHz (Haswell), ProcessorCount=4&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;Frequency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3415990 Hz, Resolution=292.7409 ns, Timer=TSC&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;dotnet&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;cli&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1.0.4&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;[Host]&lt;/span&gt;     &lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;.NET&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;Core&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;4.6.25211.01,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;64bit&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;RyuJIT&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;DefaultJob&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;.NET&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;Core&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;4.6.25211.01,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;64bit&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;RyuJIT&lt;/span&gt;

 &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt;            &lt;span class=&quot;err&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt;     &lt;span class=&quot;err&quot;&gt;Mean&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt;     &lt;span class=&quot;err&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt;    &lt;span class=&quot;err&quot;&gt;StdDev&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt;
 &lt;span class=&quot;err&quot;&gt;|------------------&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|---------:|----------:|----------:|&lt;/span&gt;
 &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;Gradient100X100&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;1.177&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ms&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0.0057&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ms&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0.0048&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;ms&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;|&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Tue, 01 Aug 2017 21:02:00 +0000</pubDate>
        <link>https://roy-t.nl/2017/08/01/A-Star-Pathfinding-nuget-package.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2017/08/01/A-Star-Pathfinding-nuget-package.html</guid>
        
        
      </item>
    
      <item>
        <title>Installing XNA 4 under Visual Studio 2017</title>
        <description>&lt;p&gt;At &lt;a href=&quot;http://silverfit.nl&quot;&gt;SilverFit&lt;/a&gt; we use XNA to create physical and mental exercises for the elderly care industry. We’ve been doing this for more than eight years now. Leaving us with products that contain more than 30 XNA based games. You can imagine our horror when we tried to install the XNA plugin under Visual Studio 2017 and it didn’t work.&lt;/p&gt;

&lt;p&gt;Of course we’re looking at alternatives. But even with alternatives such as MonoGame its hard to convert seven years of work in a short amount of time. (Actually we tried to convert all our games to MonoGame three years ago but we ran into several blocking issues).&lt;/p&gt;

&lt;p&gt;So I tried to find a solution. After some hardcore debugging I figured out how to change the VSIX file to run under VS2017 and how to move some files around so that XNA’s content pipeline would work. I’ve been sitting on this guide for a while. Hoping for a more elegant solution. But unfortunately no-one has discovered one.&lt;/p&gt;

&lt;h1 id=&quot;the-steps&quot;&gt;The steps&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;Download a modified version of the XNA &lt;strong&gt;2015&lt;/strong&gt; vsix &lt;a href=&quot;https://mxa.codeplex.com/&quot;&gt;here&lt;/a&gt; (the XNA 2017 version seems to be a failed attempt at getting things to work).&lt;/li&gt;
  &lt;li&gt;Unzip XNA Game Studio 4.0.vsix and replace the &lt;code class=&quot;highlight language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Installation&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/code&gt; tag in extension.vsixmanifest with this:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt; &lt;span class=&quot;nt&quot;&gt;&amp;lt;Installation&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;InstalledByMsi=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&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;InstallationTarget&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[12.0,16.0)&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.VisualStudio.VSWinDesktopExpress&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;InstallationTarget&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[12.0,16.0)&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.VisualStudio.Pro&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;InstallationTarget&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[12.0,16.0)&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.VisualStudio.Premium&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;InstallationTarget&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[12.0,16.0)&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.VisualStudio.Ultimate&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;InstallationTarget&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[14.0,16.0)&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.VisualStudio.Community&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;InstallationTarget&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[14.0,16.0)&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.VisualStudio.Enterprise&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;/Installation&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Place everything in a zip file again and change the extension to vsix. Now run the the vsix file. It should give a warning message but other than that install for VS2017 without problems.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copy everything from &lt;code class=&quot;highlight language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;n&quot;&gt;C:\Program&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Files&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x86&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;\MSBuild\Microsoft\XNA&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Studio&lt;/span&gt;&lt;/code&gt; to &lt;code class=&quot;highlight language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;n&quot;&gt;C:\Program&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Files&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x86&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;\Microsoft&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Visual&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Studio\2017\Community\MSBuild\Microsoft\XNA&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Studio&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Open the Visual Studio 2017 developer command prompt by searching for Developer command prompt for VS 2017 as administrator and execute the following code: (this will add the new version of Microsoft.Build.Framework to the Global Assembly Cache).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;C:\Program&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Files&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x86&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;\Microsoft&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Visual&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Studio\2017\Community\MSBuild\15.0\Bin&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gacutil&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;/i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Microsoft.Build.Framework.dll&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After this you should be able to work with XNA in Visual Studio 2017 without problems.&lt;/p&gt;

&lt;p&gt;I’ve made a ticket to get some more information from Microsoft why this is needed. You can see it &lt;a href=&quot;https://github.com/Microsoft/msbuild/issues/1831&quot;&gt;here&lt;/a&gt; but the response so far is not really overwhelming.&lt;/p&gt;
</description>
        <pubDate>Tue, 18 Jul 2017 10:15:00 +0000</pubDate>
        <link>https://roy-t.nl/2017/07/18/Installing-XNA-4-under-Visual-Studio-2017.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2017/07/18/Installing-XNA-4-under-Visual-Studio-2017.html</guid>
        
        
      </item>
    
      <item>
        <title>Conversion to Jekyll</title>
        <description>&lt;p&gt;For the last 8 years this blog was running on Wordpress. I think Wordpress is a great platform, and in those eight years I was generally satisfied with how it worked.&lt;/p&gt;

&lt;p&gt;Unfortunately the last few years have been different. Wordpress seems to have become extremely vulnerable to malware infections. This blog itself got infected at least 4 times in the last two years! This is odd since I use a completely standard installation and almost no plugins. Auto-update is configured and I’ve tried to harden the installation with a security scanner but this didn’t seem to help at all. To make things worse the blog software also didn’t really work when it wasn’t infected, it was terribly slow.&lt;/p&gt;

&lt;p&gt;Because of this I’ve decided to switch over my entire blog to plain old static html pages. This should make it virtually impossible to get infected and it also gives a nice speed boost!&lt;/p&gt;

&lt;p&gt;Of course I will not be typing HTML by hand. I’ve decided to use &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt;. Jekyll generates a complete static website from posts written in markdown.&lt;/p&gt;

&lt;p&gt;Changing from Wordpress to Jekyll isn’t painless. I’ve used a converter to convert all the old Wordpress posts to markdown but most of them need small tweaks. I’ve also had some trouble making the old Wordpress links work. But thanks to some .htaccess voodoo that too works alright now :).&lt;/p&gt;

&lt;p&gt;You can check out &lt;a href=&quot;https://github.com/roy-t/roy-t.nl&quot;&gt;Github&lt;/a&gt; to see how I’ve done the conversion. All the inputs for this website are stored there.&lt;/p&gt;

&lt;p&gt;It will take some time to convert all the old posts. There are almost 150 of them. See my twitter feed for the actual status. Currently almost everything from the last 5 years has been converted.&lt;/p&gt;

&lt;p&gt;In the meantime, sorry for the inconvenience!&lt;/p&gt;
</description>
        <pubDate>Thu, 05 May 2016 12:03:00 +0000</pubDate>
        <link>https://roy-t.nl/2016/05/05/Conversion-To-Jekyll.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2016/05/05/Conversion-To-Jekyll.html</guid>
        
        
      </item>
    
      <item>
        <title>Customizable Touch-Friendly TimePicker Clock for WPF</title>
        <description>&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-881&quot; src=&quot;https://raw.githubusercontent.com/roy-t/TimePicker/master/screenshot.png&quot; alt=&quot;screenshot&quot; width=&quot;351&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve created a fully customizable touch-friendly time picker control for WPF. Initially I tried to create a time picker that looks like the one on your phone. But I got so frustrated with creating an infinite scrollable list that I decided to make an old-fashioned time picker based on a clock.&lt;/p&gt;

&lt;p&gt;The TimePicker supports a Two-Way binding to a TimeSpan property. Dragging the hour or minute indicator updates the TimeSpan. There are also a lot of visual options&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Brush for the hour indicator&lt;/li&gt;
  &lt;li&gt;Thickness of the hour indicator&lt;/li&gt;
  &lt;li&gt;Brush for the minute indicator&lt;/li&gt;
  &lt;li&gt;Thickness of the minute indicator&lt;/li&gt;
  &lt;li&gt;Separate brushes for the hour and minute ticks&lt;/li&gt;
  &lt;li&gt;Separate thickness for the hour and minute ticks&lt;/li&gt;
  &lt;li&gt;Background brush&lt;/li&gt;
  &lt;li&gt;Border brush and border thickness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code also includes a handy math class which, among other things, makes it possible to calculate a time based on the position on of the mouse in relation to the clock.&lt;/p&gt;

&lt;p&gt;I ‘recently’ announced that I created a bitbucket account. But since I’ve grown so accustomed to git (we switched from Hg to git at work) I’ve decided to post this project on my brand new GitHub account.&lt;/p&gt;

&lt;p&gt;You can download the code and examples at &lt;a href=&quot;https://github.com/roy-t/TimePicker&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Sat, 05 Mar 2016 12:18:00 +0000</pubDate>
        <link>https://roy-t.nl/2016/03/05/customizable-touch-friendly-timepicker-clock-for-wpf.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2016/03/05/customizable-touch-friendly-timepicker-clock-for-wpf.html</guid>
        
        
      </item>
    
      <item>
        <title>BitBucket Account</title>
        <description>&lt;p&gt;Apart from code on this blog, I haven’t really contributed code on other places on the web. However, a blog really isn’t the best place to put code. So I’ve dusted off my Atlassian account and I’ll be starting to make contributions on BitBucket.&lt;/p&gt;

&lt;p&gt;You can find my BitBucket account on: &lt;a title=&quot;BitBucket Account&quot; href=&quot;https://bitbucket.org/roy-t/&quot; target=&quot;_blank&quot;&gt;https://bitbucket.org/roy-t/&lt;/a&gt; the place is a bit barren at the moment, but I hope to make some progress on my Roslyn / Code Constraints experiment this weekend. I’ll publish the changes there.&lt;/p&gt;

&lt;p&gt;Of course feel free to contribute or pull the code and check it out!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update: I’ve switched to &lt;a href=&quot;https://github.com/roy-t&quot;&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 21 Mar 2015 10:34:00 +0000</pubDate>
        <link>https://roy-t.nl/2015/03/21/bitbucket-account.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2015/03/21/bitbucket-account.html</guid>
        
        
      </item>
    
      <item>
        <title>Graduation, Jobs, Roslyn</title>
        <description>&lt;p&gt;The last few Months I haven’t been able to post any new material here, but don’t worry I haven’t been slacking off.&lt;/p&gt;

&lt;p&gt;Most of my energy has been poured into my research regarding Navigation Meshes, and I’m happy to announce that I have completed this work. This research project has also led me to graduate from Utrecht University Cum Laude. Since January 15th 2015 I am officially a Master of Science :D.&lt;/p&gt;

&lt;p&gt;While I was working on that I have also been job hunting, and last Oktober started at the company &lt;a title=&quot;SilverFit BV&quot; href=&quot;http://silverfit.nl&quot;&gt;SilverFit&lt;/a&gt;. Here I use the Kinect Camera to help elderly people rehabilitate by means of computer-aided physical exercises.&lt;/p&gt;

&lt;p&gt;I hope that, once the dust has settled, I will be able to start producing content for this blog again. I have been working on some cool things with Roslyn that I would like to show you all.&lt;/p&gt;

&lt;p&gt;Meawhile you can have a look at my &lt;a title=&quot;Navigation Meshes&quot; href=&quot;http://roy-t.nl/navigation-meshes/&quot;&gt;Navigation Mesh Research&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 15 Jan 2015 20:17:00 +0000</pubDate>
        <link>https://roy-t.nl/2015/01/15/graduation-jobs-roslyn.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2015/01/15/graduation-jobs-roslyn.html</guid>
        
        
      </item>
    
      <item>
        <title>Codesnippet, Poor man&apos;s benchmark, or quickly timing things in C#</title>
        <description>&lt;p&gt;For a project I’m working on I had to do some quick timing. Now manually working with DateTimes and TimeSpans isn’t hard but I had to do a lot (e.g. more than 3) timings inside a bigger process and I wanted to know both the time the entire process took as the time parts of the process ate up. For this I created a handy StopWatch class which uses a stack to store different date times so you can easily do nested timing with very little code. This is nothing revolutionary but I thought I’d share it anyway. Its those little things that save some time that are the nicest!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// Always accesible timing apparatus&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StopWatch&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StopWatch&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;timers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&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;p&quot;&gt;}&lt;/span&gt;


	&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// Pushes the current DateTime onto the stack of timers&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Push&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;timers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&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;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// Pops the top DateTime from the stack of timers,&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// returns the TimeSpan between when the last Push and now&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;/summary&amp;gt;        &lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Pop&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;timers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&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;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Pop&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;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&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;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Trying&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stack&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;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;p&quot;&gt;}&lt;/span&gt; 

	&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// Calls Pop(), then prints the text &amp;amp;quot;StopWatch: {totalSeconds} \n&amp;amp;quot;&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// directly to console.&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PopAndPrint&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;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StopWatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;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;nf&quot;&gt;Pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalSeconds&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;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// Returns the TimeSpan between the last Push and now&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// without popping the TimeSpan from the stack of timers&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;/// &amp;lt;/summary&amp;gt;        &lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Peek&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;timers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&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;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Peek&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;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&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;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Trying&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;peek&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stack&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;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;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Usage&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&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;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&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;// Measure the entire process&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;StopWatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Push&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;// Measure subtask            &lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;StopWatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
		
		&lt;span class=&quot;c1&quot;&gt;// Subtask took:&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;StopWatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;PopAndPrint&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;// Entire process took:&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;StopWatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;PopAndPrint&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;/figure&gt;

&lt;p&gt;Output&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-csharp&quot; data-lang=&quot;csharp&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sourcecode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;StopWatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0010001&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;StopWatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0020001&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Wed, 04 Jun 2014 14:50:00 +0000</pubDate>
        <link>https://roy-t.nl/2014/06/04/codesnippet-poor-mans-benchmark-or-quickly-timing-things-in-c.html</link>
        <guid isPermaLink="true">https://roy-t.nl/2014/06/04/codesnippet-poor-mans-benchmark-or-quickly-timing-things-in-c.html</guid>
        
        
      </item>
    
  </channel>
</rss>
