This shows curvature vectors along the Melbourne, Australia racing track. The longer the red lines, the steeper the curve.
See my previous work:
import drawTrack from './drawTrack.js'
// Draw the track.
drawTrack({
container: d3.select('.circuit'),
track: circuitTracks[0]
})
<!DOCTYPE html>
<title>blockup</title>
<link href='https://fonts.googleapis.com/css?family=VT323' rel='stylesheet'>
<link href='dist.css' rel='stylesheet' />
<body>
<h1><span>curvature</span> of the Australian Grand Prix racing circuit</h1>
<div class='circuit'></div>
<button></button>
<script src='sylvester.js'></script>
<script src='d3.v4.min.js'></script>
<script src='circuitTracks.js'></script>
<script src='dist.js'></script>
</body>
*{box-sizing:border-box}html{background:rgba(1,11,20,.5);padding:0;margin:0}body{background:#010b14;font-family:VT323,monospace;overflow:hidden;margin:0 auto;padding:0;position:relative;width:960px;height:500px}svg{display:block}h1{color:#dacbed;text-shadow:0 0 14px rgba(218,203,237,.75);text-transform:uppercase;font-weight:400;font-style:italic;position:absolute;text-align:center;padding:0;margin:0;width:100%;font-size:2.5em}h1 span{color:#f94533}button{display:block;margin:0 auto;font-family:VT323,monospace;border:solid #dacbed 1px;background:#010b14;color:#dacbed;font-size:2em;text-transform:uppercase;position:relative;top:-1em;cursor:pointer}.circuit{width:50%;position:relative;margin:0 auto;padding:0}.circuit svg{margin:0 auto;-webkit-filter:drop-shadow(0 0 14px #f94533);filter:drop-shadow(0 0 14px #f94533)}.circuit svg path.track{fill:none;stroke:#0fd0fe;opacity:.2}.circuit svg circle.p{fill:#dacbed}.circuit svg circle.q{fill:#f94533}.circuit svg line{stroke:#f94533}.circuit svg text{fill:#f94533}
!function(n){function g(I){if(t[I])return t[I].exports;var C=t[I]={i:I,l:!1,exports:{}};return n[I].call(C.exports,C,C.exports,g),C.l=!0,C.exports}var t={};g.m=n,g.c=t,g.i=function(n){return n},g.d=function(n,t,I){g.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:I})},g.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return g.d(t,"a",t),t},g.o=function(n,g){return Object.prototype.hasOwnProperty.call(n,g)},g.p="",g(g.s=1)}([function(module,exports,__webpack_require__){"use strict";eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nvar drawTrack = function drawTrack(_ref) {\n var container = _ref.container,\n track = _ref.track;\n\n var margin = 50;\n var dimension = container.node().offsetWidth - margin * 2;\n\n var xExtent = d3.extent(track, function (d) {\n return d.x;\n });\n var x = d3.scaleLinear().domain(xExtent);\n\n var yExtent = d3.extent(track, function (d) {\n return d.y;\n });\n var y = d3.scaleLinear().domain(yExtent);\n\n var aspect = (xExtent[1] - xExtent[0]) / (yExtent[1] - yExtent[0]);\n\n var width = Math.min(dimension * aspect, dimension);\n var height = Math.min(dimension / aspect, dimension);\n\n x.range([0, width]);\n y.range([0, height]);\n\n var svg = container.append('svg').attr('width', width + 2 * margin).attr('height', height + 2 * margin);\n\n var g = svg.append('g').attr('transform', 'translate(' + margin + ', ' + margin + ')');\n\n var line = d3.line().curve(d3.curveBasis).x(function (d) {\n return x(d.x);\n }).y(function (d) {\n return y(d.y);\n });\n\n var path = g.append('path').attr('class', 'track').datum(track).attr('d', line).node();\n\n var totalLength = path.getTotalLength();\n\n var getCoords = function getCoords(pct) {\n var length = totalLength * pct;\n var p = path.getPointAtLength(length % totalLength);\n return [p.x, p.y];\n };\n\n var centroid = d3.polygonCentroid(track.map(function (d) {\n return [d.x, d.y];\n }));\n\n var steps = 1000;\n var delta = 1 / steps;\n var positions = d3.range(0, 1 + delta, delta).map(getCoords).slice(1).map(function (p, i, a) {\n // Find the vector to the previous point.\n var o = a[(i + a.length - 1) % a.length];\n var backwards = $V([o[0] - p[0], o[1] - p[1]]);\n\n // // Find the vector to the next point.\n var q = a[(i + 1) % a.length];\n var forwards = $V([q[0] - p[0], q[1] - p[1]]);\n\n // Find the angle between the two vectors.\n var angleBetweenVectors = backwards.angleFrom(forwards) * 180 / Math.PI;\n\n // Find the normal vector and scale it based on the angle\n // between the two vectors.\n var normal = forwards.rotate(Math.PI / 2, $V([0, 0])).toUnitVector().multiply(180 - angleBetweenVectors);\n\n // Determine concavity.\n var isConcave = backwards.angleFrom(normal) * 180 / Math.PI >= 90;\n\n // Create curvature vector.\n var curvature = normal.rotate(isConcave ? 0 : Math.PI, $V([0, 0])).multiply(3);\n\n // Create position on circle.\n var startingOffset = 0.7;\n var radius = dimension / 3;\n var origin = [x(centroid[0]), y(centroid[1])];\n var circleAngle = 2 * Math.PI * i / (a.length - 1) + Math.PI * startingOffset;\n var c = [Math.cos(circleAngle), Math.sin(circleAngle)];\n\n return {\n p: p,\n c: c,\n origin: origin,\n radius: radius,\n curvature: curvature,\n isConcave: isConcave,\n modulus: curvature.modulus()\n };\n });\n\n // Draw the normal to each point.\n var lines = g.selectAll('line.normal').data(positions).enter().append('line').attr('class', 'normal').attr('x1', 0).attr('y1', 0).attr('transform', function (d) {\n return 'translate(' + (d.c[0] * d.radius + d.origin[0]) + ', ' + (d.c[1] * d.radius + d.origin[1]) + ')';\n }).attr('x2', function (d) {\n return d.c[0] * d.curvature.modulus() * (d.isConcave ? -1 : 1);\n }).attr('y2', function (d) {\n return d.c[1] * d.curvature.modulus() * (d.isConcave ? -1 : 1);\n });\n\n var button = d3.select('button');\n\n var showCurvature = true;\n // copy paste here, not ashamed\n // but maybe i am otherwise i wouldn't leave this note\n var magic = function magic() {\n var duration = 2000;\n var delay = 1;\n if (showCurvature) {\n lines.transition().duration(duration).delay(function (d, i) {\n return i * delay;\n }).attr('transform', function (d) {\n return 'translate(' + d.p + ')';\n }).attr('x2', function (d) {\n return d.curvature.elements[0];\n }).attr('y2', function (d) {\n return d.curvature.elements[1];\n });\n button.text('morph circuit to circle');\n } else {\n lines.transition().duration(duration).delay(function (d, i) {\n return i * delay;\n }).attr('transform', function (d) {\n return 'translate(' + (d.c[0] * d.radius + d.origin[0]) + ', ' + (d.c[1] * d.radius + d.origin[1]) + ')';\n }).attr('x2', function (d) {\n return d.c[0] * d.curvature.modulus() * (d.isConcave ? -1 : 1);\n }).attr('y2', function (d) {\n return d.c[1] * d.curvature.modulus() * (d.isConcave ? -1 : 1);\n });\n button.text('morph circle to circuit');\n }\n showCurvature = !showCurvature;\n };\n magic();\n\n button.on('click', magic);\n};\n\nexports.default = drawTrack;//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMC5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy9kcmF3VHJhY2suanM/MTY1OSJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBkcmF3VHJhY2sgPSAoeyBjb250YWluZXIsIHRyYWNrIH0pID0+IHtcbiAgY29uc3QgbWFyZ2luID0gNTBcbiAgY29uc3QgZGltZW5zaW9uID0gY29udGFpbmVyLm5vZGUoKS5vZmZzZXRXaWR0aCAtIG1hcmdpbiAqIDJcblxuICBjb25zdCB4RXh0ZW50ID0gZDMuZXh0ZW50KHRyYWNrLCBkID0+IGQueClcbiAgY29uc3QgeCA9IGQzLnNjYWxlTGluZWFyKCkuZG9tYWluKHhFeHRlbnQpXG5cbiAgY29uc3QgeUV4dGVudCA9IGQzLmV4dGVudCh0cmFjaywgZCA9PiBkLnkpXG4gIGNvbnN0IHkgPSBkMy5zY2FsZUxpbmVhcigpLmRvbWFpbih5RXh0ZW50KVxuXG4gIGNvbnN0IGFzcGVjdCA9ICh4RXh0ZW50WzFdIC0geEV4dGVudFswXSkgLyAoeUV4dGVudFsxXSAtIHlFeHRlbnRbMF0pXG5cbiAgY29uc3Qgd2lkdGggPSBNYXRoLm1pbihkaW1lbnNpb24gKiBhc3BlY3QsIGRpbWVuc2lvbilcbiAgY29uc3QgaGVpZ2h0ID0gTWF0aC5taW4oZGltZW5zaW9uIC8gYXNwZWN0LCBkaW1lbnNpb24pXG5cbiAgeC5yYW5nZShbMCwgd2lkdGhdKVxuICB5LnJhbmdlKFswLCBoZWlnaHRdKVxuXG4gIGNvbnN0IHN2ZyA9IGNvbnRhaW5lclxuICAgIC5hcHBlbmQoJ3N2ZycpXG4gICAgLmF0dHIoJ3dpZHRoJywgd2lkdGggKyAyICogbWFyZ2luKVxuICAgIC5hdHRyKCdoZWlnaHQnLCBoZWlnaHQgKyAyICogbWFyZ2luKVxuXG4gIGNvbnN0IGcgPSBzdmcuYXBwZW5kKCdnJykuYXR0cigndHJhbnNmb3JtJywgYHRyYW5zbGF0ZSgke21hcmdpbn0sICR7bWFyZ2lufSlgKVxuXG4gIGNvbnN0IGxpbmUgPSBkM1xuICAgIC5saW5lKClcbiAgICAuY3VydmUoZDMuY3VydmVCYXNpcylcbiAgICAueChkID0+IHgoZC54KSlcbiAgICAueShkID0+IHkoZC55KSlcblxuICBjb25zdCBwYXRoID0gZ1xuICAgIC5hcHBlbmQoJ3BhdGgnKVxuICAgIC5hdHRyKCdjbGFzcycsICd0cmFjaycpXG4gICAgLmRhdHVtKHRyYWNrKVxuICAgIC5hdHRyKCdkJywgbGluZSlcbiAgICAubm9kZSgpXG5cbiAgY29uc3QgdG90YWxMZW5ndGggPSBwYXRoLmdldFRvdGFsTGVuZ3RoKClcblxuICBjb25zdCBnZXRDb29yZHMgPSBwY3QgPT4ge1xuICAgIGNvbnN0IGxlbmd0aCA9IHRvdGFsTGVuZ3RoICogcGN0XG4gICAgY29uc3QgcCA9IHBhdGguZ2V0UG9pbnRBdExlbmd0aChsZW5ndGggJSB0b3RhbExlbmd0aClcbiAgICByZXR1cm4gW3AueCwgcC55XVxuICB9XG5cbiAgY29uc3QgY2VudHJvaWQgPSBkMy5wb2x5Z29uQ2VudHJvaWQodHJhY2subWFwKGQgPT4gW2QueCwgZC55XSkpXG5cbiAgY29uc3Qgc3RlcHMgPSAxMDAwXG4gIGNvbnN0IGRlbHRhID0gMSAvIHN0ZXBzXG4gIGNvbnN0IHBvc2l0aW9ucyA9IGQzXG4gICAgLnJhbmdlKDAsIDEgKyBkZWx0YSwgZGVsdGEpXG4gICAgLm1hcChnZXRDb29yZHMpXG4gICAgLnNsaWNlKDEpXG4gICAgLm1hcCgocCwgaSwgYSkgPT4ge1xuICAgICAgLy8gRmluZCB0aGUgdmVjdG9yIHRvIHRoZSBwcmV2aW91cyBwb2ludC5cbiAgICAgIGNvbnN0IG8gPSBhWyhpICsgYS5sZW5ndGggLSAxKSAlIGEubGVuZ3RoXVxuICAgICAgY29uc3QgYmFja3dhcmRzID0gJFYoW29bMF0gLSBwWzBdLCBvWzFdIC0gcFsxXV0pXG5cbiAgICAgIC8vIC8vIEZpbmQgdGhlIHZlY3RvciB0byB0aGUgbmV4dCBwb2ludC5cbiAgICAgIGNvbnN0IHEgPSBhWyhpICsgMSkgJSBhLmxlbmd0aF1cbiAgICAgIGNvbnN0IGZvcndhcmRzID0gJFYoW3FbMF0gLSBwWzBdLCBxWzFdIC0gcFsxXV0pXG5cbiAgICAgIC8vIEZpbmQgdGhlIGFuZ2xlIGJldHdlZW4gdGhlIHR3byB2ZWN0b3JzLlxuICAgICAgY29uc3QgYW5nbGVCZXR3ZWVuVmVjdG9ycyA9IGJhY2t3YXJkcy5hbmdsZUZyb20oZm9yd2FyZHMpICogMTgwIC8gTWF0aC5QSVxuXG4gICAgICAvLyBGaW5kIHRoZSBub3JtYWwgdmVjdG9yIGFuZCBzY2FsZSBpdCBiYXNlZCBvbiB0aGUgYW5nbGVcbiAgICAgIC8vIGJldHdlZW4gdGhlIHR3byB2ZWN0b3JzLlxuICAgICAgY29uc3Qgbm9ybWFsID0gZm9yd2FyZHNcbiAgICAgICAgLnJvdGF0ZShNYXRoLlBJIC8gMiwgJFYoWzAsIDBdKSlcbiAgICAgICAgLnRvVW5pdFZlY3RvcigpXG4gICAgICAgIC5tdWx0aXBseSgxODAgLSBhbmdsZUJldHdlZW5WZWN0b3JzKVxuXG4gICAgICAvLyBEZXRlcm1pbmUgY29uY2F2aXR5LlxuICAgICAgY29uc3QgaXNDb25jYXZlID0gYmFja3dhcmRzLmFuZ2xlRnJvbShub3JtYWwpICogMTgwIC8gTWF0aC5QSSA+PSA5MFxuXG4gICAgICAvLyBDcmVhdGUgY3VydmF0dXJlIHZlY3Rvci5cbiAgICAgIGNvbnN0IGN1cnZhdHVyZSA9IG5vcm1hbFxuICAgICAgICAucm90YXRlKGlzQ29uY2F2ZSA/IDAgOiBNYXRoLlBJLCAkVihbMCwgMF0pKVxuICAgICAgICAubXVsdGlwbHkoMylcblxuICAgICAgLy8gQ3JlYXRlIHBvc2l0aW9uIG9uIGNpcmNsZS5cbiAgICAgIGNvbnN0IHN0YXJ0aW5nT2Zmc2V0ID0gMC43XG4gICAgICBjb25zdCByYWRpdXMgPSBkaW1lbnNpb24gLyAzXG4gICAgICBjb25zdCBvcmlnaW4gPSBbeChjZW50cm9pZFswXSksIHkoY2VudHJvaWRbMV0pXVxuICAgICAgY29uc3QgY2lyY2xlQW5nbGUgPVxuICAgICAgICAyICogTWF0aC5QSSAqIGkgLyAoYS5sZW5ndGggLSAxKSArIE1hdGguUEkgKiBzdGFydGluZ09mZnNldFxuICAgICAgY29uc3QgYyA9IFtNYXRoLmNvcyhjaXJjbGVBbmdsZSksIE1hdGguc2luKGNpcmNsZUFuZ2xlKV1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcCxcbiAgICAgICAgYyxcbiAgICAgICAgb3JpZ2luLFxuICAgICAgICByYWRpdXMsXG4gICAgICAgIGN1cnZhdHVyZSxcbiAgICAgICAgaXNDb25jYXZlLFxuICAgICAgICBtb2R1bHVzOiBjdXJ2YXR1cmUubW9kdWx1cygpXG4gICAgICB9XG4gICAgfSlcblxuICAvLyBEcmF3IHRoZSBub3JtYWwgdG8gZWFjaCBwb2ludC5cbiAgY29uc3QgbGluZXMgPSBnXG4gICAgLnNlbGVjdEFsbCgnbGluZS5ub3JtYWwnKVxuICAgIC5kYXRhKHBvc2l0aW9ucylcbiAgICAuZW50ZXIoKVxuICAgIC5hcHBlbmQoJ2xpbmUnKVxuICAgIC5hdHRyKCdjbGFzcycsICdub3JtYWwnKVxuICAgIC5hdHRyKCd4MScsIDApXG4gICAgLmF0dHIoJ3kxJywgMClcbiAgICAuYXR0cihcbiAgICAgICd0cmFuc2Zvcm0nLFxuICAgICAgZCA9PlxuICAgICAgICBgdHJhbnNsYXRlKCR7ZC5jWzBdICogZC5yYWRpdXMgKyBkLm9yaWdpblswXX0sICR7ZC5jWzFdICogZC5yYWRpdXMgK1xuICAgICAgICAgIGQub3JpZ2luWzFdfSlgXG4gICAgKVxuICAgIC5hdHRyKCd4MicsIGQgPT4gZC5jWzBdICogZC5jdXJ2YXR1cmUubW9kdWx1cygpICogKGQuaXNDb25jYXZlID8gLTEgOiAxKSlcbiAgICAuYXR0cigneTInLCBkID0+IGQuY1sxXSAqIGQuY3VydmF0dXJlLm1vZHVsdXMoKSAqIChkLmlzQ29uY2F2ZSA/IC0xIDogMSkpXG5cbiAgY29uc3QgYnV0dG9uID0gZDMuc2VsZWN0KCdidXR0b24nKVxuXG4gIGxldCBzaG93Q3VydmF0dXJlID0gdHJ1ZVxuICAvLyBjb3B5IHBhc3RlIGhlcmUsIG5vdCBhc2hhbWVkXG4gIC8vIGJ1dCBtYXliZSBpIGFtIG90aGVyd2lzZSBpIHdvdWxkbid0IGxlYXZlIHRoaXMgbm90ZVxuICBjb25zdCBtYWdpYyA9ICgpID0+IHtcbiAgICBjb25zdCBkdXJhdGlvbiA9IDIwMDBcbiAgICBjb25zdCBkZWxheSA9IDFcbiAgICBpZiAoc2hvd0N1cnZhdHVyZSkge1xuICAgICAgbGluZXNcbiAgICAgICAgLnRyYW5zaXRpb24oKVxuICAgICAgICAuZHVyYXRpb24oZHVyYXRpb24pXG4gICAgICAgIC5kZWxheSgoZCwgaSkgPT4gaSAqIGRlbGF5KVxuICAgICAgICAuYXR0cigndHJhbnNmb3JtJywgZCA9PiBgdHJhbnNsYXRlKCR7ZC5wfSlgKVxuICAgICAgICAuYXR0cigneDInLCBkID0+IGQuY3VydmF0dXJlLmVsZW1lbnRzWzBdKVxuICAgICAgICAuYXR0cigneTInLCBkID0+IGQuY3VydmF0dXJlLmVsZW1lbnRzWzFdKVxuICAgICAgYnV0dG9uLnRleHQoJ21vcnBoIGNpcmN1aXQgdG8gY2lyY2xlJylcbiAgICB9IGVsc2Uge1xuICAgICAgbGluZXNcbiAgICAgICAgLnRyYW5zaXRpb24oKVxuICAgICAgICAuZHVyYXRpb24oZHVyYXRpb24pXG4gICAgICAgIC5kZWxheSgoZCwgaSkgPT4gaSAqIGRlbGF5KVxuICAgICAgICAuYXR0cihcbiAgICAgICAgICAndHJhbnNmb3JtJyxcbiAgICAgICAgICBkID0+XG4gICAgICAgICAgICBgdHJhbnNsYXRlKCR7ZC5jWzBdICogZC5yYWRpdXMgKyBkLm9yaWdpblswXX0sICR7ZC5jWzFdICogZC5yYWRpdXMgK1xuICAgICAgICAgICAgICBkLm9yaWdpblsxXX0pYFxuICAgICAgICApXG4gICAgICAgIC5hdHRyKFxuICAgICAgICAgICd4MicsXG4gICAgICAgICAgZCA9PiBkLmNbMF0gKiBkLmN1cnZhdHVyZS5tb2R1bHVzKCkgKiAoZC5pc0NvbmNhdmUgPyAtMSA6IDEpXG4gICAgICAgIClcbiAgICAgICAgLmF0dHIoXG4gICAgICAgICAgJ3kyJyxcbiAgICAgICAgICBkID0+IGQuY1sxXSAqIGQuY3VydmF0dXJlLm1vZHVsdXMoKSAqIChkLmlzQ29uY2F2ZSA/IC0xIDogMSlcbiAgICAgICAgKVxuICAgICAgYnV0dG9uLnRleHQoJ21vcnBoIGNpcmNsZSB0byBjaXJjdWl0JylcbiAgICB9XG4gICAgc2hvd0N1cnZhdHVyZSA9ICFzaG93Q3VydmF0dXJlXG4gIH1cbiAgbWFnaWMoKVxuXG4gIGJ1dHRvbi5vbignY2xpY2snLCBtYWdpYylcbn1cblxuZXhwb3J0IGRlZmF1bHQgZHJhd1RyYWNrXG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gZHJhd1RyYWNrLmpzIl0sIm1hcHBpbmdzIjoiOzs7OztBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUlBO0FBQ0E7QUFDQTtBQUdBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBUEE7QUFTQTtBQUNBO0FBQ0E7QUFDQTtBQVVBO0FBQUE7QUFJQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFHQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBR0E7QUFBQTtBQUdBO0FBQUE7QUFNQTtBQUFBO0FBSUE7QUFBQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///0\n")},function(module,exports,__webpack_require__){"use strict";eval("\n\nvar _drawTrack = __webpack_require__(0);\n\nvar _drawTrack2 = _interopRequireDefault(_drawTrack);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n// Draw the track.\n(0, _drawTrack2.default)({\n container: d3.select('.circuit'),\n track: circuitTracks[0]\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy9zY3JpcHQuanM/OWE5NSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZHJhd1RyYWNrIGZyb20gJy4vZHJhd1RyYWNrLmpzJ1xuXG4vLyBEcmF3IHRoZSB0cmFjay5cbmRyYXdUcmFjayh7XG4gIGNvbnRhaW5lcjogZDMuc2VsZWN0KCcuY2lyY3VpdCcpLFxuICB0cmFjazogY2lyY3VpdFRyYWNrc1swXVxufSlcblxuXG5cbi8vIFdFQlBBQ0sgRk9PVEVSIC8vXG4vLyBzY3JpcHQuanMiXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTs7Ozs7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUZBIiwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///1\n")}]);
const drawTrack = ({ container, track }) => {
const margin = 50
const dimension = container.node().offsetWidth - margin * 2
const xExtent = d3.extent(track, d => d.x)
const x = d3.scaleLinear().domain(xExtent)
const yExtent = d3.extent(track, d => d.y)
const y = d3.scaleLinear().domain(yExtent)
const aspect = (xExtent[1] - xExtent[0]) / (yExtent[1] - yExtent[0])
const width = Math.min(dimension * aspect, dimension)
const height = Math.min(dimension / aspect, dimension)
x.range([0, width])
y.range([0, height])
const svg = container
.append('svg')
.attr('width', width + 2 * margin)
.attr('height', height + 2 * margin)
const g = svg.append('g').attr('transform', `translate(${margin}, ${margin})`)
const line = d3
.line()
.curve(d3.curveBasis)
.x(d => x(d.x))
.y(d => y(d.y))
const path = g
.append('path')
.attr('class', 'track')
.datum(track)
.attr('d', line)
.node()
const totalLength = path.getTotalLength()
const getCoords = pct => {
const length = totalLength * pct
const p = path.getPointAtLength(length % totalLength)
return [p.x, p.y]
}
const centroid = d3.polygonCentroid(track.map(d => [d.x, d.y]))
const steps = 1000
const delta = 1 / steps
const positions = d3
.range(0, 1 + delta, delta)
.map(getCoords)
.slice(1)
.map((p, i, a) => {
// Find the vector to the previous point.
const o = a[(i + a.length - 1) % a.length]
const backwards = $V([o[0] - p[0], o[1] - p[1]])
// // Find the vector to the next point.
const q = a[(i + 1) % a.length]
const forwards = $V([q[0] - p[0], q[1] - p[1]])
// Find the angle between the two vectors.
const angleBetweenVectors = backwards.angleFrom(forwards) * 180 / Math.PI
// Find the normal vector and scale it based on the angle
// between the two vectors.
const normal = forwards
.rotate(Math.PI / 2, $V([0, 0]))
.toUnitVector()
.multiply(180 - angleBetweenVectors)
// Determine concavity.
const isConcave = backwards.angleFrom(normal) * 180 / Math.PI >= 90
// Create curvature vector.
const curvature = normal
.rotate(isConcave ? 0 : Math.PI, $V([0, 0]))
.multiply(3)
// Create position on circle.
const startingOffset = 0.7
const radius = dimension / 3
const origin = [x(centroid[0]), y(centroid[1])]
const circleAngle =
2 * Math.PI * i / (a.length - 1) + Math.PI * startingOffset
const c = [Math.cos(circleAngle), Math.sin(circleAngle)]
return {
p,
c,
origin,
radius,
curvature,
isConcave,
modulus: curvature.modulus()
}
})
// Draw the normal to each point.
const lines = g
.selectAll('line.normal')
.data(positions)
.enter()
.append('line')
.attr('class', 'normal')
.attr('x1', 0)
.attr('y1', 0)
.attr(
'transform',
d =>
`translate(${d.c[0] * d.radius + d.origin[0]}, ${d.c[1] * d.radius +
d.origin[1]})`
)
.attr('x2', d => d.c[0] * d.curvature.modulus() * (d.isConcave ? -1 : 1))
.attr('y2', d => d.c[1] * d.curvature.modulus() * (d.isConcave ? -1 : 1))
const button = d3.select('button')
let showCurvature = true
// copy paste here, not ashamed
// but maybe i am otherwise i wouldn't leave this note
const magic = () => {
const duration = 2000
const delay = 1
if (showCurvature) {
lines
.transition()
.duration(duration)
.delay((d, i) => i * delay)
.attr('transform', d => `translate(${d.p})`)
.attr('x2', d => d.curvature.elements[0])
.attr('y2', d => d.curvature.elements[1])
button.text('morph circuit to circle')
} else {
lines
.transition()
.duration(duration)
.delay((d, i) => i * delay)
.attr(
'transform',
d =>
`translate(${d.c[0] * d.radius + d.origin[0]}, ${d.c[1] * d.radius +
d.origin[1]})`
)
.attr(
'x2',
d => d.c[0] * d.curvature.modulus() * (d.isConcave ? -1 : 1)
)
.attr(
'y2',
d => d.c[1] * d.curvature.modulus() * (d.isConcave ? -1 : 1)
)
button.text('morph circle to circuit')
}
showCurvature = !showCurvature
}
magic()
button.on('click', magic)
}
export default drawTrack
{
"standard": {
"globals": [
"drivers",
"circuitTracks",
"d3",
"$V",
"_"
]
}
}
$black = #010b14
$white = #dacbed
$blue = #0fd0fe
$yellow = #f6df83
$lightblue = darken($blue, 35%)
$red = lighten(#f11c07, 20%)
$blur-radius = 14px
$text-blur-opacity = 0.75
$svg-blur-opacity = 1
$font-family = 'VT323', monospace
*
box-sizing border-box
html
background alpha($black, 0.5)
padding 0
margin 0
body
background $black
font-family $font-family
overflow hidden
margin 0 auto
padding 0
position relative
width 960px
height 500px
// // border solid $white 1px
svg
display block
h1
// visibility hidden
color $white
text-shadow 0 0 $blur-radius alpha($white, $text-blur-opacity)
text-transform uppercase
font-weight normal
font-style italic
position absolute
text-align center
padding 0
margin 0
width 100%
font-size 2.5em
span
color $red
button
// visibility hidden
display block
margin 0 auto
font-family $font-family
border solid $white 1px
background $black
color $white
font-size 2em
text-transform uppercase
position relative
top -1em
cursor pointer
.circuit
width 50%
position relative
margin 0 auto
padding 0
svg
margin 0 auto
filter drop-shadow(0 0 $blur-radius alpha($red, $svg-blur-opacity))
path.track
fill none
stroke $blue
opacity 0.2
circle
&.p
fill $white
&.q
fill $red
line
stroke $red
text
fill $red
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j<k;j++){o(M.4[j][i]!=0){1c=[];1s=1n;J{p=1n-1s;1c.19(M.4[i][p]+M.4[j][p])}H(--1s);M.4[i]=1c;1I}}}o(M.4[i][i]!=0){2e(j=i+1;j<k;j++){9 a=M.4[j][i]/M.4[i][i];1c=[];1s=1n;J{p=1n-1s;1c.19(p<=i?0:M.4[j][p]-M.4[i][p]*a)}H(--1s);M.4[j]=1c}}}H(--n);8 M},3h:l(){8 7.1K()},2z:l(){o(!7.1y()){8 w}9 M=7.1K();9 a=M.4[0][0],n=M.4.q-1,k=n,i;J{i=k-n+1;a=a*M.4[i][i]}H(--n);8 a},3f:l(){8 7.2z()},2y:l(){8(7.1y()&&7.2z()===0)},2Y:l(){o(!7.1y()){8 w}9 a=7.4[0][0],n=7.4.q-1,k=n,i;J{i=k-n+1;a+=7.4[i][i]}H(--n);8 a},3e:l(){8 7.2Y()},1Y:l(){9 M=7.1K(),1Y=0;9 a=7.4.q,15=a,i,G,10=7.4[0].q,j;J{i=15-a;G=10;J{j=10-G;o(F.13(M.4[i][j])>17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j<i;j++){1c=[];b=1n;J{p=1n-b;1c.19(M.4[j][p]-M.4[i][p]*M.4[j][i])}H(--b);M.4[j]=1c}}H(--a);8 S.u(c)},3c:l(){8 7.2w()},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(p){8(F.13(p-x)<=17.16)?x:p})},2n:l(){9 a=[];9 n=7.4.q,k=n,i;J{i=k-n;a.19(v.u(7.4[i]).2n())}H(--n);8 a.2K(\'\\n\')},26:l(a){9 i,4=a.4||a;o(1g(4[0][0])!=\'1f\'){9 b=4.q,15=b,G,10,j;7.4=[];J{i=15-b;G=4[i].q;10=G;7.4[i]=[];J{j=10-G;7.4[i][j]=4[i][j]}H(--G)}H(--b);8 7}9 n=4.q,k=n;7.4=[];J{i=k-n;7.4.19([4[i]])}H(--n);8 7}};S.u=l(a){9 M=25 S();8 M.26(a)};S.I=l(n){9 a=[],k=n,i,G,j;J{i=k-n;a[i]=[];G=k;J{j=k-G;a[i][j]=(i==j)?1:0}H(--G)}H(--n);8 S.u(a)};S.2X=l(a){9 n=a.q,k=n,i;9 M=S.I(n);J{i=k-n;M.4[i][i]=a[i]}H(--n);8 M};S.1R=l(b,a){o(!a){8 S.u([[F.1H(b),-F.1G(b)],[F.1G(b),F.1H(b)]])}9 d=a.1q();o(d.4.q!=3){8 w}9 e=d.1u();9 x=d.4[0]/e,y=d.4[1]/e,z=d.4[2]/e;9 s=F.1G(b),c=F.1H(b),t=1-c;8 S.u([[t*x*x+c,t*x*y-s*z,t*x*z+s*y],[t*x*y+s*z,t*y*y+c,t*y*z-s*x],[t*x*z-s*y,t*y*z+s*x,t*z*z+c]])};S.3b=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[1,0,0],[0,c,-s],[0,s,c]])};S.39=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,0,s],[0,1,0],[-s,0,c]])};S.38=l(t){9 c=F.1H(t),s=F.1G(t);8 S.u([[c,-s,0],[s,c,0],[0,0,1]])};S.2J=l(n,m){8 S.1j(n,m).1b(l(){8 F.2F()})};S.1j=l(n,m){9 a=[],12=n,i,G,j;J{i=n-12;a[i]=[];G=m;J{j=m-G;a[i][j]=0}H(--G)}H(--12);8 S.u(a)};l 14(){}14.23={24:l(a){8(7.1m(a)&&7.1h(a.K))},1q:l(){8 14.u(7.K,7.U)},2U:l(a){9 V=a.4||a;8 14.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.U)},1m:l(a){o(a.W){8 a.1m(7)}9 b=7.U.1C(a.U);8(F.13(b)<=17.16||F.13(b-F.1A)<=17.16)},1o:l(a){o(a.W){8 a.1o(7)}o(a.U){o(7.1m(a)){8 7.1o(a.K)}9 N=7.U.2f(a.U).2q().4;9 A=7.K.4,B=a.K.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,D=7.U.4;9 b=P[0]-A[0],2a=P[1]-A[1],29=(P[2]||0)-A[2];9 c=F.1x(b*b+2a*2a+29*29);o(c===0)8 0;9 d=(b*D[0]+2a*D[1]+29*D[2])/c;9 e=1-d*d;8 F.13(c*F.1x(e<0?0:e))}},1h:l(a){9 b=7.1o(a);8(b!==w&&b<=17.16)},2T:l(a){8 a.1h(7)},1v:l(a){o(a.W){8 a.1v(7)}8(!7.1m(a)&&7.1o(a)<=17.16)},1U:l(a){o(a.W){8 a.1U(7)}o(!7.1v(a)){8 w}9 P=7.K.4,X=7.U.4,Q=a.K.4,Y=a.U.4;9 b=X[0],1z=X[1],1B=X[2],1T=Y[0],1S=Y[1],1M=Y[2];9 c=P[0]-Q[0],2s=P[1]-Q[1],2r=P[2]-Q[2];9 d=-b*c-1z*2s-1B*2r;9 e=1T*c+1S*2s+1M*2r;9 f=b*b+1z*1z+1B*1B;9 g=1T*1T+1S*1S+1M*1M;9 h=b*1T+1z*1S+1B*1M;9 k=(d*g/f+h*e)/(g-h*h);8 v.u([P[0]+k*b,P[1]+k*1z,P[2]+k*1B])},1r:l(a){o(a.U){o(7.1v(a)){8 7.1U(a)}o(7.1m(a)){8 w}9 D=7.U.4,E=a.U.4;9 b=D[0],1l=D[1],1k=D[2],1P=E[0],1O=E[1],1Q=E[2];9 x=(1k*1P-b*1Q),y=(b*1O-1l*1P),z=(1l*1Q-1k*1O);9 N=v.u([x*1Q-y*1O,y*1P-z*1Q,z*1O-x*1P]);9 P=11.u(a.K,N);8 P.1U(7)}1d{9 P=a.4||a;o(7.1h(P)){8 v.u(P)}9 A=7.K.4,D=7.U.4;9 b=D[0],1l=D[1],1k=D[2],1w=A[0],18=A[1],1a=A[2];9 x=b*(P[1]-18)-1l*(P[0]-1w),y=1l*((P[2]||0)-1a)-1k*(P[1]-18),z=1k*(P[0]-1w)-b*((P[2]||0)-1a);9 V=v.u([1l*x-1k*z,1k*y-b*x,b*z-1l*y]);9 k=7.1o(P)/V.1u();8 v.u([P[0]+V.4[0]*k,P[1]+V.4[1]*k,(P[2]||0)+V.4[2]*k])}},1V:l(t,a){o(1g(a.U)==\'1f\'){a=14.u(a.1N(),v.k)}9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,D=7.U.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 14.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*D[0]+R[0][1]*D[1]+R[0][2]*D[2],R[1][0]*D[0]+R[1][1]*D[1]+R[1][2]*D[2],R[2][0]*D[0]+R[2][1]*D[1]+R[2][2]*D[2]])},1t:l(a){o(a.W){9 A=7.K.4,D=7.U.4;9 b=A[0],18=A[1],1a=A[2],2N=D[0],1l=D[1],1k=D[2];9 c=7.K.1t(a).4;9 d=b+2N,2h=18+1l,2o=1a+1k;9 Q=a.1r([d,2h,2o]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2h)-c[1],Q[2]+(Q[2]-2o)-c[2]];8 14.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 14.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.U)}},1Z:l(a,b){a=v.u(a);b=v.u(b);o(a.4.q==2){a.4.19(0)}o(b.4.q==2){b.4.19(0)}o(a.4.q>3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{}))