mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-11-22 05:37:55 +01:00
Merge branch 'feature/comb' into develop
This commit is contained in:
commit
6971c3c4b5
97
comb.js
Normal file
97
comb.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import comb from './src/sliceActions/helpers/comb.js';
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
document.body.appendChild(canvas);
|
||||||
|
canvas.width = 800;
|
||||||
|
canvas.height = 800;
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
context.lineJoin = 'bevel';
|
||||||
|
|
||||||
|
function circle(radius = 10, x = 0, y = 0, clockWise = true, segments = 40) {
|
||||||
|
const shape = [];
|
||||||
|
|
||||||
|
for (let rad = 0; rad < Math.PI * 2; rad += Math.PI * 2 / segments) {
|
||||||
|
if (clockWise) {
|
||||||
|
shape.push({ x: Math.cos(rad) * radius + x, y: Math.sin(rad) * radius + y });
|
||||||
|
} else {
|
||||||
|
shape.push({ x: Math.cos(rad) * radius + x, y: -Math.sin(rad) * radius + y });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
const START = { x: 200, y: 400 };
|
||||||
|
const END = { x: 400, y: 300 };
|
||||||
|
|
||||||
|
const POLYGON = [[
|
||||||
|
{ x: 10, y: 10 },
|
||||||
|
{ x: 600, y: 10 },
|
||||||
|
{ x: 500, y: 200 },
|
||||||
|
{ x: 600, y: 600 },
|
||||||
|
{ x: 10, y: 600 }
|
||||||
|
], [
|
||||||
|
{ x: 160, y: 120 },
|
||||||
|
{ x: 120, y: 400 },
|
||||||
|
{ x: 400, y: 400 }
|
||||||
|
]];
|
||||||
|
// const POLYGON = [
|
||||||
|
// circle(300, 305, 305, true, 4),
|
||||||
|
// circle(40, 305, 105, false, 4),
|
||||||
|
// circle(40, 305, 205, false, 4),
|
||||||
|
// circle(40, 305, 305, false, 4),
|
||||||
|
// circle(40, 305, 405, false, 4),
|
||||||
|
// circle(40, 305, 505, false, 4)
|
||||||
|
// ];
|
||||||
|
|
||||||
|
canvas.onmousedown = (event) => {
|
||||||
|
START.x = event.offsetX;
|
||||||
|
START.y = event.offsetY;
|
||||||
|
compute();
|
||||||
|
};
|
||||||
|
canvas.onmousemove = (event) => {
|
||||||
|
END.x = event.offsetX;
|
||||||
|
END.y = event.offsetY;
|
||||||
|
compute();
|
||||||
|
};
|
||||||
|
compute();
|
||||||
|
|
||||||
|
function compute() {
|
||||||
|
const path = comb(POLYGON, START, END);
|
||||||
|
|
||||||
|
// draw
|
||||||
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
context.beginPath();
|
||||||
|
for (const shape of POLYGON) {
|
||||||
|
let first = true;
|
||||||
|
for (const { x, y } of shape) {
|
||||||
|
if (first) {
|
||||||
|
context.moveTo(x, y);
|
||||||
|
} else {
|
||||||
|
context.lineTo(x, y);
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.closePath();
|
||||||
|
context.fillStyle = 'lightgray';
|
||||||
|
context.fill();
|
||||||
|
|
||||||
|
context.beginPath();
|
||||||
|
for (const { x, y } of path) {
|
||||||
|
context.lineTo(x, y);
|
||||||
|
}
|
||||||
|
context.lineWidth = 2;
|
||||||
|
context.stroke();
|
||||||
|
|
||||||
|
context.beginPath();
|
||||||
|
context.arc(START.x, START.y, 3, 0, Math.PI * 2);
|
||||||
|
context.fillStyle = 'blue';
|
||||||
|
context.fill();
|
||||||
|
|
||||||
|
context.beginPath();
|
||||||
|
context.arc(END.x, END.y, 3, 0, Math.PI * 2);
|
||||||
|
context.fillStyle = 'red';
|
||||||
|
context.fill();
|
||||||
|
}
|
82
package-lock.json
generated
82
package-lock.json
generated
@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@doodle3d/doodle3d-core": {
|
"@doodle3d/doodle3d-core": {
|
||||||
"version": "github:doodle3d/doodle3d-core#0a3686d8df05e275805ebb8029528a45d7f31f39",
|
"version": "github:doodle3d/doodle3d-core#ac2256d2c541fb465f959131f6a216574be7f70b",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@doodle3d/cal": "0.0.8",
|
"@doodle3d/cal": "0.0.8",
|
||||||
"@doodle3d/clipper-js": "1.0.10",
|
"@doodle3d/clipper-js": "1.0.10",
|
||||||
@ -41,7 +41,7 @@
|
|||||||
"@doodle3d/potrace-js": "0.0.6",
|
"@doodle3d/potrace-js": "0.0.6",
|
||||||
"@doodle3d/threejs-export-obj": "0.0.8",
|
"@doodle3d/threejs-export-obj": "0.0.8",
|
||||||
"@doodle3d/threejs-export-stl": "0.0.5",
|
"@doodle3d/threejs-export-stl": "0.0.5",
|
||||||
"@doodle3d/touch-events": "0.0.7",
|
"@doodle3d/touch-events": "0.0.9",
|
||||||
"babel-polyfill": "6.26.0",
|
"babel-polyfill": "6.26.0",
|
||||||
"bezier-js": "2.2.5",
|
"bezier-js": "2.2.5",
|
||||||
"blueimp-canvas-to-blob": "3.14.0",
|
"blueimp-canvas-to-blob": "3.14.0",
|
||||||
@ -90,6 +90,9 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||||
|
},
|
||||||
|
"three-js-csg": {
|
||||||
|
"version": "github:Doodle3D/three-js-csg#a36f23da6e9be2405a9094de5709cb0ae8f58045"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -125,9 +128,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@doodle3d/touch-events": {
|
"@doodle3d/touch-events": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@doodle3d/touch-events/-/touch-events-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@doodle3d/touch-events/-/touch-events-0.0.9.tgz",
|
||||||
"integrity": "sha512-EpL8IEGKKy2gqFFlxA4n84IeAyPTrEzle0jwmRv+mmVBzwGr6xDl5Ga5vJIrg2WcYs4Xc7qWbiKSHEXvEpDLlg==",
|
"integrity": "sha512-VedelafzxzDlibHMlysYsayt5c+TpE/deOi4W6TEcm39PL6u+ihntDhgsflJUsg7bFM7bVrekgdn3OLreK8/UA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"eventdispatcher.js": "0.0.2",
|
"eventdispatcher.js": "0.0.2",
|
||||||
"pepjs": "0.4.3"
|
"pepjs": "0.4.3"
|
||||||
@ -3795,9 +3798,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"expand-template": {
|
"expand-template": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz",
|
||||||
"integrity": "sha512-kkjwkMqj0h4w/sb32ERCDxCQkREMCAgS39DscDnSwDsbxnwwM1BTZySdC3Bn1lhY7vL08n9GoO/fVTynjDgRyQ=="
|
"integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg=="
|
||||||
},
|
},
|
||||||
"express": {
|
"express": {
|
||||||
"version": "4.16.2",
|
"version": "4.16.2",
|
||||||
@ -7266,9 +7269,9 @@
|
|||||||
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
|
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
|
||||||
},
|
},
|
||||||
"lodash-es": {
|
"lodash-es": {
|
||||||
"version": "4.17.8",
|
"version": "4.17.10",
|
||||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz",
|
||||||
"integrity": "sha512-I9mjAxengFAleSThFhhAhvba6fsO0hunb9/0sQ6qQihSZsJRBofv2rYH58WXaOb/O++eUmYpCLywSQ22GfU+sA=="
|
"integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg=="
|
||||||
},
|
},
|
||||||
"lodash._arraycopy": {
|
"lodash._arraycopy": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@ -8254,9 +8257,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-abi": {
|
"node-abi": {
|
||||||
"version": "2.3.0",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.1.tgz",
|
||||||
"integrity": "sha512-zwm6vU3SsVgw3e9fu48JBaRBCJGIvAgysDsqtf5+vEexFE71bEOtaMWb5zr/zODZNzTPtQlqUUpC79k68Hspow==",
|
"integrity": "sha512-pUlswqpHQ7zGPI9lGjZ4XDNIEUDbHxsltfIRb7dTnYdhgHWHOcB0MLZKLoCz6UMcGzSPG5wGl1HODZVQAUsH6w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"semver": "5.4.1"
|
"semver": "5.4.1"
|
||||||
}
|
}
|
||||||
@ -9340,18 +9343,18 @@
|
|||||||
"integrity": "sha512-/rI36cN2g7vDQnKWN8Uzupi++KjyqS9iS+/fpwG4Ea8d0Pip0PQ5bshUNzVwt+/D2MRfhVAplYMMvWLqWrCF/g==",
|
"integrity": "sha512-/rI36cN2g7vDQnKWN8Uzupi++KjyqS9iS+/fpwG4Ea8d0Pip0PQ5bshUNzVwt+/D2MRfhVAplYMMvWLqWrCF/g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"detect-libc": "1.0.3",
|
"detect-libc": "1.0.3",
|
||||||
"expand-template": "1.1.0",
|
"expand-template": "1.1.1",
|
||||||
"github-from-package": "0.0.0",
|
"github-from-package": "0.0.0",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"node-abi": "2.3.0",
|
"node-abi": "2.4.1",
|
||||||
"noop-logger": "0.1.1",
|
"noop-logger": "0.1.1",
|
||||||
"npmlog": "4.1.2",
|
"npmlog": "4.1.2",
|
||||||
"os-homedir": "1.0.2",
|
"os-homedir": "1.0.2",
|
||||||
"pump": "2.0.1",
|
"pump": "2.0.1",
|
||||||
"rc": "1.2.6",
|
"rc": "1.2.6",
|
||||||
"simple-get": "2.7.0",
|
"simple-get": "2.8.1",
|
||||||
"tar-fs": "1.16.0",
|
"tar-fs": "1.16.2",
|
||||||
"tunnel-agent": "0.6.0",
|
"tunnel-agent": "0.6.0",
|
||||||
"which-pm-runs": "1.0.0"
|
"which-pm-runs": "1.0.0"
|
||||||
},
|
},
|
||||||
@ -9748,8 +9751,8 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"hoist-non-react-statics": "2.5.0",
|
"hoist-non-react-statics": "2.5.0",
|
||||||
"invariant": "2.2.2",
|
"invariant": "2.2.2",
|
||||||
"lodash": "4.17.5",
|
"lodash": "4.17.10",
|
||||||
"lodash-es": "4.17.8",
|
"lodash-es": "4.17.10",
|
||||||
"loose-envify": "1.3.1",
|
"loose-envify": "1.3.1",
|
||||||
"prop-types": "15.6.0"
|
"prop-types": "15.6.0"
|
||||||
},
|
},
|
||||||
@ -9760,9 +9763,9 @@
|
|||||||
"integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w=="
|
"integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w=="
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.5",
|
"version": "4.17.10",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||||
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
|
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -9921,8 +9924,8 @@
|
|||||||
"hoist-non-react-statics": "2.5.0",
|
"hoist-non-react-statics": "2.5.0",
|
||||||
"invariant": "2.2.4",
|
"invariant": "2.2.4",
|
||||||
"is-promise": "2.1.0",
|
"is-promise": "2.1.0",
|
||||||
"lodash": "4.17.5",
|
"lodash": "4.17.10",
|
||||||
"lodash-es": "4.17.8",
|
"lodash-es": "4.17.10",
|
||||||
"prop-types": "15.6.1"
|
"prop-types": "15.6.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -9940,9 +9943,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.5",
|
"version": "4.17.10",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||||
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
|
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
|
||||||
},
|
},
|
||||||
"prop-types": {
|
"prop-types": {
|
||||||
"version": "15.6.1",
|
"version": "15.6.1",
|
||||||
@ -10113,7 +10116,7 @@
|
|||||||
"performance-now": "2.1.0",
|
"performance-now": "2.1.0",
|
||||||
"qs": "6.5.1",
|
"qs": "6.5.1",
|
||||||
"safe-buffer": "5.1.1",
|
"safe-buffer": "5.1.1",
|
||||||
"stringstream": "0.0.5",
|
"stringstream": "0.0.6",
|
||||||
"tough-cookie": "2.3.4",
|
"tough-cookie": "2.3.4",
|
||||||
"tunnel-agent": "0.6.0",
|
"tunnel-agent": "0.6.0",
|
||||||
"uuid": "3.2.1"
|
"uuid": "3.2.1"
|
||||||
@ -10462,9 +10465,9 @@
|
|||||||
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
|
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
|
||||||
},
|
},
|
||||||
"simple-get": {
|
"simple-get": {
|
||||||
"version": "2.7.0",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz",
|
||||||
"integrity": "sha512-RkE9rGPHcxYZ/baYmgJtOSM63vH0Vyq+ma5TijBcLla41SWlh8t6XYIGMR/oeZcmr+/G8k+zrClkkVrtnQ0esg==",
|
"integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"decompress-response": "3.3.0",
|
"decompress-response": "3.3.0",
|
||||||
"once": "1.4.0",
|
"once": "1.4.0",
|
||||||
@ -10754,9 +10757,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stringstream": {
|
"stringstream": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz",
|
||||||
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
|
"integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA=="
|
||||||
},
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
@ -10906,9 +10909,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"tar-fs": {
|
"tar-fs": {
|
||||||
"version": "1.16.0",
|
"version": "1.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.2.tgz",
|
||||||
"integrity": "sha512-I9rb6v7mjWLtOfCau9eH5L7sLJyU2BnxtEZRQ5Mt+eRKmf1F0ohXmT/Jc3fr52kDvjJ/HV5MH3soQfPL5bQ0Yg==",
|
"integrity": "sha512-LdknWjPEiZC1nOBwhv0JBzfJBGPJar08dZg2rwZe0ZTLQoRGEzgrl7vF3qUEkCHpI/wN9e7RyCuDhMsJUCLPPQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"chownr": "1.0.1",
|
"chownr": "1.0.1",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
@ -10999,9 +11002,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/three/-/three-0.88.0.tgz",
|
"resolved": "https://registry.npmjs.org/three/-/three-0.88.0.tgz",
|
||||||
"integrity": "sha1-QlbC/Djk+yOg0j66K2zOTfjkZtU="
|
"integrity": "sha1-QlbC/Djk+yOg0j66K2zOTfjkZtU="
|
||||||
},
|
},
|
||||||
"three-js-csg": {
|
|
||||||
"version": "github:Doodle3D/three-js-csg#a36f23da6e9be2405a9094de5709cb0ae8f58045"
|
|
||||||
},
|
|
||||||
"through": {
|
"through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||||
|
@ -35,7 +35,7 @@ filamentThickness: 2.85
|
|||||||
temperature: 210
|
temperature: 210
|
||||||
bedTemperature: 50
|
bedTemperature: 50
|
||||||
layerHeight: 0.15
|
layerHeight: 0.15
|
||||||
combing: true
|
combing: false
|
||||||
thickness:
|
thickness:
|
||||||
top: 0.45
|
top: 0.45
|
||||||
bottom: 0.45
|
bottom: 0.45
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { scale, distanceTo } from './vector2.js';
|
import { distanceTo } from './vector2.js';
|
||||||
import { PRECISION, VERSION } from '../../constants.js';
|
import { VERSION } from '../../constants.js';
|
||||||
|
|
||||||
export const MOVE = 'G';
|
export const MOVE = 'G';
|
||||||
export const M_COMMAND = 'M';
|
export const M_COMMAND = 'M';
|
||||||
@ -55,7 +55,7 @@ export default class GCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
moveTo(x, y, z, { speed }) {
|
moveTo(x, y, z, { speed }) {
|
||||||
const newNozzlePosition = scale({ x, y }, PRECISION);
|
const newNozzlePosition = { x, y };
|
||||||
const lineLength = distanceTo(this._nozzlePosition, newNozzlePosition);
|
const lineLength = distanceTo(this._nozzlePosition, newNozzlePosition);
|
||||||
|
|
||||||
this._duration += lineLength / speed;
|
this._duration += lineLength / speed;
|
||||||
@ -74,7 +74,7 @@ export default class GCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lineTo(x, y, z, { speed, flowRate }) {
|
lineTo(x, y, z, { speed, flowRate }) {
|
||||||
const newNozzlePosition = scale({ x, y }, PRECISION);
|
const newNozzlePosition = { x, y };
|
||||||
const lineLength = distanceTo(this._nozzlePosition, newNozzlePosition);
|
const lineLength = distanceTo(this._nozzlePosition, newNozzlePosition);
|
||||||
|
|
||||||
this._extruder += this._nozzleToFilamentRatio * lineLength * flowRate;
|
this._extruder += this._nozzleToFilamentRatio * lineLength * flowRate;
|
||||||
|
@ -1,131 +1,197 @@
|
|||||||
import Shape from 'clipper-js';
|
import { angle, subtract, distanceTo } from './vector2.js';
|
||||||
import { subtract, add, scale, normalize, dot, length, distanceTo } from './vector2.js';
|
|
||||||
import { PRECISION } from '../../constants.js';
|
|
||||||
|
|
||||||
const TOLERANCE = 1 / PRECISION;
|
const graphs = new WeakMap();
|
||||||
|
export default function comb(polygons, start, end) {
|
||||||
|
if (!graphs.has(polygons)) graphs.set(polygons, createGraph(polygons));
|
||||||
|
let { edges, graph, points } = graphs.get(polygons);
|
||||||
|
|
||||||
export default function comb(outline, start, end) {
|
points = [...points, start, end];
|
||||||
if (distanceTo(start, end) < TOLERANCE) {
|
graph = [...graph];
|
||||||
return [start, end];
|
|
||||||
}
|
|
||||||
|
|
||||||
let combPath = new Shape([[start, end]], false, true, false);
|
const startNode = createNode(graph, points, edges, start);
|
||||||
|
const endNode = createNode(graph, points, edges, end);
|
||||||
|
|
||||||
for (let i = 0; i < outline.paths.length; i ++) {
|
let result;
|
||||||
let outlinePart = new Shape([outline.paths[i]], true, false, false, true);
|
if (graph[startNode].some(node => node.to === endNode)) {
|
||||||
|
result = [start, end];
|
||||||
let snappedCombPaths = outlinePart.orientation(0) ? combPath.intersect(outlinePart) : combPath.difference(outlinePart);
|
|
||||||
|
|
||||||
snappedCombPaths = snappedCombPaths.mapToLower();
|
|
||||||
outlinePart = outlinePart.mapToLower()[0];
|
|
||||||
|
|
||||||
if (distanceTo(start, outlinePart[outlinePart.length - 1]) < distanceTo(start, outlinePart[0])) {
|
|
||||||
outlinePart = outlinePart.reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
const distanceMap = new WeakMap();
|
|
||||||
|
|
||||||
for (let i = 0; i < snappedCombPaths.length; i ++) {
|
|
||||||
const snappedCombPath = snappedCombPaths[i];
|
|
||||||
|
|
||||||
const distanceStart = distanceTo(start, snappedCombPath[0]);
|
|
||||||
const distanceEnd = distanceTo(start, snappedCombPath[snappedCombPath.length - 1]);
|
|
||||||
|
|
||||||
if (distanceStart < distanceEnd) {
|
|
||||||
distanceMap.set(snappedCombPath, distanceStart);
|
|
||||||
} else {
|
} else {
|
||||||
snappedCombPath.reverse();
|
const path = shortestPath(graph, startNode, endNode);
|
||||||
distanceMap.set(snappedCombPath, distanceEnd);
|
if (path) {
|
||||||
}
|
result = path.map(index => points[index]);
|
||||||
}
|
|
||||||
snappedCombPaths.sort((a, b) => distanceMap.get(a) - distanceMap.get(b));
|
|
||||||
|
|
||||||
const firstPath = snappedCombPaths[0];
|
|
||||||
const lastPath = snappedCombPaths[snappedCombPaths.length - 1];
|
|
||||||
|
|
||||||
if (snappedCombPaths.length === 0) {
|
|
||||||
snappedCombPaths.push([start], [end]);
|
|
||||||
} else if (distanceTo(firstPath[0], start) > 1.0) {
|
|
||||||
snappedCombPaths.unshift([start]);
|
|
||||||
} else if (distanceTo(lastPath[lastPath.length - 1], end) > 1.0) {
|
|
||||||
snappedCombPaths.push([end]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snappedCombPaths.length === 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const startPath = snappedCombPaths[0];
|
|
||||||
const startPoint = startPath[startPath.length - 1];
|
|
||||||
|
|
||||||
const endPath = snappedCombPaths[snappedCombPaths.length - 1];
|
|
||||||
const endPoint = endPath[0];
|
|
||||||
|
|
||||||
const lineIndexStart = findClosestLineOnPath(outlinePart, startPoint);
|
|
||||||
const lineIndexEnd = findClosestLineOnPath(outlinePart, endPoint);
|
|
||||||
|
|
||||||
const path = [];
|
|
||||||
if (lineIndexEnd === lineIndexStart) {
|
|
||||||
continue;
|
|
||||||
} else if (lineIndexEnd > lineIndexStart) {
|
|
||||||
if (lineIndexStart + outlinePart.length - lineIndexEnd < lineIndexEnd - lineIndexStart) {
|
|
||||||
for (let i = lineIndexStart + outlinePart.length; i > lineIndexEnd; i --) {
|
|
||||||
path.push(outlinePart[i % outlinePart.length]);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (let i = lineIndexStart; i < lineIndexEnd; i ++) {
|
result = [start, end];
|
||||||
path.push(outlinePart[i + 1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (lineIndexEnd + outlinePart.length - lineIndexStart < lineIndexStart - lineIndexEnd) {
|
return result;
|
||||||
for (let i = lineIndexStart; i < lineIndexEnd + outlinePart.length; i ++) {
|
|
||||||
path.push(outlinePart[(i + 1) % outlinePart.length]);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (let i = lineIndexStart; i > lineIndexEnd; i --) {
|
function createGraph(polygons) {
|
||||||
path.push(outlinePart[i]);
|
const points = [];
|
||||||
|
const edges = [];
|
||||||
|
const nextPoints = new WeakMap();
|
||||||
|
const previousPoints = new WeakMap();
|
||||||
|
for (let i = 0; i < polygons.length; i ++) {
|
||||||
|
const polygon = polygons[i];
|
||||||
|
for (let j = 0; j < polygon.length; j ++) {
|
||||||
|
const point = polygon[j];
|
||||||
|
const nextPoint = polygon[(j + 1) % polygon.length];
|
||||||
|
const previousPoint = polygon[(j - 1 + polygon.length) % polygon.length];
|
||||||
|
|
||||||
|
points.push(point);
|
||||||
|
edges.push([point, nextPoint]);
|
||||||
|
nextPoints.set(point, nextPoint);
|
||||||
|
previousPoints.set(point, previousPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const graph = points.map(() => ([]));
|
||||||
|
for (let i = 0; i < points.length; i ++) {
|
||||||
|
const a = points[i];
|
||||||
|
|
||||||
|
for (let j = i + 1; j < points.length; j ++) {
|
||||||
|
const b = points[j];
|
||||||
|
const nextPoint = nextPoints.get(a);
|
||||||
|
const previousPoint = previousPoints.get(a);
|
||||||
|
|
||||||
|
if (!lineIsVisible(previousPoint, nextPoint, edges, a, b)) continue;
|
||||||
|
|
||||||
|
const distance = distanceTo(a, b);
|
||||||
|
|
||||||
|
const connectNodeA = graph[i];
|
||||||
|
connectNodeA.push({ to: j, distance });
|
||||||
|
|
||||||
|
const connectNodeB = graph[j];
|
||||||
|
connectNodeB.push({ to: i, distance });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { graph, edges, points };
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNode(graph, points, edges, point) {
|
||||||
|
const node = [];
|
||||||
|
const to = graph.length;
|
||||||
|
graph.push(node);
|
||||||
|
|
||||||
|
let previousPoint;
|
||||||
|
let nextPoint;
|
||||||
|
for (let j = 0; j < edges.length; j ++) {
|
||||||
|
const edge = edges[j];
|
||||||
|
if (pointOnLine(edge, point)) [previousPoint, nextPoint] = edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < graph.length; i ++) {
|
||||||
|
const b = points[i];
|
||||||
|
|
||||||
|
if (!lineIsVisible(previousPoint, nextPoint, edges, point, b)) continue;
|
||||||
|
|
||||||
|
const distance = distanceTo(point, b);
|
||||||
|
|
||||||
|
node.push({ to: i, distance });
|
||||||
|
graph[i] = [...graph[i], { to, distance }];
|
||||||
|
}
|
||||||
|
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lineIsVisible(previousPoint, nextPoint, edges, a, b) {
|
||||||
|
if (b === nextPoint || b === previousPoint) return true;
|
||||||
|
|
||||||
|
if (previousPoint && nextPoint) {
|
||||||
|
const angleLine = angle(subtract(b, a));
|
||||||
|
const anglePrevious = angle(subtract(previousPoint, a));
|
||||||
|
const angleNext = angle(subtract(nextPoint, a));
|
||||||
|
|
||||||
|
if (betweenAngles(angleLine, anglePrevious, angleNext)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineCrossesEdges(edges, a, b)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lineCrossesEdges(edges, a, b) {
|
||||||
|
for (let i = 0; i < edges.length; i ++) {
|
||||||
|
const [c, d] = edges[i];
|
||||||
|
if (lineSegmentsCross(a, b, c, d)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lineSegmentsCross(a, b, c, d) {
|
||||||
|
const denominator = ((b.x - a.x) * (d.y - c.y)) - ((b.y - a.y) * (d.x - c.x));
|
||||||
|
|
||||||
|
if (denominator === 0.0) return false;
|
||||||
|
|
||||||
|
const numerator1 = ((a.y - c.y) * (d.x - c.x)) - ((a.x - c.x) * (d.y - c.y));
|
||||||
|
const numerator2 = ((a.y - c.y) * (b.x - a.x)) - ((a.x - c.x) * (b.y - a.y));
|
||||||
|
if (numerator1 === 0.0 || numerator2 === 0.0) return false;
|
||||||
|
|
||||||
|
const r = numerator1 / denominator;
|
||||||
|
const s = numerator2 / denominator;
|
||||||
|
return (r > 0.0 && r < 1.0) && (s >= 0.0 && s <= 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TAU = Math.PI * 2.0;
|
||||||
|
function normalizeAngle(a) {
|
||||||
|
a %= TAU;
|
||||||
|
return a > 0.0 ? a : a + TAU;
|
||||||
|
}
|
||||||
|
|
||||||
|
function betweenAngles(n, a, b) {
|
||||||
|
n = normalizeAngle(n);
|
||||||
|
a = normalizeAngle(a);
|
||||||
|
b = normalizeAngle(b);
|
||||||
|
return a < b ? a <= n && n <= b : a <= n || n <= b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dijkstra's algorithm
|
||||||
|
function shortestPath(graph, start, end) {
|
||||||
|
const distances = graph.map(() => Infinity);
|
||||||
|
distances[start] = 0;
|
||||||
|
const traverse = [];
|
||||||
|
const queue = [];
|
||||||
|
for (let i = 0; i < distances.length; i ++) {
|
||||||
|
queue.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (queue.length > 0) {
|
||||||
|
let queueIndex;
|
||||||
|
let minDistance = Infinity;
|
||||||
|
for (let index = 0; index < queue.length; index ++) {
|
||||||
|
const nodeIndex = queue[index];
|
||||||
|
const distance = distances[nodeIndex];
|
||||||
|
if (distances[nodeIndex] < minDistance) {
|
||||||
|
queueIndex = index;
|
||||||
|
minDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [nodeIndex] = queue.splice(queueIndex, 1);
|
||||||
|
const node = graph[nodeIndex];
|
||||||
|
|
||||||
|
for (let i = 0; i < node.length; i ++) {
|
||||||
|
const child = node[i];
|
||||||
|
const distance = distances[nodeIndex] + child.distance;
|
||||||
|
if (distance < distances[child.to]) {
|
||||||
|
distances[child.to] = distance;
|
||||||
|
traverse[child.to] = nodeIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
combPath = new Shape([[...startPath, ...path, ...endPath]], false, true, false, true);
|
if (!traverse.hasOwnProperty(end)) return null;
|
||||||
|
|
||||||
|
const path = [end];
|
||||||
|
let nodeIndex = end;
|
||||||
|
do {
|
||||||
|
nodeIndex = traverse[nodeIndex];
|
||||||
|
path.push(nodeIndex);
|
||||||
|
} while (nodeIndex !== start);
|
||||||
|
|
||||||
|
return path.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
return combPath.mapToLower()[0];
|
function pointOnLine([a, b], point) {
|
||||||
}
|
return (a.x - point.x) * (a.y - point.y) === (b.x - point.x) * (b.y - point.y);
|
||||||
|
|
||||||
function findClosestLineOnPath(path, point) {
|
|
||||||
let distance = Infinity;
|
|
||||||
let lineIndex;
|
|
||||||
|
|
||||||
for (let i = 0; i < path.length; i ++) {
|
|
||||||
const pointA = path[i];
|
|
||||||
const pointB = path[(i + 1) % path.length];
|
|
||||||
|
|
||||||
const tempClosestPoint = findClosestPointOnLine(pointA, pointB, point);
|
|
||||||
const tempDistance = distanceTo(tempClosestPoint, point);
|
|
||||||
|
|
||||||
if (tempDistance < distance) {
|
|
||||||
distance = tempDistance;
|
|
||||||
lineIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lineIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findClosestPointOnLine(a, b, c) {
|
|
||||||
const b_ = subtract(b, a);
|
|
||||||
const c_ = subtract(c, a);
|
|
||||||
|
|
||||||
const lambda = dot(normalize(b_), c_) / length(b_);
|
|
||||||
|
|
||||||
if (lambda >= 1) {
|
|
||||||
return b;
|
|
||||||
} else if (lambda > 0) {
|
|
||||||
return add(a, scale(b_, lambda));
|
|
||||||
} else {
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ export const almostEquals = (a, b) => Math.abs(a.x - b.x) < 0.001 && Math.abs(a.
|
|||||||
export const dot = (a, b) => a.x * b.x + a.y * b.y;
|
export const dot = (a, b) => a.x * b.x + a.y * b.y;
|
||||||
export const length = (v) => Math.sqrt(v.x * v.x + v.y * v.y);
|
export const length = (v) => Math.sqrt(v.x * v.x + v.y * v.y);
|
||||||
export const distanceTo = (a, b) => length(subtract(a, b));
|
export const distanceTo = (a, b) => length(subtract(a, b));
|
||||||
|
export const angle = (v) => Math.atan2(v.y, v.x);
|
||||||
export const normalize = (v) => {
|
export const normalize = (v) => {
|
||||||
const l = length(v);
|
const l = length(v);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import shapesToSlices from './shapesToSlices.js';
|
|||||||
import slicesToGCode from './slicesToGCode.js';
|
import slicesToGCode from './slicesToGCode.js';
|
||||||
import applyPrecision from './applyPrecision.js';
|
import applyPrecision from './applyPrecision.js';
|
||||||
import { hslToRgb } from './helpers/color.js';
|
import { hslToRgb } from './helpers/color.js';
|
||||||
// // import removePrecision from './removePrecision.js';
|
import removePrecision from './removePrecision.js';
|
||||||
|
|
||||||
export default function slice(settings, geometry, openObjectIndexes, constructLinePreview, onProgress) {
|
export default function slice(settings, geometry, openObjectIndexes, constructLinePreview, onProgress) {
|
||||||
const total = 11;
|
const total = 11;
|
||||||
@ -48,7 +48,7 @@ export default function slice(settings, geometry, openObjectIndexes, constructLi
|
|||||||
updateProgress('Optimizing paths');
|
updateProgress('Optimizing paths');
|
||||||
optimizePaths(slices, settings);
|
optimizePaths(slices, settings);
|
||||||
|
|
||||||
// removePrecision(slices);
|
removePrecision(slices);
|
||||||
|
|
||||||
updateProgress('Constructing gcode');
|
updateProgress('Constructing gcode');
|
||||||
const gcode = slicesToGCode(slices, settings);
|
const gcode = slicesToGCode(slices, settings);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import GCode from './helpers/GCode.js';
|
import GCode from './helpers/GCode.js';
|
||||||
import comb from './helpers/comb.js';
|
import comb from './helpers/comb.js';
|
||||||
import { divide } from './helpers/vector2.js';
|
import { Z_OFFSET } from '../constants.js';
|
||||||
import { PRECISION, Z_OFFSET } from '../constants.js';
|
|
||||||
|
|
||||||
const PROFILE_TYPES = ['support', 'innerShell', 'outerShell', 'innerInfill', 'outerInfill', 'brim'];
|
const PROFILE_TYPES = ['support', 'innerShell', 'outerShell', 'innerInfill', 'outerInfill', 'brim'];
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ export default function slicesToGCode(slices, settings) {
|
|||||||
const part = slice.parts[i];
|
const part = slice.parts[i];
|
||||||
|
|
||||||
if (part.closed) {
|
if (part.closed) {
|
||||||
const outline = part.shell[0];
|
const outline = part.shell[0].mapToLower();
|
||||||
|
|
||||||
for (let i = 0; i < part.shell.length; i ++) {
|
for (let i = 0; i < part.shell.length; i ++) {
|
||||||
const shell = part.shell[i];
|
const shell = part.shell[i];
|
||||||
@ -72,7 +71,8 @@ export default function slicesToGCode(slices, settings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof slice.support !== 'undefined') {
|
if (typeof slice.support !== 'undefined') {
|
||||||
pathToGCode(slice.supportOutline, combing, gcode, slice.support, true, true, z, profiles.support);
|
const supportOutline = slice.supportOutline.mapToLower();
|
||||||
|
pathToGCode(supportOutline, combing, gcode, slice.support, true, true, z, profiles.support);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ function pathToGCode(outline, combing, gcode, shape, retract, unRetract, z, prof
|
|||||||
|
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
if (combing) {
|
if (combing) {
|
||||||
const combPath = comb(outline, divide(gcode._nozzlePosition, PRECISION), point);
|
const combPath = comb(outline, gcode._nozzlePosition, point);
|
||||||
for (let i = 0; i < combPath.length; i ++) {
|
for (let i = 0; i < combPath.length; i ++) {
|
||||||
const combPoint = combPath[i];
|
const combPoint = combPath[i];
|
||||||
gcode.moveTo(combPoint.x, combPoint.y, z, travelProfile);
|
gcode.moveTo(combPoint.x, combPoint.y, z, travelProfile);
|
||||||
|
Loading…
Reference in New Issue
Block a user