From eb910b81746ee4ec0af08fb1dc4d7b890598d4ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Mar 2021 20:49:09 +0000 Subject: [PATCH 1/8] Bump three from 0.123.0 to 0.125.0 Bumps [three](https://github.com/mrdoob/three.js) from 0.123.0 to 0.125.0. - [Release notes](https://github.com/mrdoob/three.js/releases) - [Commits](https://github.com/mrdoob/three.js/commits) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83614e6d..a0dc23f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7733,9 +7733,9 @@ } }, "three": { - "version": "0.123.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.123.0.tgz", - "integrity": "sha512-KNnx/IbilvoHRkxOtL0ouozoDoElyuvAXhFB21RK7F5IPWSmqyFelICK6x3hJerLNSlAdHxR0hkuvMMhH9pqXg==" + "version": "0.125.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.125.0.tgz", + "integrity": "sha512-qL36qUGsPQ/Ofo/RZdXwHwM7A8wzUSAIyawtjIebJSPvounUQeneSqxI0aBY2iwKpseGy+RUtj3C5f/z4poyXw==" }, "three-orbitcontrols": { "version": "2.110.3", diff --git a/package.json b/package.json index ee6d8f14..fd477cbb 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "deploy": "firebase deploy --only hosting" }, "dependencies": { - "three": "^0.123.0", + "three": "^0.125.0", "three-orbitcontrols": "^2.110.3" } } From df43b6e86fb403eb52e25c969ebbc7228736f990 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Apr 2021 02:18:19 +0000 Subject: [PATCH 2/8] Bump y18n from 4.0.0 to 4.0.1 Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1. - [Release notes](https://github.com/yargs/y18n/releases) - [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md) - [Commits](https://github.com/yargs/y18n/commits) Signed-off-by: dependabot[bot] --- package-lock.json | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83614e6d..ba74aad3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4208,6 +4208,12 @@ "has-flag": "^4.0.0" } }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, "yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", @@ -5275,6 +5281,12 @@ "has-flag": "^4.0.0" } }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, "yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", @@ -8350,9 +8362,9 @@ "dev": true }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", "dev": true }, "yallist": { @@ -8422,12 +8434,6 @@ "strip-ansi": "^6.0.0" } }, - "y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", - "dev": true - }, "yargs-parser": { "version": "20.2.4", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", From d65fd01e3def959460e9a6178a77fb9c232236d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 17:41:13 +0000 Subject: [PATCH 3/8] Bump lodash from 4.17.20 to 4.17.21 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1f2c9e1..cf43c27c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5881,9 +5881,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash.memoize": { From 410e336dd270fd247f72ab0fc0f61bd5e0396bdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 19:48:25 +0000 Subject: [PATCH 4/8] Bump hosted-git-info from 2.8.8 to 2.8.9 Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9. - [Release notes](https://github.com/npm/hosted-git-info/releases) - [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md) - [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1f2c9e1..8074b0a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3658,9 +3658,9 @@ } }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "html-encoding-sniffer": { From 9989bd455806cc9fe82344cab1eff3fa2d244525 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 May 2021 13:44:15 +0000 Subject: [PATCH 5/8] Bump ws from 7.4.0 to 7.4.6 Bumps [ws](https://github.com/websockets/ws) from 7.4.0 to 7.4.6. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/7.4.0...7.4.6) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf43c27c..c630cbc5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8338,9 +8338,9 @@ } }, "ws": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz", - "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "dev": true }, "xml-name-validator": { From a42671ce10e09c2c9ebffef9e7ded87ec66e6019 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Fri, 4 Jun 2021 22:02:59 +0200 Subject: [PATCH 6/8] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a293034c..19aa3ae9 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,10 @@ or #### Javascript ``` + import * as GCodePreview from "gcode-preview"; + const gcode = 'G0 X0 Y0 Z0.2\nG1 X42 Y42'; // draw a diagonal line - const preview = new WebGLPreview({ + const preview = new GCodePreview.WebGLPreview({ targetId: 'gcode-preview', }); From b7aec39f5481c2ea83765923d88454a52a260516 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Sat, 5 Jun 2021 14:58:05 +0200 Subject: [PATCH 7/8] Parse and keep feedrate param --- demo/dist/gcode-preview.js | 2 +- dist/gcode-parser.d.ts | 2 +- dist/gcode-preview.es.js | 2 +- dist/gcode-preview.js | 2 +- src/gcode-parser.ts | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/demo/dist/gcode-preview.js b/demo/dist/gcode-preview.js index 2b4dac54..0862c5e4 100644 --- a/demo/dist/gcode-preview.js +++ b/demo/dist/gcode-preview.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("three"),require("three-orbitcontrols")):"function"==typeof define&&define.amd?define(["exports","three","three-orbitcontrols"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).GCodePreview={},t.THREE,t.THREE.OrbitControls)}(this,(function(t,e,n){"use strict";var i="default"in e?e.default:e;class r extends class{constructor(t,e){this.gcode=t,this.comment=e}}{constructor(t,e,n){super(t,n),this.params=e}}class s{constructor(t,e){this.layer=t,this.commands=e}}class a{constructor(){this.layers=[],this.curZ=0,this.maxZ=0}parseCommand(t,e=!0){const n=t.trim().split(";"),i=n[0],s=e&&n[1]||null,a=i.split(/ +/g),o=a[0].toLowerCase();switch(o){case"g0":case"g1":const t=this.parseMove(a.slice(1));return new r(o,t,s);default:return null}}parseMove(t){return t.reduce(((t,e)=>{const n=e.charAt(0).toLowerCase();return"x"!=n&&"y"!=n&&"z"!=n&&"e"!=n||(t[n]=parseFloat(e.slice(1))),t}),{})}groupIntoLayers(t){for(const e of t.filter((t=>t instanceof r))){const t=e.params;t.z&&(this.curZ=t.z),t.e>0&&(null!=t.x||null!=t.y)&&this.curZ>this.maxZ?(this.maxZ=this.curZ,this.currentLayer=new s(this.layers.length,[e]),this.layers.push(this.currentLayer)):this.currentLayer&&this.currentLayer.commands.push(e)}return this.layers}parseGcode(t){const e=Array.isArray(t)?t:t.split("\n").filter((t=>t.length>0)),n=this.lines2commands(e);return this.groupIntoLayers(n),{layers:this.layers}}lines2commands(t){return t.filter((t=>t.length>0)).map((t=>this.parseCommand(t))).filter((t=>null!==t))}}e.UniformsLib.line={linewidth:{value:1},resolution:{value:new e.Vector2(1,1)},dashScale:{value:1},dashSize:{value:1},gapSize:{value:1}},e.ShaderLib.line={uniforms:e.UniformsUtils.merge([e.UniformsLib.common,e.UniformsLib.fog,e.UniformsLib.line]),vertexShader:"\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tuniform float linewidth;\n\t\tuniform vec2 resolution;\n\n\t\tattribute vec3 instanceStart;\n\t\tattribute vec3 instanceEnd;\n\n\t\tattribute vec3 instanceColorStart;\n\t\tattribute vec3 instanceColorEnd;\n\n\t\tvarying vec2 vUv;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashScale;\n\t\t\tattribute float instanceDistanceStart;\n\t\t\tattribute float instanceDistanceEnd;\n\t\t\tvarying float vLineDistance;\n\n\t\t#endif\n\n\t\tvoid trimSegment( const in vec4 start, inout vec4 end ) {\n\n\t\t\t// trim end segment so it terminates between the camera plane and the near plane\n\n\t\t\t// conservative estimate of the near plane\n\t\t\tfloat a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column\n\t\t\tfloat b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column\n\t\t\tfloat nearEstimate = - 0.5 * b / a;\n\n\t\t\tfloat alpha = ( nearEstimate - start.z ) / ( end.z - start.z );\n\n\t\t\tend.xyz = mix( start.xyz, end.xyz, alpha );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\t#ifdef USE_COLOR\n\n\t\t\t\tvColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;\n\n\t\t\t#endif\n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tvLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;\n\n\t\t\t#endif\n\n\t\t\tfloat aspect = resolution.x / resolution.y;\n\n\t\t\tvUv = uv;\n\n\t\t\t// camera space\n\t\t\tvec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );\n\t\t\tvec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );\n\n\t\t\t// special case for perspective projection, and segments that terminate either in, or behind, the camera plane\n\t\t\t// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space\n\t\t\t// but we need to perform ndc-space calculations in the shader, so we must address this issue directly\n\t\t\t// perhaps there is a more elegant solution -- WestLangley\n\n\t\t\tbool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column\n\n\t\t\tif ( perspective ) {\n\n\t\t\t\tif ( start.z < 0.0 && end.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( start, end );\n\n\t\t\t\t} else if ( end.z < 0.0 && start.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( end, start );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// clip space\n\t\t\tvec4 clipStart = projectionMatrix * start;\n\t\t\tvec4 clipEnd = projectionMatrix * end;\n\n\t\t\t// ndc space\n\t\t\tvec2 ndcStart = clipStart.xy / clipStart.w;\n\t\t\tvec2 ndcEnd = clipEnd.xy / clipEnd.w;\n\n\t\t\t// direction\n\t\t\tvec2 dir = ndcEnd - ndcStart;\n\n\t\t\t// account for clip-space aspect ratio\n\t\t\tdir.x *= aspect;\n\t\t\tdir = normalize( dir );\n\n\t\t\t// perpendicular to dir\n\t\t\tvec2 offset = vec2( dir.y, - dir.x );\n\n\t\t\t// undo aspect ratio adjustment\n\t\t\tdir.x /= aspect;\n\t\t\toffset.x /= aspect;\n\n\t\t\t// sign flip\n\t\t\tif ( position.x < 0.0 ) offset *= - 1.0;\n\n\t\t\t// endcaps\n\t\t\tif ( position.y < 0.0 ) {\n\n\t\t\t\toffset += - dir;\n\n\t\t\t} else if ( position.y > 1.0 ) {\n\n\t\t\t\toffset += dir;\n\n\t\t\t}\n\n\t\t\t// adjust for linewidth\n\t\t\toffset *= linewidth;\n\n\t\t\t// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...\n\t\t\toffset /= resolution.y;\n\n\t\t\t// select end\n\t\t\tvec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;\n\n\t\t\t// back to clip space\n\t\t\toffset *= clip.w;\n\n\t\t\tclip.xy += offset;\n\n\t\t\tgl_Position = clip;\n\n\t\t\tvec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t",fragmentShader:"\n\t\tuniform vec3 diffuse;\n\t\tuniform float opacity;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashSize;\n\t\t\tuniform float gapSize;\n\n\t\t#endif\n\n\t\tvarying float vLineDistance;\n\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\t#include \n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tif ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps\n\n\t\t\t\tif ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX\n\n\t\t\t#endif\n\n\t\t\tif ( abs( vUv.y ) > 1.0 ) {\n\n\t\t\t\tfloat a = vUv.x;\n\t\t\t\tfloat b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;\n\t\t\t\tfloat len2 = a * a + b * b;\n\n\t\t\t\tif ( len2 > 1.0 ) discard;\n\n\t\t\t}\n\n\t\t\tvec4 diffuseColor = vec4( diffuse, opacity );\n\n\t\t\t#include \n\t\t\t#include \n\n\t\t\tgl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t"};var o=function(t){e.ShaderMaterial.call(this,{type:"LineMaterial",uniforms:e.UniformsUtils.clone(e.ShaderLib.line.uniforms),vertexShader:e.ShaderLib.line.vertexShader,fragmentShader:e.ShaderLib.line.fragmentShader,clipping:!0}),this.dashed=!1,Object.defineProperties(this,{color:{enumerable:!0,get:function(){return this.uniforms.diffuse.value},set:function(t){this.uniforms.diffuse.value=t}},linewidth:{enumerable:!0,get:function(){return this.uniforms.linewidth.value},set:function(t){this.uniforms.linewidth.value=t}},dashScale:{enumerable:!0,get:function(){return this.uniforms.dashScale.value},set:function(t){this.uniforms.dashScale.value=t}},dashSize:{enumerable:!0,get:function(){return this.uniforms.dashSize.value},set:function(t){this.uniforms.dashSize.value=t}},gapSize:{enumerable:!0,get:function(){return this.uniforms.gapSize.value},set:function(t){this.uniforms.gapSize.value=t}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(t){this.uniforms.resolution.value.copy(t)}}}),this.setValues(t)};(o.prototype=Object.create(e.ShaderMaterial.prototype)).constructor=o,o.prototype.isLineMaterial=!0;var l,c=function(){e.InstancedBufferGeometry.call(this),this.type="LineSegmentsGeometry";this.setIndex([0,2,1,2,3,1,2,4,3,4,5,3,4,6,5,6,7,5]),this.setAttribute("position",new e.Float32BufferAttribute([-1,2,0,1,2,0,-1,1,0,1,1,0,-1,0,0,1,0,0,-1,-1,0,1,-1,0],3)),this.setAttribute("uv",new e.Float32BufferAttribute([-1,2,1,2,-1,1,1,1,-1,-1,1,-1,-1,-2,1,-2],2))};c.prototype=Object.assign(Object.create(e.InstancedBufferGeometry.prototype),{constructor:c,isLineSegmentsGeometry:!0,applyMatrix4:function(t){var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;return void 0!==e&&(e.applyMatrix4(t),n.applyMatrix4(t),e.data.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},setPositions:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceEnd",new e.InterleavedBufferAttribute(i,3,3)),this.computeBoundingBox(),this.computeBoundingSphere(),this},setColors:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceColorStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceColorEnd",new e.InterleavedBufferAttribute(i,3,3)),this},fromWireframeGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromEdgesGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromMesh:function(t){return this.fromWireframeGeometry(new e.WireframeGeometry(t.geometry)),this},fromLineSegements:function(t){var e=t.geometry;return e.isGeometry?this.setPositions(e.vertices):e.isBufferGeometry&&this.setPositions(e.position.array),this},computeBoundingBox:function(){var t=new e.Box3;return function(){null===this.boundingBox&&(this.boundingBox=new e.Box3);var n=this.attributes.instanceStart,i=this.attributes.instanceEnd;void 0!==n&&void 0!==i&&(this.boundingBox.setFromBufferAttribute(n),t.setFromBufferAttribute(i),this.boundingBox.union(t))}}(),computeBoundingSphere:(l=new e.Vector3,function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere),null===this.boundingBox&&this.computeBoundingBox();var t=this.attributes.instanceStart,n=this.attributes.instanceEnd;if(void 0!==t&&void 0!==n){var i=this.boundingSphere.center;this.boundingBox.getCenter(i);for(var r=0,s=0,a=t.count;s1&&n.z>1;if(!S&&!L){t.x*=m.x/2,t.y*=m.y/2,n.x*=m.x/2,n.y*=m.y/2,a.start.copy(t),a.start.z=0,a.end.copy(n),a.end.z=0;var A=a.closestPointToPointParameter(r,!0);a.at(A,o);var B=e.MathUtils.lerp(t.z,n.z,A),z=B>=-1&&B<=1,M=r.distanceTo(o)<.5*y;if(z&&M){a.start.fromBufferAttribute(v,x),a.end.fromBufferAttribute(g,x),a.start.applyMatrix4(b),a.end.applyMatrix4(b);var C=new e.Vector3,E=new e.Vector3;u.distanceSqToSegment(a.start,a.end,E,C),c.push({point:E,pointOnLine:C,distance:u.origin.distanceTo(E),object:this,face:null,faceIndex:x,uv:null,uv2:null})}}}}}()});class p extends e.LineSegments{constructor(t,n,i,r,s=4473924,a=8947848){s=new e.Color(s),a=new e.Color(a);var o=Math.round(t/n);i=Math.round(i/r)*r/2;const l=[],c=[];let u=0;for(var d=-1*(t=o*n/2);d<=t;d+=n){l.push(d,0,-1*i,d,0,i),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}for(d=-1*i;d<=i;d+=r){var h;l.push(-1*t,0,d,t,0,d),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}const f=new e.BufferGeometry;f.setAttribute("position",new e.Float32BufferAttribute(l,3)),f.setAttribute("color",new e.Float32BufferAttribute(c,3));super(f,new e.LineBasicMaterial({vertexColors:!0,toneMapped:!1})),this.type="BuildVolume"}}function m(t,e,n,r){const s=function(t,e,n,r){t*=.5,e*=.5,n*=.5;const s=new i.BufferGeometry,a=[];return a.push(-t,-e,-n,-t,e,-n,-t,e,-n,t,e,-n,t,e,-n,t,-e,-n,t,-e,-n,-t,-e,-n,-t,-e,n,-t,e,n,-t,e,n,t,e,n,t,e,n,t,-e,n,t,-e,n,-t,-e,n,-t,-e,-n,-t,-e,n,-t,e,-n,-t,e,n,t,e,-n,t,e,n,t,-e,-n,t,-e,n),s.setAttribute("position",new i.Float32BufferAttribute(a,3)),s}(t,e,n),a=new i.LineSegments(s,new i.LineDashedMaterial({color:new i.Color(r),dashSize:3,gapSize:1}));return a.computeLineDistances(),a}t.WebGLPreview=class{constructor(t){var i,r;if(this.parser=new a,this.backgroundColor=14737632,this.travelColor=10027008,this.extrusionColor=65280,this.renderExtrusion=!0,this.renderTravel=!1,this.singleLayerMode=!1,this.initialCameraPosition=[-100,400,450],this.debug=!1,this.scene=new e.Scene,this.scene.background=new e.Color(this.backgroundColor),this.canvas=t.canvas,this.targetId=t.targetId,this.endLayer=t.endLayer,this.startLayer=t.startLayer,this.topLayerColor=t.topLayerColor,this.lastSegmentColor=t.lastSegmentColor,this.lineWidth=t.lineWidth,this.buildVolume=t.buildVolume,this.initialCameraPosition=null!==(i=t.initialCameraPosition)&&void 0!==i?i:this.initialCameraPosition,this.debug=null!==(r=t.debug)&&void 0!==r?r:this.debug,console.debug("opts",t),!this.canvas&&!this.targetId)throw Error("Set either opts.canvas or opts.targetId");if(this.canvas)this.renderer=new e.WebGLRenderer({canvas:this.canvas,preserveDrawingBuffer:!0});else{const t=document.getElementById(this.targetId);if(!t)throw new Error("Unable to find element "+this.targetId);this.renderer=new e.WebGLRenderer({preserveDrawingBuffer:!0}),this.canvas=this.renderer.domElement,t.appendChild(this.canvas)}this.camera=new e.PerspectiveCamera(25,this.canvas.offsetWidth/this.canvas.offsetHeight,10,5e3),this.camera.position.fromArray(this.initialCameraPosition);const s=this.camera.far,o=.8*s;this.scene.fog=new e.Fog(this.scene.background,o,s),this.resize();new n(this.camera,this.renderer.domElement);this.animate()}get layers(){return this.parser.layers}get maxLayerIndex(){var t;return(null!==(t=this.endLayer)&&void 0!==t?t:this.layers.length)-1}get minLayerIndex(){var t;return this.singleLayerMode?this.maxLayerIndex:(null!==(t=this.startLayer)&&void 0!==t?t:0)-1}animate(){requestAnimationFrame((()=>this.animate())),this.renderer.render(this.scene,this.camera)}processGCode(t){this.parser.parseGcode(t),this.render()}render(){for(var t,n;this.scene.children.length>0;)this.scene.remove(this.scene.children[0]);if(this.debug){const t=new e.AxesHelper(Math.max(this.buildVolume.x/2,this.buildVolume.y/2)+20);this.scene.add(t)}this.buildVolume&&this.drawBuildVolume(),this.group=new e.Group,this.group.name="gcode";const i={x:0,y:0,z:0,e:0};for(let r=0;rthis.maxLayerIndex);r++){const s={extrusion:[],travel:[],z:i.z},a=this.layers[r];for(const t of a.commands)if("g0"==t.gcode||"g1"==t.gcode){const e=t,n={x:void 0!==e.params.x?e.params.x:i.x,y:void 0!==e.params.y?e.params.y:i.y,z:void 0!==e.params.z?e.params.z:i.z,e:void 0!==e.params.e?e.params.e:i.e};if(r>=this.minLayerIndex){const t=e.params.e>0;(t&&this.renderExtrusion||!t&&this.renderTravel)&&this.addLineSegment(s,i,n,t)}e.params.x&&(i.x=e.params.x),e.params.y&&(i.y=e.params.y),e.params.z&&(i.z=e.params.z),e.params.e&&(i.e=e.params.e)}if(this.renderExtrusion){const i=Math.round(80*r/this.layers.length),a=new e.Color(`hsl(0, 0%, ${i}%)`).getHex();if(r==this.layers.length-1){const e=null!==(t=this.topLayerColor)&&void 0!==t?t:a,i=null!==(n=this.lastSegmentColor)&&void 0!==n?n:e,r=s.extrusion.splice(-3);this.addLine(s.extrusion,e);const o=s.extrusion.splice(-3);this.addLine([...o,...r],i)}else this.addLine(s.extrusion,a)}this.renderTravel&&this.addLine(s.travel,this.travelColor)}this.group.quaternion.setFromEuler(new e.Euler(-Math.PI/2,0,0)),this.buildVolume?this.group.position.set(-this.buildVolume.x/2,0,this.buildVolume.y/2):this.group.position.set(-100,0,100),this.scene.add(this.group),this.renderer.render(this.scene,this.camera)}drawBuildVolume(){this.scene.add(new p(this.buildVolume.x,10,this.buildVolume.y,10));const t=m(this.buildVolume.x,this.buildVolume.z,this.buildVolume.y,8947848);t.position.setY(this.buildVolume.z/2),this.scene.add(t)}clear(){this.startLayer=1,this.endLayer=1/0,this.singleLayerMode=!1,this.parser=new a}resize(){const[t,e]=[this.canvas.offsetWidth,this.canvas.offsetHeight];this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,e,!1)}addLineSegment(t,e,n,i){(i?t.extrusion:t.travel).push(e.x,e.y,e.z,n.x,n.y,n.z)}addLine(t,n){if("number"==typeof this.lineWidth&&this.lineWidth>0)return void this.addThickLine(t,n);const i=new e.BufferGeometry;i.setAttribute("position",new e.Float32BufferAttribute(t,3));const r=new e.LineBasicMaterial({color:n}),s=new e.LineSegments(i,r);this.group.add(s)}addThickLine(t,e){if(!t.length)return;const n=new u,i=new o({color:e,linewidth:this.lineWidth/(1e3*window.devicePixelRatio)});n.setPositions(t);const r=new f(n,i);this.group.add(r)}},Object.defineProperty(t,"__esModule",{value:!0})})); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("three"),require("three-orbitcontrols")):"function"==typeof define&&define.amd?define(["exports","three","three-orbitcontrols"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).GCodePreview={},t.THREE,t.THREE.OrbitControls)}(this,(function(t,e,n){"use strict";var i="default"in e?e.default:e;class r extends class{constructor(t,e){this.gcode=t,this.comment=e}}{constructor(t,e,n){super(t,n),this.params=e}}class s{constructor(t,e){this.layer=t,this.commands=e}}class a{constructor(){this.layers=[],this.curZ=0,this.maxZ=0}parseCommand(t,e=!0){const n=t.trim().split(";"),i=n[0],s=e&&n[1]||null,a=i.split(/ +/g),o=a[0].toLowerCase();switch(o){case"g0":case"g1":const t=this.parseMove(a.slice(1));return new r(o,t,s);default:return null}}parseMove(t){return t.reduce(((t,e)=>{const n=e.charAt(0).toLowerCase();return"x"!=n&&"y"!=n&&"z"!=n&&"e"!=n&&"f"!=n||(t[n]=parseFloat(e.slice(1))),t}),{})}groupIntoLayers(t){for(const e of t.filter((t=>t instanceof r))){const t=e.params;t.z&&(this.curZ=t.z),t.e>0&&(null!=t.x||null!=t.y)&&this.curZ>this.maxZ?(this.maxZ=this.curZ,this.currentLayer=new s(this.layers.length,[e]),this.layers.push(this.currentLayer)):this.currentLayer&&this.currentLayer.commands.push(e)}return this.layers}parseGcode(t){const e=Array.isArray(t)?t:t.split("\n").filter((t=>t.length>0)),n=this.lines2commands(e);return this.groupIntoLayers(n),{layers:this.layers}}lines2commands(t){return t.filter((t=>t.length>0)).map((t=>this.parseCommand(t))).filter((t=>null!==t))}}e.UniformsLib.line={linewidth:{value:1},resolution:{value:new e.Vector2(1,1)},dashScale:{value:1},dashSize:{value:1},gapSize:{value:1}},e.ShaderLib.line={uniforms:e.UniformsUtils.merge([e.UniformsLib.common,e.UniformsLib.fog,e.UniformsLib.line]),vertexShader:"\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tuniform float linewidth;\n\t\tuniform vec2 resolution;\n\n\t\tattribute vec3 instanceStart;\n\t\tattribute vec3 instanceEnd;\n\n\t\tattribute vec3 instanceColorStart;\n\t\tattribute vec3 instanceColorEnd;\n\n\t\tvarying vec2 vUv;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashScale;\n\t\t\tattribute float instanceDistanceStart;\n\t\t\tattribute float instanceDistanceEnd;\n\t\t\tvarying float vLineDistance;\n\n\t\t#endif\n\n\t\tvoid trimSegment( const in vec4 start, inout vec4 end ) {\n\n\t\t\t// trim end segment so it terminates between the camera plane and the near plane\n\n\t\t\t// conservative estimate of the near plane\n\t\t\tfloat a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column\n\t\t\tfloat b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column\n\t\t\tfloat nearEstimate = - 0.5 * b / a;\n\n\t\t\tfloat alpha = ( nearEstimate - start.z ) / ( end.z - start.z );\n\n\t\t\tend.xyz = mix( start.xyz, end.xyz, alpha );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\t#ifdef USE_COLOR\n\n\t\t\t\tvColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;\n\n\t\t\t#endif\n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tvLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;\n\n\t\t\t#endif\n\n\t\t\tfloat aspect = resolution.x / resolution.y;\n\n\t\t\tvUv = uv;\n\n\t\t\t// camera space\n\t\t\tvec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );\n\t\t\tvec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );\n\n\t\t\t// special case for perspective projection, and segments that terminate either in, or behind, the camera plane\n\t\t\t// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space\n\t\t\t// but we need to perform ndc-space calculations in the shader, so we must address this issue directly\n\t\t\t// perhaps there is a more elegant solution -- WestLangley\n\n\t\t\tbool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column\n\n\t\t\tif ( perspective ) {\n\n\t\t\t\tif ( start.z < 0.0 && end.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( start, end );\n\n\t\t\t\t} else if ( end.z < 0.0 && start.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( end, start );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// clip space\n\t\t\tvec4 clipStart = projectionMatrix * start;\n\t\t\tvec4 clipEnd = projectionMatrix * end;\n\n\t\t\t// ndc space\n\t\t\tvec2 ndcStart = clipStart.xy / clipStart.w;\n\t\t\tvec2 ndcEnd = clipEnd.xy / clipEnd.w;\n\n\t\t\t// direction\n\t\t\tvec2 dir = ndcEnd - ndcStart;\n\n\t\t\t// account for clip-space aspect ratio\n\t\t\tdir.x *= aspect;\n\t\t\tdir = normalize( dir );\n\n\t\t\t// perpendicular to dir\n\t\t\tvec2 offset = vec2( dir.y, - dir.x );\n\n\t\t\t// undo aspect ratio adjustment\n\t\t\tdir.x /= aspect;\n\t\t\toffset.x /= aspect;\n\n\t\t\t// sign flip\n\t\t\tif ( position.x < 0.0 ) offset *= - 1.0;\n\n\t\t\t// endcaps\n\t\t\tif ( position.y < 0.0 ) {\n\n\t\t\t\toffset += - dir;\n\n\t\t\t} else if ( position.y > 1.0 ) {\n\n\t\t\t\toffset += dir;\n\n\t\t\t}\n\n\t\t\t// adjust for linewidth\n\t\t\toffset *= linewidth;\n\n\t\t\t// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...\n\t\t\toffset /= resolution.y;\n\n\t\t\t// select end\n\t\t\tvec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;\n\n\t\t\t// back to clip space\n\t\t\toffset *= clip.w;\n\n\t\t\tclip.xy += offset;\n\n\t\t\tgl_Position = clip;\n\n\t\t\tvec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t",fragmentShader:"\n\t\tuniform vec3 diffuse;\n\t\tuniform float opacity;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashSize;\n\t\t\tuniform float gapSize;\n\n\t\t#endif\n\n\t\tvarying float vLineDistance;\n\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\t#include \n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tif ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps\n\n\t\t\t\tif ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX\n\n\t\t\t#endif\n\n\t\t\tif ( abs( vUv.y ) > 1.0 ) {\n\n\t\t\t\tfloat a = vUv.x;\n\t\t\t\tfloat b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;\n\t\t\t\tfloat len2 = a * a + b * b;\n\n\t\t\t\tif ( len2 > 1.0 ) discard;\n\n\t\t\t}\n\n\t\t\tvec4 diffuseColor = vec4( diffuse, opacity );\n\n\t\t\t#include \n\t\t\t#include \n\n\t\t\tgl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t"};var o=function(t){e.ShaderMaterial.call(this,{type:"LineMaterial",uniforms:e.UniformsUtils.clone(e.ShaderLib.line.uniforms),vertexShader:e.ShaderLib.line.vertexShader,fragmentShader:e.ShaderLib.line.fragmentShader,clipping:!0}),this.dashed=!1,Object.defineProperties(this,{color:{enumerable:!0,get:function(){return this.uniforms.diffuse.value},set:function(t){this.uniforms.diffuse.value=t}},linewidth:{enumerable:!0,get:function(){return this.uniforms.linewidth.value},set:function(t){this.uniforms.linewidth.value=t}},dashScale:{enumerable:!0,get:function(){return this.uniforms.dashScale.value},set:function(t){this.uniforms.dashScale.value=t}},dashSize:{enumerable:!0,get:function(){return this.uniforms.dashSize.value},set:function(t){this.uniforms.dashSize.value=t}},gapSize:{enumerable:!0,get:function(){return this.uniforms.gapSize.value},set:function(t){this.uniforms.gapSize.value=t}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(t){this.uniforms.resolution.value.copy(t)}}}),this.setValues(t)};(o.prototype=Object.create(e.ShaderMaterial.prototype)).constructor=o,o.prototype.isLineMaterial=!0;var l,c=function(){e.InstancedBufferGeometry.call(this),this.type="LineSegmentsGeometry";this.setIndex([0,2,1,2,3,1,2,4,3,4,5,3,4,6,5,6,7,5]),this.setAttribute("position",new e.Float32BufferAttribute([-1,2,0,1,2,0,-1,1,0,1,1,0,-1,0,0,1,0,0,-1,-1,0,1,-1,0],3)),this.setAttribute("uv",new e.Float32BufferAttribute([-1,2,1,2,-1,1,1,1,-1,-1,1,-1,-1,-2,1,-2],2))};c.prototype=Object.assign(Object.create(e.InstancedBufferGeometry.prototype),{constructor:c,isLineSegmentsGeometry:!0,applyMatrix4:function(t){var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;return void 0!==e&&(e.applyMatrix4(t),n.applyMatrix4(t),e.data.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},setPositions:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceEnd",new e.InterleavedBufferAttribute(i,3,3)),this.computeBoundingBox(),this.computeBoundingSphere(),this},setColors:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceColorStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceColorEnd",new e.InterleavedBufferAttribute(i,3,3)),this},fromWireframeGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromEdgesGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromMesh:function(t){return this.fromWireframeGeometry(new e.WireframeGeometry(t.geometry)),this},fromLineSegements:function(t){var e=t.geometry;return e.isGeometry?this.setPositions(e.vertices):e.isBufferGeometry&&this.setPositions(e.position.array),this},computeBoundingBox:function(){var t=new e.Box3;return function(){null===this.boundingBox&&(this.boundingBox=new e.Box3);var n=this.attributes.instanceStart,i=this.attributes.instanceEnd;void 0!==n&&void 0!==i&&(this.boundingBox.setFromBufferAttribute(n),t.setFromBufferAttribute(i),this.boundingBox.union(t))}}(),computeBoundingSphere:(l=new e.Vector3,function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere),null===this.boundingBox&&this.computeBoundingBox();var t=this.attributes.instanceStart,n=this.attributes.instanceEnd;if(void 0!==t&&void 0!==n){var i=this.boundingSphere.center;this.boundingBox.getCenter(i);for(var r=0,s=0,a=t.count;s1&&n.z>1;if(!S&&!L){t.x*=m.x/2,t.y*=m.y/2,n.x*=m.x/2,n.y*=m.y/2,a.start.copy(t),a.start.z=0,a.end.copy(n),a.end.z=0;var A=a.closestPointToPointParameter(r,!0);a.at(A,o);var B=e.MathUtils.lerp(t.z,n.z,A),z=B>=-1&&B<=1,M=r.distanceTo(o)<.5*y;if(z&&M){a.start.fromBufferAttribute(v,x),a.end.fromBufferAttribute(g,x),a.start.applyMatrix4(b),a.end.applyMatrix4(b);var C=new e.Vector3,E=new e.Vector3;u.distanceSqToSegment(a.start,a.end,E,C),c.push({point:E,pointOnLine:C,distance:u.origin.distanceTo(E),object:this,face:null,faceIndex:x,uv:null,uv2:null})}}}}}()});class p extends e.LineSegments{constructor(t,n,i,r,s=4473924,a=8947848){s=new e.Color(s),a=new e.Color(a);var o=Math.round(t/n);i=Math.round(i/r)*r/2;const l=[],c=[];let u=0;for(var d=-1*(t=o*n/2);d<=t;d+=n){l.push(d,0,-1*i,d,0,i),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}for(d=-1*i;d<=i;d+=r){var h;l.push(-1*t,0,d,t,0,d),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}const f=new e.BufferGeometry;f.setAttribute("position",new e.Float32BufferAttribute(l,3)),f.setAttribute("color",new e.Float32BufferAttribute(c,3));super(f,new e.LineBasicMaterial({vertexColors:!0,toneMapped:!1})),this.type="BuildVolume"}}function m(t,e,n,r){const s=function(t,e,n,r){t*=.5,e*=.5,n*=.5;const s=new i.BufferGeometry,a=[];return a.push(-t,-e,-n,-t,e,-n,-t,e,-n,t,e,-n,t,e,-n,t,-e,-n,t,-e,-n,-t,-e,-n,-t,-e,n,-t,e,n,-t,e,n,t,e,n,t,e,n,t,-e,n,t,-e,n,-t,-e,n,-t,-e,-n,-t,-e,n,-t,e,-n,-t,e,n,t,e,-n,t,e,n,t,-e,-n,t,-e,n),s.setAttribute("position",new i.Float32BufferAttribute(a,3)),s}(t,e,n),a=new i.LineSegments(s,new i.LineDashedMaterial({color:new i.Color(r),dashSize:3,gapSize:1}));return a.computeLineDistances(),a}t.WebGLPreview=class{constructor(t){var i,r;if(this.parser=new a,this.backgroundColor=14737632,this.travelColor=10027008,this.extrusionColor=65280,this.renderExtrusion=!0,this.renderTravel=!1,this.singleLayerMode=!1,this.initialCameraPosition=[-100,400,450],this.debug=!1,this.scene=new e.Scene,this.scene.background=new e.Color(this.backgroundColor),this.canvas=t.canvas,this.targetId=t.targetId,this.endLayer=t.endLayer,this.startLayer=t.startLayer,this.topLayerColor=t.topLayerColor,this.lastSegmentColor=t.lastSegmentColor,this.lineWidth=t.lineWidth,this.buildVolume=t.buildVolume,this.initialCameraPosition=null!==(i=t.initialCameraPosition)&&void 0!==i?i:this.initialCameraPosition,this.debug=null!==(r=t.debug)&&void 0!==r?r:this.debug,console.debug("opts",t),!this.canvas&&!this.targetId)throw Error("Set either opts.canvas or opts.targetId");if(this.canvas)this.renderer=new e.WebGLRenderer({canvas:this.canvas,preserveDrawingBuffer:!0});else{const t=document.getElementById(this.targetId);if(!t)throw new Error("Unable to find element "+this.targetId);this.renderer=new e.WebGLRenderer({preserveDrawingBuffer:!0}),this.canvas=this.renderer.domElement,t.appendChild(this.canvas)}this.camera=new e.PerspectiveCamera(25,this.canvas.offsetWidth/this.canvas.offsetHeight,10,5e3),this.camera.position.fromArray(this.initialCameraPosition);const s=this.camera.far,o=.8*s;this.scene.fog=new e.Fog(this.scene.background,o,s),this.resize();new n(this.camera,this.renderer.domElement);this.animate()}get layers(){return this.parser.layers}get maxLayerIndex(){var t;return(null!==(t=this.endLayer)&&void 0!==t?t:this.layers.length)-1}get minLayerIndex(){var t;return this.singleLayerMode?this.maxLayerIndex:(null!==(t=this.startLayer)&&void 0!==t?t:0)-1}animate(){requestAnimationFrame((()=>this.animate())),this.renderer.render(this.scene,this.camera)}processGCode(t){this.parser.parseGcode(t),this.render()}render(){for(var t,n;this.scene.children.length>0;)this.scene.remove(this.scene.children[0]);if(this.debug){const t=new e.AxesHelper(Math.max(this.buildVolume.x/2,this.buildVolume.y/2)+20);this.scene.add(t)}this.buildVolume&&this.drawBuildVolume(),this.group=new e.Group,this.group.name="gcode";const i={x:0,y:0,z:0,e:0};for(let r=0;rthis.maxLayerIndex);r++){const s={extrusion:[],travel:[],z:i.z},a=this.layers[r];for(const t of a.commands)if("g0"==t.gcode||"g1"==t.gcode){const e=t,n={x:void 0!==e.params.x?e.params.x:i.x,y:void 0!==e.params.y?e.params.y:i.y,z:void 0!==e.params.z?e.params.z:i.z,e:void 0!==e.params.e?e.params.e:i.e};if(r>=this.minLayerIndex){const t=e.params.e>0;(t&&this.renderExtrusion||!t&&this.renderTravel)&&this.addLineSegment(s,i,n,t)}e.params.x&&(i.x=e.params.x),e.params.y&&(i.y=e.params.y),e.params.z&&(i.z=e.params.z),e.params.e&&(i.e=e.params.e)}if(this.renderExtrusion){const i=Math.round(80*r/this.layers.length),a=new e.Color(`hsl(0, 0%, ${i}%)`).getHex();if(r==this.layers.length-1){const e=null!==(t=this.topLayerColor)&&void 0!==t?t:a,i=null!==(n=this.lastSegmentColor)&&void 0!==n?n:e,r=s.extrusion.splice(-3);this.addLine(s.extrusion,e);const o=s.extrusion.splice(-3);this.addLine([...o,...r],i)}else this.addLine(s.extrusion,a)}this.renderTravel&&this.addLine(s.travel,this.travelColor)}this.group.quaternion.setFromEuler(new e.Euler(-Math.PI/2,0,0)),this.buildVolume?this.group.position.set(-this.buildVolume.x/2,0,this.buildVolume.y/2):this.group.position.set(-100,0,100),this.scene.add(this.group),this.renderer.render(this.scene,this.camera)}drawBuildVolume(){this.scene.add(new p(this.buildVolume.x,10,this.buildVolume.y,10));const t=m(this.buildVolume.x,this.buildVolume.z,this.buildVolume.y,8947848);t.position.setY(this.buildVolume.z/2),this.scene.add(t)}clear(){this.startLayer=1,this.endLayer=1/0,this.singleLayerMode=!1,this.parser=new a}resize(){const[t,e]=[this.canvas.offsetWidth,this.canvas.offsetHeight];this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,e,!1)}addLineSegment(t,e,n,i){(i?t.extrusion:t.travel).push(e.x,e.y,e.z,n.x,n.y,n.z)}addLine(t,n){if("number"==typeof this.lineWidth&&this.lineWidth>0)return void this.addThickLine(t,n);const i=new e.BufferGeometry;i.setAttribute("position",new e.Float32BufferAttribute(t,3));const r=new e.LineBasicMaterial({color:n}),s=new e.LineSegments(i,r);this.group.add(s)}addThickLine(t,e){if(!t.length)return;const n=new u,i=new o({color:e,linewidth:this.lineWidth/(1e3*window.devicePixelRatio)});n.setPositions(t);const r=new f(n,i);this.group.add(r)}},Object.defineProperty(t,"__esModule",{value:!0})})); diff --git a/dist/gcode-parser.d.ts b/dist/gcode-parser.d.ts index b729c138..6298186c 100644 --- a/dist/gcode-parser.d.ts +++ b/dist/gcode-parser.d.ts @@ -7,7 +7,7 @@ export declare class MoveCommand extends GCodeCommand { params: MoveCommandParams; constructor(gcode: string, params: MoveCommandParams, comment?: string); } -declare type MoveCommandParamName = 'x' | 'y' | 'z' | 'e'; +declare type MoveCommandParamName = 'x' | 'y' | 'z' | 'e' | 'f'; declare type MoveCommandParams = { [key in MoveCommandParamName]?: number; }; diff --git a/dist/gcode-preview.es.js b/dist/gcode-preview.es.js index db2b67f5..eeca49f8 100644 --- a/dist/gcode-preview.es.js +++ b/dist/gcode-preview.es.js @@ -1 +1 @@ -import t,{UniformsLib as e,Vector2 as n,ShaderLib as i,UniformsUtils as r,ShaderMaterial as s,InstancedBufferGeometry as a,InstancedInterleavedBuffer as o,InterleavedBufferAttribute as c,WireframeGeometry as l,Box3 as u,Vector3 as d,Sphere as h,Float32BufferAttribute as p,Mesh as f,Vector4 as m,Matrix4 as y,Line3 as v,MathUtils as g,LineSegments as x,Color as b,BufferGeometry as w,LineBasicMaterial as S,Scene as L,WebGLRenderer as z,PerspectiveCamera as A,Fog as M,AxesHelper as C,Group as E,Euler as B}from"three";import*as _ from"three-orbitcontrols";class P extends class{constructor(t,e){this.gcode=t,this.comment=e}}{constructor(t,e,n){super(t,n),this.params=e}}class j{constructor(t,e){this.layer=t,this.commands=e}}class I{constructor(){this.layers=[],this.curZ=0,this.maxZ=0}parseCommand(t,e=!0){const n=t.trim().split(";"),i=n[0],r=e&&n[1]||null,s=i.split(/ +/g),a=s[0].toLowerCase();switch(a){case"g0":case"g1":const t=this.parseMove(s.slice(1));return new P(a,t,r);default:return null}}parseMove(t){return t.reduce(((t,e)=>{const n=e.charAt(0).toLowerCase();return"x"!=n&&"y"!=n&&"z"!=n&&"e"!=n||(t[n]=parseFloat(e.slice(1))),t}),{})}groupIntoLayers(t){for(const e of t.filter((t=>t instanceof P))){const t=e.params;t.z&&(this.curZ=t.z),t.e>0&&(null!=t.x||null!=t.y)&&this.curZ>this.maxZ?(this.maxZ=this.curZ,this.currentLayer=new j(this.layers.length,[e]),this.layers.push(this.currentLayer)):this.currentLayer&&this.currentLayer.commands.push(e)}return this.layers}parseGcode(t){const e=Array.isArray(t)?t:t.split("\n").filter((t=>t.length>0)),n=this.lines2commands(e);return this.groupIntoLayers(n),{layers:this.layers}}lines2commands(t){return t.filter((t=>t.length>0)).map((t=>this.parseCommand(t))).filter((t=>null!==t))}}e.line={linewidth:{value:1},resolution:{value:new n(1,1)},dashScale:{value:1},dashSize:{value:1},gapSize:{value:1}},i.line={uniforms:r.merge([e.common,e.fog,e.line]),vertexShader:"\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tuniform float linewidth;\n\t\tuniform vec2 resolution;\n\n\t\tattribute vec3 instanceStart;\n\t\tattribute vec3 instanceEnd;\n\n\t\tattribute vec3 instanceColorStart;\n\t\tattribute vec3 instanceColorEnd;\n\n\t\tvarying vec2 vUv;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashScale;\n\t\t\tattribute float instanceDistanceStart;\n\t\t\tattribute float instanceDistanceEnd;\n\t\t\tvarying float vLineDistance;\n\n\t\t#endif\n\n\t\tvoid trimSegment( const in vec4 start, inout vec4 end ) {\n\n\t\t\t// trim end segment so it terminates between the camera plane and the near plane\n\n\t\t\t// conservative estimate of the near plane\n\t\t\tfloat a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column\n\t\t\tfloat b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column\n\t\t\tfloat nearEstimate = - 0.5 * b / a;\n\n\t\t\tfloat alpha = ( nearEstimate - start.z ) / ( end.z - start.z );\n\n\t\t\tend.xyz = mix( start.xyz, end.xyz, alpha );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\t#ifdef USE_COLOR\n\n\t\t\t\tvColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;\n\n\t\t\t#endif\n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tvLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;\n\n\t\t\t#endif\n\n\t\t\tfloat aspect = resolution.x / resolution.y;\n\n\t\t\tvUv = uv;\n\n\t\t\t// camera space\n\t\t\tvec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );\n\t\t\tvec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );\n\n\t\t\t// special case for perspective projection, and segments that terminate either in, or behind, the camera plane\n\t\t\t// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space\n\t\t\t// but we need to perform ndc-space calculations in the shader, so we must address this issue directly\n\t\t\t// perhaps there is a more elegant solution -- WestLangley\n\n\t\t\tbool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column\n\n\t\t\tif ( perspective ) {\n\n\t\t\t\tif ( start.z < 0.0 && end.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( start, end );\n\n\t\t\t\t} else if ( end.z < 0.0 && start.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( end, start );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// clip space\n\t\t\tvec4 clipStart = projectionMatrix * start;\n\t\t\tvec4 clipEnd = projectionMatrix * end;\n\n\t\t\t// ndc space\n\t\t\tvec2 ndcStart = clipStart.xy / clipStart.w;\n\t\t\tvec2 ndcEnd = clipEnd.xy / clipEnd.w;\n\n\t\t\t// direction\n\t\t\tvec2 dir = ndcEnd - ndcStart;\n\n\t\t\t// account for clip-space aspect ratio\n\t\t\tdir.x *= aspect;\n\t\t\tdir = normalize( dir );\n\n\t\t\t// perpendicular to dir\n\t\t\tvec2 offset = vec2( dir.y, - dir.x );\n\n\t\t\t// undo aspect ratio adjustment\n\t\t\tdir.x /= aspect;\n\t\t\toffset.x /= aspect;\n\n\t\t\t// sign flip\n\t\t\tif ( position.x < 0.0 ) offset *= - 1.0;\n\n\t\t\t// endcaps\n\t\t\tif ( position.y < 0.0 ) {\n\n\t\t\t\toffset += - dir;\n\n\t\t\t} else if ( position.y > 1.0 ) {\n\n\t\t\t\toffset += dir;\n\n\t\t\t}\n\n\t\t\t// adjust for linewidth\n\t\t\toffset *= linewidth;\n\n\t\t\t// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...\n\t\t\toffset /= resolution.y;\n\n\t\t\t// select end\n\t\t\tvec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;\n\n\t\t\t// back to clip space\n\t\t\toffset *= clip.w;\n\n\t\t\tclip.xy += offset;\n\n\t\t\tgl_Position = clip;\n\n\t\t\tvec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t",fragmentShader:"\n\t\tuniform vec3 diffuse;\n\t\tuniform float opacity;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashSize;\n\t\t\tuniform float gapSize;\n\n\t\t#endif\n\n\t\tvarying float vLineDistance;\n\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\t#include \n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tif ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps\n\n\t\t\t\tif ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX\n\n\t\t\t#endif\n\n\t\t\tif ( abs( vUv.y ) > 1.0 ) {\n\n\t\t\t\tfloat a = vUv.x;\n\t\t\t\tfloat b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;\n\t\t\t\tfloat len2 = a * a + b * b;\n\n\t\t\t\tif ( len2 > 1.0 ) discard;\n\n\t\t\t}\n\n\t\t\tvec4 diffuseColor = vec4( diffuse, opacity );\n\n\t\t\t#include \n\t\t\t#include \n\n\t\t\tgl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t"};var V=function(t){s.call(this,{type:"LineMaterial",uniforms:r.clone(i.line.uniforms),vertexShader:i.line.vertexShader,fragmentShader:i.line.fragmentShader,clipping:!0}),this.dashed=!1,Object.defineProperties(this,{color:{enumerable:!0,get:function(){return this.uniforms.diffuse.value},set:function(t){this.uniforms.diffuse.value=t}},linewidth:{enumerable:!0,get:function(){return this.uniforms.linewidth.value},set:function(t){this.uniforms.linewidth.value=t}},dashScale:{enumerable:!0,get:function(){return this.uniforms.dashScale.value},set:function(t){this.uniforms.dashScale.value=t}},dashSize:{enumerable:!0,get:function(){return this.uniforms.dashSize.value},set:function(t){this.uniforms.dashSize.value=t}},gapSize:{enumerable:!0,get:function(){return this.uniforms.gapSize.value},set:function(t){this.uniforms.gapSize.value=t}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(t){this.uniforms.resolution.value.copy(t)}}}),this.setValues(t)};(V.prototype=Object.create(s.prototype)).constructor=V,V.prototype.isLineMaterial=!0;var D,G=function(){a.call(this),this.type="LineSegmentsGeometry";this.setIndex([0,2,1,2,3,1,2,4,3,4,5,3,4,6,5,6,7,5]),this.setAttribute("position",new p([-1,2,0,1,2,0,-1,1,0,1,1,0,-1,0,0,1,0,0,-1,-1,0,1,-1,0],3)),this.setAttribute("uv",new p([-1,2,1,2,-1,1,1,1,-1,-1,1,-1,-1,-2,1,-2],2))};G.prototype=Object.assign(Object.create(a.prototype),{constructor:G,isLineSegmentsGeometry:!0,applyMatrix4:function(t){var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;return void 0!==e&&(e.applyMatrix4(t),n.applyMatrix4(t),e.data.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},setPositions:function(t){var e;t instanceof Float32Array?e=t:Array.isArray(t)&&(e=new Float32Array(t));var n=new o(e,6,1);return this.setAttribute("instanceStart",new c(n,3,0)),this.setAttribute("instanceEnd",new c(n,3,3)),this.computeBoundingBox(),this.computeBoundingSphere(),this},setColors:function(t){var e;t instanceof Float32Array?e=t:Array.isArray(t)&&(e=new Float32Array(t));var n=new o(e,6,1);return this.setAttribute("instanceColorStart",new c(n,3,0)),this.setAttribute("instanceColorEnd",new c(n,3,3)),this},fromWireframeGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromEdgesGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromMesh:function(t){return this.fromWireframeGeometry(new l(t.geometry)),this},fromLineSegements:function(t){var e=t.geometry;return e.isGeometry?this.setPositions(e.vertices):e.isBufferGeometry&&this.setPositions(e.position.array),this},computeBoundingBox:function(){var t=new u;return function(){null===this.boundingBox&&(this.boundingBox=new u);var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;void 0!==e&&void 0!==n&&(this.boundingBox.setFromBufferAttribute(e),t.setFromBufferAttribute(n),this.boundingBox.union(t))}}(),computeBoundingSphere:(D=new d,function(){null===this.boundingSphere&&(this.boundingSphere=new h),null===this.boundingBox&&this.computeBoundingBox();var t=this.attributes.instanceStart,e=this.attributes.instanceEnd;if(void 0!==t&&void 0!==e){var n=this.boundingSphere.center;this.boundingBox.getCenter(n);for(var i=0,r=0,s=t.count;r1&&e.z>1;if(!L&&!z){t.x*=m.x/2,t.y*=m.y/2,e.x*=m.x/2,e.y*=m.y/2,s.start.copy(t),s.start.z=0,s.end.copy(e),s.end.z=0;var A=s.closestPointToPointParameter(i,!0);s.at(A,a);var M=g.lerp(t.z,e.z,A),C=M>=-1&&M<=1,E=i.distanceTo(a)<.5*y;if(C&&E){s.start.fromBufferAttribute(v,w),s.end.fromBufferAttribute(x,w),s.start.applyMatrix4(b),s.end.applyMatrix4(b);var B=new d,_=new d;l.distanceSqToSegment(s.start,s.end,_,B),c.push({point:_,pointOnLine:B,distance:l.origin.distanceTo(_),object:this,face:null,faceIndex:w,uv:null,uv2:null})}}}}}()});class O extends x{constructor(t,e,n,i,r=4473924,s=8947848){r=new b(r),s=new b(s);var a=Math.round(t/e);n=Math.round(n/i)*i/2;const o=[],c=[];let l=0;for(var u=-1*(t=a*e/2);u<=t;u+=e){o.push(u,0,-1*n,u,0,n),(d=0===u?r:s).toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3}for(u=-1*n;u<=n;u+=i){var d;o.push(-1*t,0,u,t,0,u),(d=0===u?r:s).toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3}const h=new w;h.setAttribute("position",new p(o,3)),h.setAttribute("color",new p(c,3));super(h,new S({vertexColors:!0,toneMapped:!1})),this.type="BuildVolume"}}function H(e,n,i,r){const s=function(e,n,i,r){e*=.5,n*=.5,i*=.5;const s=new t.BufferGeometry,a=[];return a.push(-e,-n,-i,-e,n,-i,-e,n,-i,e,n,-i,e,n,-i,e,-n,-i,e,-n,-i,-e,-n,-i,-e,-n,i,-e,n,i,-e,n,i,e,n,i,e,n,i,e,-n,i,e,-n,i,-e,-n,i,-e,-n,-i,-e,-n,i,-e,n,-i,-e,n,i,e,n,-i,e,n,i,e,-n,-i,e,-n,i),s.setAttribute("position",new t.Float32BufferAttribute(a,3)),s}(e,n,i),a=new t.LineSegments(s,new t.LineDashedMaterial({color:new t.Color(r),dashSize:3,gapSize:1}));return a.computeLineDistances(),a}class k{constructor(t){var e,n;if(this.parser=new I,this.backgroundColor=14737632,this.travelColor=10027008,this.extrusionColor=65280,this.renderExtrusion=!0,this.renderTravel=!1,this.singleLayerMode=!1,this.initialCameraPosition=[-100,400,450],this.debug=!1,this.scene=new L,this.scene.background=new b(this.backgroundColor),this.canvas=t.canvas,this.targetId=t.targetId,this.endLayer=t.endLayer,this.startLayer=t.startLayer,this.topLayerColor=t.topLayerColor,this.lastSegmentColor=t.lastSegmentColor,this.lineWidth=t.lineWidth,this.buildVolume=t.buildVolume,this.initialCameraPosition=null!==(e=t.initialCameraPosition)&&void 0!==e?e:this.initialCameraPosition,this.debug=null!==(n=t.debug)&&void 0!==n?n:this.debug,console.debug("opts",t),!this.canvas&&!this.targetId)throw Error("Set either opts.canvas or opts.targetId");if(this.canvas)this.renderer=new z({canvas:this.canvas,preserveDrawingBuffer:!0});else{const t=document.getElementById(this.targetId);if(!t)throw new Error("Unable to find element "+this.targetId);this.renderer=new z({preserveDrawingBuffer:!0}),this.canvas=this.renderer.domElement,t.appendChild(this.canvas)}this.camera=new A(25,this.canvas.offsetWidth/this.canvas.offsetHeight,10,5e3),this.camera.position.fromArray(this.initialCameraPosition);const i=this.camera.far,r=.8*i;this.scene.fog=new M(this.scene.background,r,i),this.resize();new _(this.camera,this.renderer.domElement);this.animate()}get layers(){return this.parser.layers}get maxLayerIndex(){var t;return(null!==(t=this.endLayer)&&void 0!==t?t:this.layers.length)-1}get minLayerIndex(){var t;return this.singleLayerMode?this.maxLayerIndex:(null!==(t=this.startLayer)&&void 0!==t?t:0)-1}animate(){requestAnimationFrame((()=>this.animate())),this.renderer.render(this.scene,this.camera)}processGCode(t){this.parser.parseGcode(t),this.render()}render(){for(var t,e;this.scene.children.length>0;)this.scene.remove(this.scene.children[0]);if(this.debug){const t=new C(Math.max(this.buildVolume.x/2,this.buildVolume.y/2)+20);this.scene.add(t)}this.buildVolume&&this.drawBuildVolume(),this.group=new E,this.group.name="gcode";const n={x:0,y:0,z:0,e:0};for(let i=0;ithis.maxLayerIndex);i++){const r={extrusion:[],travel:[],z:n.z},s=this.layers[i];for(const t of s.commands)if("g0"==t.gcode||"g1"==t.gcode){const e=t,s={x:void 0!==e.params.x?e.params.x:n.x,y:void 0!==e.params.y?e.params.y:n.y,z:void 0!==e.params.z?e.params.z:n.z,e:void 0!==e.params.e?e.params.e:n.e};if(i>=this.minLayerIndex){const t=e.params.e>0;(t&&this.renderExtrusion||!t&&this.renderTravel)&&this.addLineSegment(r,n,s,t)}e.params.x&&(n.x=e.params.x),e.params.y&&(n.y=e.params.y),e.params.z&&(n.z=e.params.z),e.params.e&&(n.e=e.params.e)}if(this.renderExtrusion){const n=Math.round(80*i/this.layers.length),s=new b(`hsl(0, 0%, ${n}%)`).getHex();if(i==this.layers.length-1){const n=null!==(t=this.topLayerColor)&&void 0!==t?t:s,i=null!==(e=this.lastSegmentColor)&&void 0!==e?e:n,a=r.extrusion.splice(-3);this.addLine(r.extrusion,n);const o=r.extrusion.splice(-3);this.addLine([...o,...a],i)}else this.addLine(r.extrusion,s)}this.renderTravel&&this.addLine(r.travel,this.travelColor)}this.group.quaternion.setFromEuler(new B(-Math.PI/2,0,0)),this.buildVolume?this.group.position.set(-this.buildVolume.x/2,0,this.buildVolume.y/2):this.group.position.set(-100,0,100),this.scene.add(this.group),this.renderer.render(this.scene,this.camera)}drawBuildVolume(){this.scene.add(new O(this.buildVolume.x,10,this.buildVolume.y,10));const t=H(this.buildVolume.x,this.buildVolume.z,this.buildVolume.y,8947848);t.position.setY(this.buildVolume.z/2),this.scene.add(t)}clear(){this.startLayer=1,this.endLayer=1/0,this.singleLayerMode=!1,this.parser=new I}resize(){const[t,e]=[this.canvas.offsetWidth,this.canvas.offsetHeight];this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,e,!1)}addLineSegment(t,e,n,i){(i?t.extrusion:t.travel).push(e.x,e.y,e.z,n.x,n.y,n.z)}addLine(t,e){if("number"==typeof this.lineWidth&&this.lineWidth>0)return void this.addThickLine(t,e);const n=new w;n.setAttribute("position",new p(t,3));const i=new S({color:e}),r=new x(n,i);this.group.add(r)}addThickLine(t,e){if(!t.length)return;const n=new U,i=new V({color:e,linewidth:this.lineWidth/(1e3*window.devicePixelRatio)});n.setPositions(t);const r=new W(n,i);this.group.add(r)}}export{k as WebGLPreview}; +import t,{UniformsLib as e,Vector2 as n,ShaderLib as i,UniformsUtils as r,ShaderMaterial as s,InstancedBufferGeometry as a,InstancedInterleavedBuffer as o,InterleavedBufferAttribute as c,WireframeGeometry as l,Box3 as u,Vector3 as d,Sphere as h,Float32BufferAttribute as p,Mesh as f,Vector4 as m,Matrix4 as y,Line3 as v,MathUtils as g,LineSegments as x,Color as b,BufferGeometry as w,LineBasicMaterial as S,Scene as L,WebGLRenderer as z,PerspectiveCamera as A,Fog as M,AxesHelper as C,Group as E,Euler as B}from"three";import*as _ from"three-orbitcontrols";class P extends class{constructor(t,e){this.gcode=t,this.comment=e}}{constructor(t,e,n){super(t,n),this.params=e}}class j{constructor(t,e){this.layer=t,this.commands=e}}class I{constructor(){this.layers=[],this.curZ=0,this.maxZ=0}parseCommand(t,e=!0){const n=t.trim().split(";"),i=n[0],r=e&&n[1]||null,s=i.split(/ +/g),a=s[0].toLowerCase();switch(a){case"g0":case"g1":const t=this.parseMove(s.slice(1));return new P(a,t,r);default:return null}}parseMove(t){return t.reduce(((t,e)=>{const n=e.charAt(0).toLowerCase();return"x"!=n&&"y"!=n&&"z"!=n&&"e"!=n&&"f"!=n||(t[n]=parseFloat(e.slice(1))),t}),{})}groupIntoLayers(t){for(const e of t.filter((t=>t instanceof P))){const t=e.params;t.z&&(this.curZ=t.z),t.e>0&&(null!=t.x||null!=t.y)&&this.curZ>this.maxZ?(this.maxZ=this.curZ,this.currentLayer=new j(this.layers.length,[e]),this.layers.push(this.currentLayer)):this.currentLayer&&this.currentLayer.commands.push(e)}return this.layers}parseGcode(t){const e=Array.isArray(t)?t:t.split("\n").filter((t=>t.length>0)),n=this.lines2commands(e);return this.groupIntoLayers(n),{layers:this.layers}}lines2commands(t){return t.filter((t=>t.length>0)).map((t=>this.parseCommand(t))).filter((t=>null!==t))}}e.line={linewidth:{value:1},resolution:{value:new n(1,1)},dashScale:{value:1},dashSize:{value:1},gapSize:{value:1}},i.line={uniforms:r.merge([e.common,e.fog,e.line]),vertexShader:"\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tuniform float linewidth;\n\t\tuniform vec2 resolution;\n\n\t\tattribute vec3 instanceStart;\n\t\tattribute vec3 instanceEnd;\n\n\t\tattribute vec3 instanceColorStart;\n\t\tattribute vec3 instanceColorEnd;\n\n\t\tvarying vec2 vUv;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashScale;\n\t\t\tattribute float instanceDistanceStart;\n\t\t\tattribute float instanceDistanceEnd;\n\t\t\tvarying float vLineDistance;\n\n\t\t#endif\n\n\t\tvoid trimSegment( const in vec4 start, inout vec4 end ) {\n\n\t\t\t// trim end segment so it terminates between the camera plane and the near plane\n\n\t\t\t// conservative estimate of the near plane\n\t\t\tfloat a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column\n\t\t\tfloat b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column\n\t\t\tfloat nearEstimate = - 0.5 * b / a;\n\n\t\t\tfloat alpha = ( nearEstimate - start.z ) / ( end.z - start.z );\n\n\t\t\tend.xyz = mix( start.xyz, end.xyz, alpha );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\t#ifdef USE_COLOR\n\n\t\t\t\tvColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;\n\n\t\t\t#endif\n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tvLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;\n\n\t\t\t#endif\n\n\t\t\tfloat aspect = resolution.x / resolution.y;\n\n\t\t\tvUv = uv;\n\n\t\t\t// camera space\n\t\t\tvec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );\n\t\t\tvec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );\n\n\t\t\t// special case for perspective projection, and segments that terminate either in, or behind, the camera plane\n\t\t\t// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space\n\t\t\t// but we need to perform ndc-space calculations in the shader, so we must address this issue directly\n\t\t\t// perhaps there is a more elegant solution -- WestLangley\n\n\t\t\tbool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column\n\n\t\t\tif ( perspective ) {\n\n\t\t\t\tif ( start.z < 0.0 && end.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( start, end );\n\n\t\t\t\t} else if ( end.z < 0.0 && start.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( end, start );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// clip space\n\t\t\tvec4 clipStart = projectionMatrix * start;\n\t\t\tvec4 clipEnd = projectionMatrix * end;\n\n\t\t\t// ndc space\n\t\t\tvec2 ndcStart = clipStart.xy / clipStart.w;\n\t\t\tvec2 ndcEnd = clipEnd.xy / clipEnd.w;\n\n\t\t\t// direction\n\t\t\tvec2 dir = ndcEnd - ndcStart;\n\n\t\t\t// account for clip-space aspect ratio\n\t\t\tdir.x *= aspect;\n\t\t\tdir = normalize( dir );\n\n\t\t\t// perpendicular to dir\n\t\t\tvec2 offset = vec2( dir.y, - dir.x );\n\n\t\t\t// undo aspect ratio adjustment\n\t\t\tdir.x /= aspect;\n\t\t\toffset.x /= aspect;\n\n\t\t\t// sign flip\n\t\t\tif ( position.x < 0.0 ) offset *= - 1.0;\n\n\t\t\t// endcaps\n\t\t\tif ( position.y < 0.0 ) {\n\n\t\t\t\toffset += - dir;\n\n\t\t\t} else if ( position.y > 1.0 ) {\n\n\t\t\t\toffset += dir;\n\n\t\t\t}\n\n\t\t\t// adjust for linewidth\n\t\t\toffset *= linewidth;\n\n\t\t\t// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...\n\t\t\toffset /= resolution.y;\n\n\t\t\t// select end\n\t\t\tvec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;\n\n\t\t\t// back to clip space\n\t\t\toffset *= clip.w;\n\n\t\t\tclip.xy += offset;\n\n\t\t\tgl_Position = clip;\n\n\t\t\tvec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t",fragmentShader:"\n\t\tuniform vec3 diffuse;\n\t\tuniform float opacity;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashSize;\n\t\t\tuniform float gapSize;\n\n\t\t#endif\n\n\t\tvarying float vLineDistance;\n\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\t#include \n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tif ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps\n\n\t\t\t\tif ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX\n\n\t\t\t#endif\n\n\t\t\tif ( abs( vUv.y ) > 1.0 ) {\n\n\t\t\t\tfloat a = vUv.x;\n\t\t\t\tfloat b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;\n\t\t\t\tfloat len2 = a * a + b * b;\n\n\t\t\t\tif ( len2 > 1.0 ) discard;\n\n\t\t\t}\n\n\t\t\tvec4 diffuseColor = vec4( diffuse, opacity );\n\n\t\t\t#include \n\t\t\t#include \n\n\t\t\tgl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t"};var V=function(t){s.call(this,{type:"LineMaterial",uniforms:r.clone(i.line.uniforms),vertexShader:i.line.vertexShader,fragmentShader:i.line.fragmentShader,clipping:!0}),this.dashed=!1,Object.defineProperties(this,{color:{enumerable:!0,get:function(){return this.uniforms.diffuse.value},set:function(t){this.uniforms.diffuse.value=t}},linewidth:{enumerable:!0,get:function(){return this.uniforms.linewidth.value},set:function(t){this.uniforms.linewidth.value=t}},dashScale:{enumerable:!0,get:function(){return this.uniforms.dashScale.value},set:function(t){this.uniforms.dashScale.value=t}},dashSize:{enumerable:!0,get:function(){return this.uniforms.dashSize.value},set:function(t){this.uniforms.dashSize.value=t}},gapSize:{enumerable:!0,get:function(){return this.uniforms.gapSize.value},set:function(t){this.uniforms.gapSize.value=t}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(t){this.uniforms.resolution.value.copy(t)}}}),this.setValues(t)};(V.prototype=Object.create(s.prototype)).constructor=V,V.prototype.isLineMaterial=!0;var D,G=function(){a.call(this),this.type="LineSegmentsGeometry";this.setIndex([0,2,1,2,3,1,2,4,3,4,5,3,4,6,5,6,7,5]),this.setAttribute("position",new p([-1,2,0,1,2,0,-1,1,0,1,1,0,-1,0,0,1,0,0,-1,-1,0,1,-1,0],3)),this.setAttribute("uv",new p([-1,2,1,2,-1,1,1,1,-1,-1,1,-1,-1,-2,1,-2],2))};G.prototype=Object.assign(Object.create(a.prototype),{constructor:G,isLineSegmentsGeometry:!0,applyMatrix4:function(t){var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;return void 0!==e&&(e.applyMatrix4(t),n.applyMatrix4(t),e.data.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},setPositions:function(t){var e;t instanceof Float32Array?e=t:Array.isArray(t)&&(e=new Float32Array(t));var n=new o(e,6,1);return this.setAttribute("instanceStart",new c(n,3,0)),this.setAttribute("instanceEnd",new c(n,3,3)),this.computeBoundingBox(),this.computeBoundingSphere(),this},setColors:function(t){var e;t instanceof Float32Array?e=t:Array.isArray(t)&&(e=new Float32Array(t));var n=new o(e,6,1);return this.setAttribute("instanceColorStart",new c(n,3,0)),this.setAttribute("instanceColorEnd",new c(n,3,3)),this},fromWireframeGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromEdgesGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromMesh:function(t){return this.fromWireframeGeometry(new l(t.geometry)),this},fromLineSegements:function(t){var e=t.geometry;return e.isGeometry?this.setPositions(e.vertices):e.isBufferGeometry&&this.setPositions(e.position.array),this},computeBoundingBox:function(){var t=new u;return function(){null===this.boundingBox&&(this.boundingBox=new u);var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;void 0!==e&&void 0!==n&&(this.boundingBox.setFromBufferAttribute(e),t.setFromBufferAttribute(n),this.boundingBox.union(t))}}(),computeBoundingSphere:(D=new d,function(){null===this.boundingSphere&&(this.boundingSphere=new h),null===this.boundingBox&&this.computeBoundingBox();var t=this.attributes.instanceStart,e=this.attributes.instanceEnd;if(void 0!==t&&void 0!==e){var n=this.boundingSphere.center;this.boundingBox.getCenter(n);for(var i=0,r=0,s=t.count;r1&&e.z>1;if(!L&&!z){t.x*=m.x/2,t.y*=m.y/2,e.x*=m.x/2,e.y*=m.y/2,s.start.copy(t),s.start.z=0,s.end.copy(e),s.end.z=0;var A=s.closestPointToPointParameter(i,!0);s.at(A,a);var M=g.lerp(t.z,e.z,A),C=M>=-1&&M<=1,E=i.distanceTo(a)<.5*y;if(C&&E){s.start.fromBufferAttribute(v,w),s.end.fromBufferAttribute(x,w),s.start.applyMatrix4(b),s.end.applyMatrix4(b);var B=new d,_=new d;l.distanceSqToSegment(s.start,s.end,_,B),c.push({point:_,pointOnLine:B,distance:l.origin.distanceTo(_),object:this,face:null,faceIndex:w,uv:null,uv2:null})}}}}}()});class O extends x{constructor(t,e,n,i,r=4473924,s=8947848){r=new b(r),s=new b(s);var a=Math.round(t/e);n=Math.round(n/i)*i/2;const o=[],c=[];let l=0;for(var u=-1*(t=a*e/2);u<=t;u+=e){o.push(u,0,-1*n,u,0,n),(d=0===u?r:s).toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3}for(u=-1*n;u<=n;u+=i){var d;o.push(-1*t,0,u,t,0,u),(d=0===u?r:s).toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3,d.toArray(c,l),l+=3}const h=new w;h.setAttribute("position",new p(o,3)),h.setAttribute("color",new p(c,3));super(h,new S({vertexColors:!0,toneMapped:!1})),this.type="BuildVolume"}}function H(e,n,i,r){const s=function(e,n,i,r){e*=.5,n*=.5,i*=.5;const s=new t.BufferGeometry,a=[];return a.push(-e,-n,-i,-e,n,-i,-e,n,-i,e,n,-i,e,n,-i,e,-n,-i,e,-n,-i,-e,-n,-i,-e,-n,i,-e,n,i,-e,n,i,e,n,i,e,n,i,e,-n,i,e,-n,i,-e,-n,i,-e,-n,-i,-e,-n,i,-e,n,-i,-e,n,i,e,n,-i,e,n,i,e,-n,-i,e,-n,i),s.setAttribute("position",new t.Float32BufferAttribute(a,3)),s}(e,n,i),a=new t.LineSegments(s,new t.LineDashedMaterial({color:new t.Color(r),dashSize:3,gapSize:1}));return a.computeLineDistances(),a}class k{constructor(t){var e,n;if(this.parser=new I,this.backgroundColor=14737632,this.travelColor=10027008,this.extrusionColor=65280,this.renderExtrusion=!0,this.renderTravel=!1,this.singleLayerMode=!1,this.initialCameraPosition=[-100,400,450],this.debug=!1,this.scene=new L,this.scene.background=new b(this.backgroundColor),this.canvas=t.canvas,this.targetId=t.targetId,this.endLayer=t.endLayer,this.startLayer=t.startLayer,this.topLayerColor=t.topLayerColor,this.lastSegmentColor=t.lastSegmentColor,this.lineWidth=t.lineWidth,this.buildVolume=t.buildVolume,this.initialCameraPosition=null!==(e=t.initialCameraPosition)&&void 0!==e?e:this.initialCameraPosition,this.debug=null!==(n=t.debug)&&void 0!==n?n:this.debug,console.debug("opts",t),!this.canvas&&!this.targetId)throw Error("Set either opts.canvas or opts.targetId");if(this.canvas)this.renderer=new z({canvas:this.canvas,preserveDrawingBuffer:!0});else{const t=document.getElementById(this.targetId);if(!t)throw new Error("Unable to find element "+this.targetId);this.renderer=new z({preserveDrawingBuffer:!0}),this.canvas=this.renderer.domElement,t.appendChild(this.canvas)}this.camera=new A(25,this.canvas.offsetWidth/this.canvas.offsetHeight,10,5e3),this.camera.position.fromArray(this.initialCameraPosition);const i=this.camera.far,r=.8*i;this.scene.fog=new M(this.scene.background,r,i),this.resize();new _(this.camera,this.renderer.domElement);this.animate()}get layers(){return this.parser.layers}get maxLayerIndex(){var t;return(null!==(t=this.endLayer)&&void 0!==t?t:this.layers.length)-1}get minLayerIndex(){var t;return this.singleLayerMode?this.maxLayerIndex:(null!==(t=this.startLayer)&&void 0!==t?t:0)-1}animate(){requestAnimationFrame((()=>this.animate())),this.renderer.render(this.scene,this.camera)}processGCode(t){this.parser.parseGcode(t),this.render()}render(){for(var t,e;this.scene.children.length>0;)this.scene.remove(this.scene.children[0]);if(this.debug){const t=new C(Math.max(this.buildVolume.x/2,this.buildVolume.y/2)+20);this.scene.add(t)}this.buildVolume&&this.drawBuildVolume(),this.group=new E,this.group.name="gcode";const n={x:0,y:0,z:0,e:0};for(let i=0;ithis.maxLayerIndex);i++){const r={extrusion:[],travel:[],z:n.z},s=this.layers[i];for(const t of s.commands)if("g0"==t.gcode||"g1"==t.gcode){const e=t,s={x:void 0!==e.params.x?e.params.x:n.x,y:void 0!==e.params.y?e.params.y:n.y,z:void 0!==e.params.z?e.params.z:n.z,e:void 0!==e.params.e?e.params.e:n.e};if(i>=this.minLayerIndex){const t=e.params.e>0;(t&&this.renderExtrusion||!t&&this.renderTravel)&&this.addLineSegment(r,n,s,t)}e.params.x&&(n.x=e.params.x),e.params.y&&(n.y=e.params.y),e.params.z&&(n.z=e.params.z),e.params.e&&(n.e=e.params.e)}if(this.renderExtrusion){const n=Math.round(80*i/this.layers.length),s=new b(`hsl(0, 0%, ${n}%)`).getHex();if(i==this.layers.length-1){const n=null!==(t=this.topLayerColor)&&void 0!==t?t:s,i=null!==(e=this.lastSegmentColor)&&void 0!==e?e:n,a=r.extrusion.splice(-3);this.addLine(r.extrusion,n);const o=r.extrusion.splice(-3);this.addLine([...o,...a],i)}else this.addLine(r.extrusion,s)}this.renderTravel&&this.addLine(r.travel,this.travelColor)}this.group.quaternion.setFromEuler(new B(-Math.PI/2,0,0)),this.buildVolume?this.group.position.set(-this.buildVolume.x/2,0,this.buildVolume.y/2):this.group.position.set(-100,0,100),this.scene.add(this.group),this.renderer.render(this.scene,this.camera)}drawBuildVolume(){this.scene.add(new O(this.buildVolume.x,10,this.buildVolume.y,10));const t=H(this.buildVolume.x,this.buildVolume.z,this.buildVolume.y,8947848);t.position.setY(this.buildVolume.z/2),this.scene.add(t)}clear(){this.startLayer=1,this.endLayer=1/0,this.singleLayerMode=!1,this.parser=new I}resize(){const[t,e]=[this.canvas.offsetWidth,this.canvas.offsetHeight];this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,e,!1)}addLineSegment(t,e,n,i){(i?t.extrusion:t.travel).push(e.x,e.y,e.z,n.x,n.y,n.z)}addLine(t,e){if("number"==typeof this.lineWidth&&this.lineWidth>0)return void this.addThickLine(t,e);const n=new w;n.setAttribute("position",new p(t,3));const i=new S({color:e}),r=new x(n,i);this.group.add(r)}addThickLine(t,e){if(!t.length)return;const n=new U,i=new V({color:e,linewidth:this.lineWidth/(1e3*window.devicePixelRatio)});n.setPositions(t);const r=new W(n,i);this.group.add(r)}}export{k as WebGLPreview}; diff --git a/dist/gcode-preview.js b/dist/gcode-preview.js index 2b4dac54..0862c5e4 100644 --- a/dist/gcode-preview.js +++ b/dist/gcode-preview.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("three"),require("three-orbitcontrols")):"function"==typeof define&&define.amd?define(["exports","three","three-orbitcontrols"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).GCodePreview={},t.THREE,t.THREE.OrbitControls)}(this,(function(t,e,n){"use strict";var i="default"in e?e.default:e;class r extends class{constructor(t,e){this.gcode=t,this.comment=e}}{constructor(t,e,n){super(t,n),this.params=e}}class s{constructor(t,e){this.layer=t,this.commands=e}}class a{constructor(){this.layers=[],this.curZ=0,this.maxZ=0}parseCommand(t,e=!0){const n=t.trim().split(";"),i=n[0],s=e&&n[1]||null,a=i.split(/ +/g),o=a[0].toLowerCase();switch(o){case"g0":case"g1":const t=this.parseMove(a.slice(1));return new r(o,t,s);default:return null}}parseMove(t){return t.reduce(((t,e)=>{const n=e.charAt(0).toLowerCase();return"x"!=n&&"y"!=n&&"z"!=n&&"e"!=n||(t[n]=parseFloat(e.slice(1))),t}),{})}groupIntoLayers(t){for(const e of t.filter((t=>t instanceof r))){const t=e.params;t.z&&(this.curZ=t.z),t.e>0&&(null!=t.x||null!=t.y)&&this.curZ>this.maxZ?(this.maxZ=this.curZ,this.currentLayer=new s(this.layers.length,[e]),this.layers.push(this.currentLayer)):this.currentLayer&&this.currentLayer.commands.push(e)}return this.layers}parseGcode(t){const e=Array.isArray(t)?t:t.split("\n").filter((t=>t.length>0)),n=this.lines2commands(e);return this.groupIntoLayers(n),{layers:this.layers}}lines2commands(t){return t.filter((t=>t.length>0)).map((t=>this.parseCommand(t))).filter((t=>null!==t))}}e.UniformsLib.line={linewidth:{value:1},resolution:{value:new e.Vector2(1,1)},dashScale:{value:1},dashSize:{value:1},gapSize:{value:1}},e.ShaderLib.line={uniforms:e.UniformsUtils.merge([e.UniformsLib.common,e.UniformsLib.fog,e.UniformsLib.line]),vertexShader:"\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tuniform float linewidth;\n\t\tuniform vec2 resolution;\n\n\t\tattribute vec3 instanceStart;\n\t\tattribute vec3 instanceEnd;\n\n\t\tattribute vec3 instanceColorStart;\n\t\tattribute vec3 instanceColorEnd;\n\n\t\tvarying vec2 vUv;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashScale;\n\t\t\tattribute float instanceDistanceStart;\n\t\t\tattribute float instanceDistanceEnd;\n\t\t\tvarying float vLineDistance;\n\n\t\t#endif\n\n\t\tvoid trimSegment( const in vec4 start, inout vec4 end ) {\n\n\t\t\t// trim end segment so it terminates between the camera plane and the near plane\n\n\t\t\t// conservative estimate of the near plane\n\t\t\tfloat a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column\n\t\t\tfloat b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column\n\t\t\tfloat nearEstimate = - 0.5 * b / a;\n\n\t\t\tfloat alpha = ( nearEstimate - start.z ) / ( end.z - start.z );\n\n\t\t\tend.xyz = mix( start.xyz, end.xyz, alpha );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\t#ifdef USE_COLOR\n\n\t\t\t\tvColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;\n\n\t\t\t#endif\n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tvLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;\n\n\t\t\t#endif\n\n\t\t\tfloat aspect = resolution.x / resolution.y;\n\n\t\t\tvUv = uv;\n\n\t\t\t// camera space\n\t\t\tvec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );\n\t\t\tvec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );\n\n\t\t\t// special case for perspective projection, and segments that terminate either in, or behind, the camera plane\n\t\t\t// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space\n\t\t\t// but we need to perform ndc-space calculations in the shader, so we must address this issue directly\n\t\t\t// perhaps there is a more elegant solution -- WestLangley\n\n\t\t\tbool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column\n\n\t\t\tif ( perspective ) {\n\n\t\t\t\tif ( start.z < 0.0 && end.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( start, end );\n\n\t\t\t\t} else if ( end.z < 0.0 && start.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( end, start );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// clip space\n\t\t\tvec4 clipStart = projectionMatrix * start;\n\t\t\tvec4 clipEnd = projectionMatrix * end;\n\n\t\t\t// ndc space\n\t\t\tvec2 ndcStart = clipStart.xy / clipStart.w;\n\t\t\tvec2 ndcEnd = clipEnd.xy / clipEnd.w;\n\n\t\t\t// direction\n\t\t\tvec2 dir = ndcEnd - ndcStart;\n\n\t\t\t// account for clip-space aspect ratio\n\t\t\tdir.x *= aspect;\n\t\t\tdir = normalize( dir );\n\n\t\t\t// perpendicular to dir\n\t\t\tvec2 offset = vec2( dir.y, - dir.x );\n\n\t\t\t// undo aspect ratio adjustment\n\t\t\tdir.x /= aspect;\n\t\t\toffset.x /= aspect;\n\n\t\t\t// sign flip\n\t\t\tif ( position.x < 0.0 ) offset *= - 1.0;\n\n\t\t\t// endcaps\n\t\t\tif ( position.y < 0.0 ) {\n\n\t\t\t\toffset += - dir;\n\n\t\t\t} else if ( position.y > 1.0 ) {\n\n\t\t\t\toffset += dir;\n\n\t\t\t}\n\n\t\t\t// adjust for linewidth\n\t\t\toffset *= linewidth;\n\n\t\t\t// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...\n\t\t\toffset /= resolution.y;\n\n\t\t\t// select end\n\t\t\tvec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;\n\n\t\t\t// back to clip space\n\t\t\toffset *= clip.w;\n\n\t\t\tclip.xy += offset;\n\n\t\t\tgl_Position = clip;\n\n\t\t\tvec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t",fragmentShader:"\n\t\tuniform vec3 diffuse;\n\t\tuniform float opacity;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashSize;\n\t\t\tuniform float gapSize;\n\n\t\t#endif\n\n\t\tvarying float vLineDistance;\n\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\t#include \n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tif ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps\n\n\t\t\t\tif ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX\n\n\t\t\t#endif\n\n\t\t\tif ( abs( vUv.y ) > 1.0 ) {\n\n\t\t\t\tfloat a = vUv.x;\n\t\t\t\tfloat b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;\n\t\t\t\tfloat len2 = a * a + b * b;\n\n\t\t\t\tif ( len2 > 1.0 ) discard;\n\n\t\t\t}\n\n\t\t\tvec4 diffuseColor = vec4( diffuse, opacity );\n\n\t\t\t#include \n\t\t\t#include \n\n\t\t\tgl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t"};var o=function(t){e.ShaderMaterial.call(this,{type:"LineMaterial",uniforms:e.UniformsUtils.clone(e.ShaderLib.line.uniforms),vertexShader:e.ShaderLib.line.vertexShader,fragmentShader:e.ShaderLib.line.fragmentShader,clipping:!0}),this.dashed=!1,Object.defineProperties(this,{color:{enumerable:!0,get:function(){return this.uniforms.diffuse.value},set:function(t){this.uniforms.diffuse.value=t}},linewidth:{enumerable:!0,get:function(){return this.uniforms.linewidth.value},set:function(t){this.uniforms.linewidth.value=t}},dashScale:{enumerable:!0,get:function(){return this.uniforms.dashScale.value},set:function(t){this.uniforms.dashScale.value=t}},dashSize:{enumerable:!0,get:function(){return this.uniforms.dashSize.value},set:function(t){this.uniforms.dashSize.value=t}},gapSize:{enumerable:!0,get:function(){return this.uniforms.gapSize.value},set:function(t){this.uniforms.gapSize.value=t}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(t){this.uniforms.resolution.value.copy(t)}}}),this.setValues(t)};(o.prototype=Object.create(e.ShaderMaterial.prototype)).constructor=o,o.prototype.isLineMaterial=!0;var l,c=function(){e.InstancedBufferGeometry.call(this),this.type="LineSegmentsGeometry";this.setIndex([0,2,1,2,3,1,2,4,3,4,5,3,4,6,5,6,7,5]),this.setAttribute("position",new e.Float32BufferAttribute([-1,2,0,1,2,0,-1,1,0,1,1,0,-1,0,0,1,0,0,-1,-1,0,1,-1,0],3)),this.setAttribute("uv",new e.Float32BufferAttribute([-1,2,1,2,-1,1,1,1,-1,-1,1,-1,-1,-2,1,-2],2))};c.prototype=Object.assign(Object.create(e.InstancedBufferGeometry.prototype),{constructor:c,isLineSegmentsGeometry:!0,applyMatrix4:function(t){var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;return void 0!==e&&(e.applyMatrix4(t),n.applyMatrix4(t),e.data.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},setPositions:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceEnd",new e.InterleavedBufferAttribute(i,3,3)),this.computeBoundingBox(),this.computeBoundingSphere(),this},setColors:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceColorStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceColorEnd",new e.InterleavedBufferAttribute(i,3,3)),this},fromWireframeGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromEdgesGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromMesh:function(t){return this.fromWireframeGeometry(new e.WireframeGeometry(t.geometry)),this},fromLineSegements:function(t){var e=t.geometry;return e.isGeometry?this.setPositions(e.vertices):e.isBufferGeometry&&this.setPositions(e.position.array),this},computeBoundingBox:function(){var t=new e.Box3;return function(){null===this.boundingBox&&(this.boundingBox=new e.Box3);var n=this.attributes.instanceStart,i=this.attributes.instanceEnd;void 0!==n&&void 0!==i&&(this.boundingBox.setFromBufferAttribute(n),t.setFromBufferAttribute(i),this.boundingBox.union(t))}}(),computeBoundingSphere:(l=new e.Vector3,function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere),null===this.boundingBox&&this.computeBoundingBox();var t=this.attributes.instanceStart,n=this.attributes.instanceEnd;if(void 0!==t&&void 0!==n){var i=this.boundingSphere.center;this.boundingBox.getCenter(i);for(var r=0,s=0,a=t.count;s1&&n.z>1;if(!S&&!L){t.x*=m.x/2,t.y*=m.y/2,n.x*=m.x/2,n.y*=m.y/2,a.start.copy(t),a.start.z=0,a.end.copy(n),a.end.z=0;var A=a.closestPointToPointParameter(r,!0);a.at(A,o);var B=e.MathUtils.lerp(t.z,n.z,A),z=B>=-1&&B<=1,M=r.distanceTo(o)<.5*y;if(z&&M){a.start.fromBufferAttribute(v,x),a.end.fromBufferAttribute(g,x),a.start.applyMatrix4(b),a.end.applyMatrix4(b);var C=new e.Vector3,E=new e.Vector3;u.distanceSqToSegment(a.start,a.end,E,C),c.push({point:E,pointOnLine:C,distance:u.origin.distanceTo(E),object:this,face:null,faceIndex:x,uv:null,uv2:null})}}}}}()});class p extends e.LineSegments{constructor(t,n,i,r,s=4473924,a=8947848){s=new e.Color(s),a=new e.Color(a);var o=Math.round(t/n);i=Math.round(i/r)*r/2;const l=[],c=[];let u=0;for(var d=-1*(t=o*n/2);d<=t;d+=n){l.push(d,0,-1*i,d,0,i),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}for(d=-1*i;d<=i;d+=r){var h;l.push(-1*t,0,d,t,0,d),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}const f=new e.BufferGeometry;f.setAttribute("position",new e.Float32BufferAttribute(l,3)),f.setAttribute("color",new e.Float32BufferAttribute(c,3));super(f,new e.LineBasicMaterial({vertexColors:!0,toneMapped:!1})),this.type="BuildVolume"}}function m(t,e,n,r){const s=function(t,e,n,r){t*=.5,e*=.5,n*=.5;const s=new i.BufferGeometry,a=[];return a.push(-t,-e,-n,-t,e,-n,-t,e,-n,t,e,-n,t,e,-n,t,-e,-n,t,-e,-n,-t,-e,-n,-t,-e,n,-t,e,n,-t,e,n,t,e,n,t,e,n,t,-e,n,t,-e,n,-t,-e,n,-t,-e,-n,-t,-e,n,-t,e,-n,-t,e,n,t,e,-n,t,e,n,t,-e,-n,t,-e,n),s.setAttribute("position",new i.Float32BufferAttribute(a,3)),s}(t,e,n),a=new i.LineSegments(s,new i.LineDashedMaterial({color:new i.Color(r),dashSize:3,gapSize:1}));return a.computeLineDistances(),a}t.WebGLPreview=class{constructor(t){var i,r;if(this.parser=new a,this.backgroundColor=14737632,this.travelColor=10027008,this.extrusionColor=65280,this.renderExtrusion=!0,this.renderTravel=!1,this.singleLayerMode=!1,this.initialCameraPosition=[-100,400,450],this.debug=!1,this.scene=new e.Scene,this.scene.background=new e.Color(this.backgroundColor),this.canvas=t.canvas,this.targetId=t.targetId,this.endLayer=t.endLayer,this.startLayer=t.startLayer,this.topLayerColor=t.topLayerColor,this.lastSegmentColor=t.lastSegmentColor,this.lineWidth=t.lineWidth,this.buildVolume=t.buildVolume,this.initialCameraPosition=null!==(i=t.initialCameraPosition)&&void 0!==i?i:this.initialCameraPosition,this.debug=null!==(r=t.debug)&&void 0!==r?r:this.debug,console.debug("opts",t),!this.canvas&&!this.targetId)throw Error("Set either opts.canvas or opts.targetId");if(this.canvas)this.renderer=new e.WebGLRenderer({canvas:this.canvas,preserveDrawingBuffer:!0});else{const t=document.getElementById(this.targetId);if(!t)throw new Error("Unable to find element "+this.targetId);this.renderer=new e.WebGLRenderer({preserveDrawingBuffer:!0}),this.canvas=this.renderer.domElement,t.appendChild(this.canvas)}this.camera=new e.PerspectiveCamera(25,this.canvas.offsetWidth/this.canvas.offsetHeight,10,5e3),this.camera.position.fromArray(this.initialCameraPosition);const s=this.camera.far,o=.8*s;this.scene.fog=new e.Fog(this.scene.background,o,s),this.resize();new n(this.camera,this.renderer.domElement);this.animate()}get layers(){return this.parser.layers}get maxLayerIndex(){var t;return(null!==(t=this.endLayer)&&void 0!==t?t:this.layers.length)-1}get minLayerIndex(){var t;return this.singleLayerMode?this.maxLayerIndex:(null!==(t=this.startLayer)&&void 0!==t?t:0)-1}animate(){requestAnimationFrame((()=>this.animate())),this.renderer.render(this.scene,this.camera)}processGCode(t){this.parser.parseGcode(t),this.render()}render(){for(var t,n;this.scene.children.length>0;)this.scene.remove(this.scene.children[0]);if(this.debug){const t=new e.AxesHelper(Math.max(this.buildVolume.x/2,this.buildVolume.y/2)+20);this.scene.add(t)}this.buildVolume&&this.drawBuildVolume(),this.group=new e.Group,this.group.name="gcode";const i={x:0,y:0,z:0,e:0};for(let r=0;rthis.maxLayerIndex);r++){const s={extrusion:[],travel:[],z:i.z},a=this.layers[r];for(const t of a.commands)if("g0"==t.gcode||"g1"==t.gcode){const e=t,n={x:void 0!==e.params.x?e.params.x:i.x,y:void 0!==e.params.y?e.params.y:i.y,z:void 0!==e.params.z?e.params.z:i.z,e:void 0!==e.params.e?e.params.e:i.e};if(r>=this.minLayerIndex){const t=e.params.e>0;(t&&this.renderExtrusion||!t&&this.renderTravel)&&this.addLineSegment(s,i,n,t)}e.params.x&&(i.x=e.params.x),e.params.y&&(i.y=e.params.y),e.params.z&&(i.z=e.params.z),e.params.e&&(i.e=e.params.e)}if(this.renderExtrusion){const i=Math.round(80*r/this.layers.length),a=new e.Color(`hsl(0, 0%, ${i}%)`).getHex();if(r==this.layers.length-1){const e=null!==(t=this.topLayerColor)&&void 0!==t?t:a,i=null!==(n=this.lastSegmentColor)&&void 0!==n?n:e,r=s.extrusion.splice(-3);this.addLine(s.extrusion,e);const o=s.extrusion.splice(-3);this.addLine([...o,...r],i)}else this.addLine(s.extrusion,a)}this.renderTravel&&this.addLine(s.travel,this.travelColor)}this.group.quaternion.setFromEuler(new e.Euler(-Math.PI/2,0,0)),this.buildVolume?this.group.position.set(-this.buildVolume.x/2,0,this.buildVolume.y/2):this.group.position.set(-100,0,100),this.scene.add(this.group),this.renderer.render(this.scene,this.camera)}drawBuildVolume(){this.scene.add(new p(this.buildVolume.x,10,this.buildVolume.y,10));const t=m(this.buildVolume.x,this.buildVolume.z,this.buildVolume.y,8947848);t.position.setY(this.buildVolume.z/2),this.scene.add(t)}clear(){this.startLayer=1,this.endLayer=1/0,this.singleLayerMode=!1,this.parser=new a}resize(){const[t,e]=[this.canvas.offsetWidth,this.canvas.offsetHeight];this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,e,!1)}addLineSegment(t,e,n,i){(i?t.extrusion:t.travel).push(e.x,e.y,e.z,n.x,n.y,n.z)}addLine(t,n){if("number"==typeof this.lineWidth&&this.lineWidth>0)return void this.addThickLine(t,n);const i=new e.BufferGeometry;i.setAttribute("position",new e.Float32BufferAttribute(t,3));const r=new e.LineBasicMaterial({color:n}),s=new e.LineSegments(i,r);this.group.add(s)}addThickLine(t,e){if(!t.length)return;const n=new u,i=new o({color:e,linewidth:this.lineWidth/(1e3*window.devicePixelRatio)});n.setPositions(t);const r=new f(n,i);this.group.add(r)}},Object.defineProperty(t,"__esModule",{value:!0})})); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("three"),require("three-orbitcontrols")):"function"==typeof define&&define.amd?define(["exports","three","three-orbitcontrols"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).GCodePreview={},t.THREE,t.THREE.OrbitControls)}(this,(function(t,e,n){"use strict";var i="default"in e?e.default:e;class r extends class{constructor(t,e){this.gcode=t,this.comment=e}}{constructor(t,e,n){super(t,n),this.params=e}}class s{constructor(t,e){this.layer=t,this.commands=e}}class a{constructor(){this.layers=[],this.curZ=0,this.maxZ=0}parseCommand(t,e=!0){const n=t.trim().split(";"),i=n[0],s=e&&n[1]||null,a=i.split(/ +/g),o=a[0].toLowerCase();switch(o){case"g0":case"g1":const t=this.parseMove(a.slice(1));return new r(o,t,s);default:return null}}parseMove(t){return t.reduce(((t,e)=>{const n=e.charAt(0).toLowerCase();return"x"!=n&&"y"!=n&&"z"!=n&&"e"!=n&&"f"!=n||(t[n]=parseFloat(e.slice(1))),t}),{})}groupIntoLayers(t){for(const e of t.filter((t=>t instanceof r))){const t=e.params;t.z&&(this.curZ=t.z),t.e>0&&(null!=t.x||null!=t.y)&&this.curZ>this.maxZ?(this.maxZ=this.curZ,this.currentLayer=new s(this.layers.length,[e]),this.layers.push(this.currentLayer)):this.currentLayer&&this.currentLayer.commands.push(e)}return this.layers}parseGcode(t){const e=Array.isArray(t)?t:t.split("\n").filter((t=>t.length>0)),n=this.lines2commands(e);return this.groupIntoLayers(n),{layers:this.layers}}lines2commands(t){return t.filter((t=>t.length>0)).map((t=>this.parseCommand(t))).filter((t=>null!==t))}}e.UniformsLib.line={linewidth:{value:1},resolution:{value:new e.Vector2(1,1)},dashScale:{value:1},dashSize:{value:1},gapSize:{value:1}},e.ShaderLib.line={uniforms:e.UniformsUtils.merge([e.UniformsLib.common,e.UniformsLib.fog,e.UniformsLib.line]),vertexShader:"\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tuniform float linewidth;\n\t\tuniform vec2 resolution;\n\n\t\tattribute vec3 instanceStart;\n\t\tattribute vec3 instanceEnd;\n\n\t\tattribute vec3 instanceColorStart;\n\t\tattribute vec3 instanceColorEnd;\n\n\t\tvarying vec2 vUv;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashScale;\n\t\t\tattribute float instanceDistanceStart;\n\t\t\tattribute float instanceDistanceEnd;\n\t\t\tvarying float vLineDistance;\n\n\t\t#endif\n\n\t\tvoid trimSegment( const in vec4 start, inout vec4 end ) {\n\n\t\t\t// trim end segment so it terminates between the camera plane and the near plane\n\n\t\t\t// conservative estimate of the near plane\n\t\t\tfloat a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column\n\t\t\tfloat b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column\n\t\t\tfloat nearEstimate = - 0.5 * b / a;\n\n\t\t\tfloat alpha = ( nearEstimate - start.z ) / ( end.z - start.z );\n\n\t\t\tend.xyz = mix( start.xyz, end.xyz, alpha );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\t#ifdef USE_COLOR\n\n\t\t\t\tvColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;\n\n\t\t\t#endif\n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tvLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;\n\n\t\t\t#endif\n\n\t\t\tfloat aspect = resolution.x / resolution.y;\n\n\t\t\tvUv = uv;\n\n\t\t\t// camera space\n\t\t\tvec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );\n\t\t\tvec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );\n\n\t\t\t// special case for perspective projection, and segments that terminate either in, or behind, the camera plane\n\t\t\t// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space\n\t\t\t// but we need to perform ndc-space calculations in the shader, so we must address this issue directly\n\t\t\t// perhaps there is a more elegant solution -- WestLangley\n\n\t\t\tbool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column\n\n\t\t\tif ( perspective ) {\n\n\t\t\t\tif ( start.z < 0.0 && end.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( start, end );\n\n\t\t\t\t} else if ( end.z < 0.0 && start.z >= 0.0 ) {\n\n\t\t\t\t\ttrimSegment( end, start );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// clip space\n\t\t\tvec4 clipStart = projectionMatrix * start;\n\t\t\tvec4 clipEnd = projectionMatrix * end;\n\n\t\t\t// ndc space\n\t\t\tvec2 ndcStart = clipStart.xy / clipStart.w;\n\t\t\tvec2 ndcEnd = clipEnd.xy / clipEnd.w;\n\n\t\t\t// direction\n\t\t\tvec2 dir = ndcEnd - ndcStart;\n\n\t\t\t// account for clip-space aspect ratio\n\t\t\tdir.x *= aspect;\n\t\t\tdir = normalize( dir );\n\n\t\t\t// perpendicular to dir\n\t\t\tvec2 offset = vec2( dir.y, - dir.x );\n\n\t\t\t// undo aspect ratio adjustment\n\t\t\tdir.x /= aspect;\n\t\t\toffset.x /= aspect;\n\n\t\t\t// sign flip\n\t\t\tif ( position.x < 0.0 ) offset *= - 1.0;\n\n\t\t\t// endcaps\n\t\t\tif ( position.y < 0.0 ) {\n\n\t\t\t\toffset += - dir;\n\n\t\t\t} else if ( position.y > 1.0 ) {\n\n\t\t\t\toffset += dir;\n\n\t\t\t}\n\n\t\t\t// adjust for linewidth\n\t\t\toffset *= linewidth;\n\n\t\t\t// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...\n\t\t\toffset /= resolution.y;\n\n\t\t\t// select end\n\t\t\tvec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;\n\n\t\t\t// back to clip space\n\t\t\toffset *= clip.w;\n\n\t\t\tclip.xy += offset;\n\n\t\t\tgl_Position = clip;\n\n\t\t\tvec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t",fragmentShader:"\n\t\tuniform vec3 diffuse;\n\t\tuniform float opacity;\n\n\t\t#ifdef USE_DASH\n\n\t\t\tuniform float dashSize;\n\t\t\tuniform float gapSize;\n\n\t\t#endif\n\n\t\tvarying float vLineDistance;\n\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\t#include \n\n\t\t\t#ifdef USE_DASH\n\n\t\t\t\tif ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps\n\n\t\t\t\tif ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX\n\n\t\t\t#endif\n\n\t\t\tif ( abs( vUv.y ) > 1.0 ) {\n\n\t\t\t\tfloat a = vUv.x;\n\t\t\t\tfloat b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;\n\t\t\t\tfloat len2 = a * a + b * b;\n\n\t\t\t\tif ( len2 > 1.0 ) discard;\n\n\t\t\t}\n\n\t\t\tvec4 diffuseColor = vec4( diffuse, opacity );\n\n\t\t\t#include \n\t\t\t#include \n\n\t\t\tgl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );\n\n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\t\t\t#include \n\n\t\t}\n\t\t"};var o=function(t){e.ShaderMaterial.call(this,{type:"LineMaterial",uniforms:e.UniformsUtils.clone(e.ShaderLib.line.uniforms),vertexShader:e.ShaderLib.line.vertexShader,fragmentShader:e.ShaderLib.line.fragmentShader,clipping:!0}),this.dashed=!1,Object.defineProperties(this,{color:{enumerable:!0,get:function(){return this.uniforms.diffuse.value},set:function(t){this.uniforms.diffuse.value=t}},linewidth:{enumerable:!0,get:function(){return this.uniforms.linewidth.value},set:function(t){this.uniforms.linewidth.value=t}},dashScale:{enumerable:!0,get:function(){return this.uniforms.dashScale.value},set:function(t){this.uniforms.dashScale.value=t}},dashSize:{enumerable:!0,get:function(){return this.uniforms.dashSize.value},set:function(t){this.uniforms.dashSize.value=t}},gapSize:{enumerable:!0,get:function(){return this.uniforms.gapSize.value},set:function(t){this.uniforms.gapSize.value=t}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(t){this.uniforms.resolution.value.copy(t)}}}),this.setValues(t)};(o.prototype=Object.create(e.ShaderMaterial.prototype)).constructor=o,o.prototype.isLineMaterial=!0;var l,c=function(){e.InstancedBufferGeometry.call(this),this.type="LineSegmentsGeometry";this.setIndex([0,2,1,2,3,1,2,4,3,4,5,3,4,6,5,6,7,5]),this.setAttribute("position",new e.Float32BufferAttribute([-1,2,0,1,2,0,-1,1,0,1,1,0,-1,0,0,1,0,0,-1,-1,0,1,-1,0],3)),this.setAttribute("uv",new e.Float32BufferAttribute([-1,2,1,2,-1,1,1,1,-1,-1,1,-1,-1,-2,1,-2],2))};c.prototype=Object.assign(Object.create(e.InstancedBufferGeometry.prototype),{constructor:c,isLineSegmentsGeometry:!0,applyMatrix4:function(t){var e=this.attributes.instanceStart,n=this.attributes.instanceEnd;return void 0!==e&&(e.applyMatrix4(t),n.applyMatrix4(t),e.data.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this},setPositions:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceEnd",new e.InterleavedBufferAttribute(i,3,3)),this.computeBoundingBox(),this.computeBoundingSphere(),this},setColors:function(t){var n;t instanceof Float32Array?n=t:Array.isArray(t)&&(n=new Float32Array(t));var i=new e.InstancedInterleavedBuffer(n,6,1);return this.setAttribute("instanceColorStart",new e.InterleavedBufferAttribute(i,3,0)),this.setAttribute("instanceColorEnd",new e.InterleavedBufferAttribute(i,3,3)),this},fromWireframeGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromEdgesGeometry:function(t){return this.setPositions(t.attributes.position.array),this},fromMesh:function(t){return this.fromWireframeGeometry(new e.WireframeGeometry(t.geometry)),this},fromLineSegements:function(t){var e=t.geometry;return e.isGeometry?this.setPositions(e.vertices):e.isBufferGeometry&&this.setPositions(e.position.array),this},computeBoundingBox:function(){var t=new e.Box3;return function(){null===this.boundingBox&&(this.boundingBox=new e.Box3);var n=this.attributes.instanceStart,i=this.attributes.instanceEnd;void 0!==n&&void 0!==i&&(this.boundingBox.setFromBufferAttribute(n),t.setFromBufferAttribute(i),this.boundingBox.union(t))}}(),computeBoundingSphere:(l=new e.Vector3,function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere),null===this.boundingBox&&this.computeBoundingBox();var t=this.attributes.instanceStart,n=this.attributes.instanceEnd;if(void 0!==t&&void 0!==n){var i=this.boundingSphere.center;this.boundingBox.getCenter(i);for(var r=0,s=0,a=t.count;s1&&n.z>1;if(!S&&!L){t.x*=m.x/2,t.y*=m.y/2,n.x*=m.x/2,n.y*=m.y/2,a.start.copy(t),a.start.z=0,a.end.copy(n),a.end.z=0;var A=a.closestPointToPointParameter(r,!0);a.at(A,o);var B=e.MathUtils.lerp(t.z,n.z,A),z=B>=-1&&B<=1,M=r.distanceTo(o)<.5*y;if(z&&M){a.start.fromBufferAttribute(v,x),a.end.fromBufferAttribute(g,x),a.start.applyMatrix4(b),a.end.applyMatrix4(b);var C=new e.Vector3,E=new e.Vector3;u.distanceSqToSegment(a.start,a.end,E,C),c.push({point:E,pointOnLine:C,distance:u.origin.distanceTo(E),object:this,face:null,faceIndex:x,uv:null,uv2:null})}}}}}()});class p extends e.LineSegments{constructor(t,n,i,r,s=4473924,a=8947848){s=new e.Color(s),a=new e.Color(a);var o=Math.round(t/n);i=Math.round(i/r)*r/2;const l=[],c=[];let u=0;for(var d=-1*(t=o*n/2);d<=t;d+=n){l.push(d,0,-1*i,d,0,i),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}for(d=-1*i;d<=i;d+=r){var h;l.push(-1*t,0,d,t,0,d),(h=0===d?s:a).toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3,h.toArray(c,u),u+=3}const f=new e.BufferGeometry;f.setAttribute("position",new e.Float32BufferAttribute(l,3)),f.setAttribute("color",new e.Float32BufferAttribute(c,3));super(f,new e.LineBasicMaterial({vertexColors:!0,toneMapped:!1})),this.type="BuildVolume"}}function m(t,e,n,r){const s=function(t,e,n,r){t*=.5,e*=.5,n*=.5;const s=new i.BufferGeometry,a=[];return a.push(-t,-e,-n,-t,e,-n,-t,e,-n,t,e,-n,t,e,-n,t,-e,-n,t,-e,-n,-t,-e,-n,-t,-e,n,-t,e,n,-t,e,n,t,e,n,t,e,n,t,-e,n,t,-e,n,-t,-e,n,-t,-e,-n,-t,-e,n,-t,e,-n,-t,e,n,t,e,-n,t,e,n,t,-e,-n,t,-e,n),s.setAttribute("position",new i.Float32BufferAttribute(a,3)),s}(t,e,n),a=new i.LineSegments(s,new i.LineDashedMaterial({color:new i.Color(r),dashSize:3,gapSize:1}));return a.computeLineDistances(),a}t.WebGLPreview=class{constructor(t){var i,r;if(this.parser=new a,this.backgroundColor=14737632,this.travelColor=10027008,this.extrusionColor=65280,this.renderExtrusion=!0,this.renderTravel=!1,this.singleLayerMode=!1,this.initialCameraPosition=[-100,400,450],this.debug=!1,this.scene=new e.Scene,this.scene.background=new e.Color(this.backgroundColor),this.canvas=t.canvas,this.targetId=t.targetId,this.endLayer=t.endLayer,this.startLayer=t.startLayer,this.topLayerColor=t.topLayerColor,this.lastSegmentColor=t.lastSegmentColor,this.lineWidth=t.lineWidth,this.buildVolume=t.buildVolume,this.initialCameraPosition=null!==(i=t.initialCameraPosition)&&void 0!==i?i:this.initialCameraPosition,this.debug=null!==(r=t.debug)&&void 0!==r?r:this.debug,console.debug("opts",t),!this.canvas&&!this.targetId)throw Error("Set either opts.canvas or opts.targetId");if(this.canvas)this.renderer=new e.WebGLRenderer({canvas:this.canvas,preserveDrawingBuffer:!0});else{const t=document.getElementById(this.targetId);if(!t)throw new Error("Unable to find element "+this.targetId);this.renderer=new e.WebGLRenderer({preserveDrawingBuffer:!0}),this.canvas=this.renderer.domElement,t.appendChild(this.canvas)}this.camera=new e.PerspectiveCamera(25,this.canvas.offsetWidth/this.canvas.offsetHeight,10,5e3),this.camera.position.fromArray(this.initialCameraPosition);const s=this.camera.far,o=.8*s;this.scene.fog=new e.Fog(this.scene.background,o,s),this.resize();new n(this.camera,this.renderer.domElement);this.animate()}get layers(){return this.parser.layers}get maxLayerIndex(){var t;return(null!==(t=this.endLayer)&&void 0!==t?t:this.layers.length)-1}get minLayerIndex(){var t;return this.singleLayerMode?this.maxLayerIndex:(null!==(t=this.startLayer)&&void 0!==t?t:0)-1}animate(){requestAnimationFrame((()=>this.animate())),this.renderer.render(this.scene,this.camera)}processGCode(t){this.parser.parseGcode(t),this.render()}render(){for(var t,n;this.scene.children.length>0;)this.scene.remove(this.scene.children[0]);if(this.debug){const t=new e.AxesHelper(Math.max(this.buildVolume.x/2,this.buildVolume.y/2)+20);this.scene.add(t)}this.buildVolume&&this.drawBuildVolume(),this.group=new e.Group,this.group.name="gcode";const i={x:0,y:0,z:0,e:0};for(let r=0;rthis.maxLayerIndex);r++){const s={extrusion:[],travel:[],z:i.z},a=this.layers[r];for(const t of a.commands)if("g0"==t.gcode||"g1"==t.gcode){const e=t,n={x:void 0!==e.params.x?e.params.x:i.x,y:void 0!==e.params.y?e.params.y:i.y,z:void 0!==e.params.z?e.params.z:i.z,e:void 0!==e.params.e?e.params.e:i.e};if(r>=this.minLayerIndex){const t=e.params.e>0;(t&&this.renderExtrusion||!t&&this.renderTravel)&&this.addLineSegment(s,i,n,t)}e.params.x&&(i.x=e.params.x),e.params.y&&(i.y=e.params.y),e.params.z&&(i.z=e.params.z),e.params.e&&(i.e=e.params.e)}if(this.renderExtrusion){const i=Math.round(80*r/this.layers.length),a=new e.Color(`hsl(0, 0%, ${i}%)`).getHex();if(r==this.layers.length-1){const e=null!==(t=this.topLayerColor)&&void 0!==t?t:a,i=null!==(n=this.lastSegmentColor)&&void 0!==n?n:e,r=s.extrusion.splice(-3);this.addLine(s.extrusion,e);const o=s.extrusion.splice(-3);this.addLine([...o,...r],i)}else this.addLine(s.extrusion,a)}this.renderTravel&&this.addLine(s.travel,this.travelColor)}this.group.quaternion.setFromEuler(new e.Euler(-Math.PI/2,0,0)),this.buildVolume?this.group.position.set(-this.buildVolume.x/2,0,this.buildVolume.y/2):this.group.position.set(-100,0,100),this.scene.add(this.group),this.renderer.render(this.scene,this.camera)}drawBuildVolume(){this.scene.add(new p(this.buildVolume.x,10,this.buildVolume.y,10));const t=m(this.buildVolume.x,this.buildVolume.z,this.buildVolume.y,8947848);t.position.setY(this.buildVolume.z/2),this.scene.add(t)}clear(){this.startLayer=1,this.endLayer=1/0,this.singleLayerMode=!1,this.parser=new a}resize(){const[t,e]=[this.canvas.offsetWidth,this.canvas.offsetHeight];this.camera.aspect=t/e,this.camera.updateProjectionMatrix(),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(t,e,!1)}addLineSegment(t,e,n,i){(i?t.extrusion:t.travel).push(e.x,e.y,e.z,n.x,n.y,n.z)}addLine(t,n){if("number"==typeof this.lineWidth&&this.lineWidth>0)return void this.addThickLine(t,n);const i=new e.BufferGeometry;i.setAttribute("position",new e.Float32BufferAttribute(t,3));const r=new e.LineBasicMaterial({color:n}),s=new e.LineSegments(i,r);this.group.add(s)}addThickLine(t,e){if(!t.length)return;const n=new u,i=new o({color:e,linewidth:this.lineWidth/(1e3*window.devicePixelRatio)});n.setPositions(t);const r=new f(n,i);this.group.add(r)}},Object.defineProperty(t,"__esModule",{value:!0})})); diff --git a/src/gcode-parser.ts b/src/gcode-parser.ts index 29210a4e..7dd56fc0 100644 --- a/src/gcode-parser.ts +++ b/src/gcode-parser.ts @@ -11,7 +11,7 @@ export class MoveCommand extends GCodeCommand { super(gcode, comment); } } -type MoveCommandParamName = 'x' | 'y' | 'z' | 'e'; +type MoveCommandParamName = 'x' | 'y' | 'z' | 'e' | 'f'; type MoveCommandParams = { [key in MoveCommandParamName]?: number; }; @@ -49,7 +49,7 @@ export class Parser { parseMove(params: string[]): MoveCommandParams { return params.reduce((acc: MoveCommandParams, cur: string) => { const key = cur.charAt(0).toLowerCase(); - if (key == 'x' || key == 'y' || key == 'z' || key == 'e') + if (key == 'x' || key == 'y' || key == 'z' || key == 'e' || key == 'f') acc[key] = parseFloat(cur.slice(1)); return acc; }, {}); From e733f782f773f07538490149a8308067b3dce567 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Sat, 5 Jun 2021 23:54:48 +0200 Subject: [PATCH 8/8] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fd477cbb..214f5576 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gcode-preview", - "version": "2.2.0", + "version": "2.3.0", "description": "Preview a 3d print from a gcode file", "author": "remcoder@gmail.com", "license": "MIT",