mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-11-22 05:37:55 +01:00
implement new combing
This commit is contained in:
parent
79e4acd3d1
commit
6c8b8e9d44
61
package-lock.json
generated
61
package-lock.json
generated
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3229,6 +3232,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"earcut": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/earcut/-/earcut-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-AxdCdWUk1zzK/NuZ7e1ljj6IGC+VAdC3Qb7QQDsXpfNrc5IM8tL9nNXUmEGE6jRHTfZ10zhzRhtDmWVsR5pd3A=="
|
||||||
|
},
|
||||||
"ecc-jsbn": {
|
"ecc-jsbn": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
|
||||||
@ -7266,9 +7274,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 +8262,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-abi": {
|
"node-abi": {
|
||||||
"version": "2.3.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.0.tgz",
|
||||||
"integrity": "sha512-zwm6vU3SsVgw3e9fu48JBaRBCJGIvAgysDsqtf5+vEexFE71bEOtaMWb5zr/zODZNzTPtQlqUUpC79k68Hspow==",
|
"integrity": "sha512-hRUz0vG+eJfSqwU6rOgW6wNyX85ec8OEE9n4A+u+eoiE8oTePhCkUFTNmwQ+86Kyu429PCLNNyI2P2jL9qKXhw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"semver": "5.4.1"
|
"semver": "5.4.1"
|
||||||
}
|
}
|
||||||
@ -9344,14 +9352,14 @@
|
|||||||
"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.0",
|
||||||
"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 +9756,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 +9768,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 +9929,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 +9948,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",
|
||||||
@ -10462,9 +10470,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",
|
||||||
@ -10906,9 +10914,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 +11007,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",
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"@doodle3d/doodle3d-api": "^1.0.5",
|
"@doodle3d/doodle3d-api": "^1.0.5",
|
||||||
"@doodle3d/doodle3d-core": "github:doodle3d/doodle3d-core",
|
"@doodle3d/doodle3d-core": "github:doodle3d/doodle3d-core",
|
||||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
|
"earcut": "^2.1.3",
|
||||||
"file-saver": "^1.3.3",
|
"file-saver": "^1.3.3",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"material-ui": "^0.19.4",
|
"material-ui": "^0.19.4",
|
||||||
|
@ -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,225 @@
|
|||||||
import Shape from 'clipper-js';
|
import { subtract, add, normalize, dot, distanceTo, divide, normal } from './vector2.js';
|
||||||
import { subtract, add, scale, normalize, dot, length, distanceTo } from './vector2.js';
|
import earcut from 'earcut';
|
||||||
import { PRECISION } from '../../constants.js';
|
|
||||||
|
|
||||||
const TOLERANCE = 1 / PRECISION;
|
// const TRIANGULATED_OUTLINES = new WeakMap();
|
||||||
|
|
||||||
export default function comb(outline, start, end) {
|
export default function comb(outline, start, end) {
|
||||||
if (distanceTo(start, end) < TOLERANCE) {
|
if (distanceTo(start, end) < 10) return [start, end];
|
||||||
return [start, end];
|
|
||||||
|
// if (!TRIANGULATED_OUTLINES.has(outline)) TRIANGULATED_OUTLINES.set(outline, decompose(outline));
|
||||||
|
// const { convexPolygons, vertices } = TRIANGULATED_OUTLINES.get(outline);
|
||||||
|
const { convexPolygons, vertices } = decompose(outline);
|
||||||
|
const startPolygon = convexPolygons.findIndex(({ face }) => pointIsInsideConvex(start, face, vertices));
|
||||||
|
const endPolygon = convexPolygons.findIndex(({ face }) => pointIsInsideConvex(end, face, vertices));
|
||||||
|
if (startPolygon === -1 || endPolygon === -1) return [start, end];
|
||||||
|
if (startPolygon === endPolygon) return [start, end];
|
||||||
|
|
||||||
|
const path = findClosestPath(convexPolygons, startPolygon, endPolygon);
|
||||||
|
if (!path) return [start, end];
|
||||||
|
const line = containLineInPath(path, start, end, vertices);
|
||||||
|
|
||||||
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
let combPath = new Shape([[start, end]], false, true, false);
|
function lineIntersection(a1, a2, b1, b2) {
|
||||||
|
// source: http://mathworld.wolfram.com/Line-LineIntersection.html
|
||||||
|
const intersection = {
|
||||||
|
x: ((a1.x * a2.y - a1.y * a2.x) * (b1.x - b2.x) - (a1.x - a2.x) * (b1.x * b2.y - b1.y * b2.x)) / ((a1.x - a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x - b2.x)),
|
||||||
|
y: ((a1.x * a2.y - a1.y * a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x * b2.y - b1.y * b2.x)) / ((a1.x - a2.x) * (b1.y - b2.y) - (a1.y - a2.y) * (b1.x - b2.x))
|
||||||
|
};
|
||||||
|
|
||||||
for (let i = 0; i < outline.paths.length; i ++) {
|
const intersectionA = subtract(intersection, a1);
|
||||||
let outlinePart = new Shape([outline.paths[i]], true, false, false, true);
|
const directionA = subtract(a2, a1);
|
||||||
|
const normalA = normalize(directionA);
|
||||||
|
const distanceA = dot(normalA, intersectionA);
|
||||||
|
if (distanceA < 0 || distanceA > dot(normalA, directionA)) return false;
|
||||||
|
|
||||||
let snappedCombPaths = outlinePart.orientation(0) ? combPath.intersect(outlinePart) : combPath.difference(outlinePart);
|
const intersectionB = subtract(intersection, b1);
|
||||||
|
const directionB = subtract(b2, b1);
|
||||||
|
const normalB = normalize(directionB);
|
||||||
|
const distanceB = dot(normalB, intersectionB);
|
||||||
|
if (distanceB < 0 || distanceB > dot(normalB, directionB)) return false;
|
||||||
|
|
||||||
snappedCombPaths = snappedCombPaths.mapToLower();
|
return intersection;
|
||||||
outlinePart = outlinePart.mapToLower()[0];
|
|
||||||
|
|
||||||
if (distanceTo(start, outlinePart[outlinePart.length - 1]) < distanceTo(start, outlinePart[0])) {
|
|
||||||
outlinePart = outlinePart.reverse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pointIsInsideConvex(point, convex, vertices) {
|
||||||
|
for (let i = 0; i < convex.length; i ++) {
|
||||||
|
const vertexA = vertices[convex[i]];
|
||||||
|
const vertexB = vertices[convex[(i + 1) % convex.length]];
|
||||||
|
|
||||||
|
const n = normalize(normal(subtract(vertexB, vertexA)));
|
||||||
|
const p = subtract(point, vertexA);
|
||||||
|
|
||||||
|
if (dot(p, n) < 0) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decompose(polygon) {
|
||||||
|
const vertices = polygon.reduce((points, path) => {
|
||||||
|
points.push(...path);
|
||||||
|
return points;
|
||||||
|
}, []);
|
||||||
|
const flatVertices = vertices.reduce((points, { x, y }) => {
|
||||||
|
points.push(x, y);
|
||||||
|
return points;
|
||||||
|
}, []);
|
||||||
|
let offset = 0;
|
||||||
|
const holes = polygon
|
||||||
|
.map(path => offset += path.length)
|
||||||
|
.slice(0, -1);
|
||||||
|
|
||||||
|
const flatTrainglesIndexed = earcut(flatVertices, holes);
|
||||||
|
const convexPolygons = [];
|
||||||
|
for (let i = 0; i < flatTrainglesIndexed.length; i += 3) {
|
||||||
|
const face = [
|
||||||
|
flatTrainglesIndexed[i],
|
||||||
|
flatTrainglesIndexed[i + 1],
|
||||||
|
flatTrainglesIndexed[i + 2]
|
||||||
|
];
|
||||||
|
const center = divide(face.reduce((total, point) => {
|
||||||
|
if (!total) {
|
||||||
|
return vertices[point];
|
||||||
|
} else {
|
||||||
|
return add(total, vertices[point]);
|
||||||
|
}
|
||||||
|
}, null), face.length);
|
||||||
|
convexPolygons.push({
|
||||||
|
center,
|
||||||
|
face,
|
||||||
|
connects: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < convexPolygons.length; i ++) {
|
||||||
|
for (let j = i + 1; j < convexPolygons.length; j ++) {
|
||||||
|
const triangleIndexedA = convexPolygons[i];
|
||||||
|
const triangleIndexedB = convexPolygons[j];
|
||||||
|
|
||||||
|
const overlap = [];
|
||||||
|
triangleIndexedA.face.map(index => {
|
||||||
|
if (triangleIndexedB.face.includes(index)) overlap.push(index);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (overlap.length === 2) {
|
||||||
|
const distance = distanceTo(convexPolygons[i].center, convexPolygons[j].center);
|
||||||
|
triangleIndexedA.connects.push({ to: j, edge: overlap, distance });
|
||||||
|
triangleIndexedB.connects.push({ to: i, edge: overlap, distance });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { vertices, convexPolygons };
|
||||||
|
}
|
||||||
|
|
||||||
|
function findClosestPath(convexPolygons, start, end, visited = [], path = []) {
|
||||||
|
if (start === end) return [];
|
||||||
|
|
||||||
|
visited = [...visited, start];
|
||||||
|
|
||||||
|
const { connects } = convexPolygons[start];
|
||||||
|
|
||||||
|
const finish = connects.find(({ to }) => to === end);
|
||||||
|
if (finish) return [...path, finish];
|
||||||
|
|
||||||
|
const posibilities = [];
|
||||||
|
for (const connect of connects) {
|
||||||
|
if (visited.includes(connect.to)) continue;
|
||||||
|
|
||||||
|
const posibility = findClosestPath(convexPolygons, connect.to, end, visited, [...path, connect]);
|
||||||
|
if (posibility) posibilities.push(posibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posibilities.length === 0) {
|
||||||
|
return null;
|
||||||
|
} else if (posibilities.length === 1) {
|
||||||
|
return posibilities[0];
|
||||||
|
} else if (posibilities.length > 1) {
|
||||||
const distanceMap = new WeakMap();
|
const distanceMap = new WeakMap();
|
||||||
|
for (const posibility of posibilities) {
|
||||||
for (let i = 0; i < snappedCombPaths.length; i ++) {
|
const distance = posibility.reduce((totalDistance, connect) => totalDistance + connect.distance, 0);
|
||||||
const snappedCombPath = snappedCombPaths[i];
|
distanceMap.set(posibility, distance);
|
||||||
|
|
||||||
const distanceStart = distanceTo(start, snappedCombPath[0]);
|
|
||||||
const distanceEnd = distanceTo(start, snappedCombPath[snappedCombPath.length - 1]);
|
|
||||||
|
|
||||||
if (distanceStart < distanceEnd) {
|
|
||||||
distanceMap.set(snappedCombPath, distanceStart);
|
|
||||||
} else {
|
|
||||||
snappedCombPath.reverse();
|
|
||||||
distanceMap.set(snappedCombPath, distanceEnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
return posibilities.sort((a, b) => distanceMap.get(a) - distanceMap.get(b))[0];
|
||||||
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 {
|
|
||||||
for (let i = lineIndexStart; i < lineIndexEnd; i ++) {
|
|
||||||
path.push(outlinePart[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (lineIndexEnd + outlinePart.length - lineIndexStart < lineIndexStart - lineIndexEnd) {
|
|
||||||
for (let i = lineIndexStart; i < lineIndexEnd + outlinePart.length; i ++) {
|
|
||||||
path.push(outlinePart[(i + 1) % outlinePart.length]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (let i = lineIndexStart; i > lineIndexEnd; i --) {
|
|
||||||
path.push(outlinePart[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
combPath = new Shape([[...startPath, ...path, ...endPath]], false, true, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return combPath.mapToLower()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
// const parse = string => parseFloat(string);
|
||||||
}
|
// function findClosestPath(map, start, end) {
|
||||||
|
// // dijkstra's algorithm
|
||||||
|
// const costs = { [start]: 0 };
|
||||||
|
// const open = { [0]: [start] };
|
||||||
|
// const predecessors = {};
|
||||||
|
//
|
||||||
|
// while (open) {
|
||||||
|
// const keys = Object.keys(open).map(parse);
|
||||||
|
// if (keys.length === 0) break;
|
||||||
|
// keys.sort();
|
||||||
|
//
|
||||||
|
// const [key] = keys;
|
||||||
|
// const bucket = open[key];
|
||||||
|
// const node = bucket.shift();
|
||||||
|
// const currentCost = key;
|
||||||
|
// const { connects } = map[node];
|
||||||
|
//
|
||||||
|
// if (!bucket.length) delete open[key];
|
||||||
|
//
|
||||||
|
// for (const { distance, to } of connects) {
|
||||||
|
// const totalCost = distance + currentCost;
|
||||||
|
// const vertexCost = costs[to];
|
||||||
|
//
|
||||||
|
// if ((typeof vertexCost === 'undefined') || (vertexCost > totalCost)) {
|
||||||
|
// costs[to] = totalCost;
|
||||||
|
//
|
||||||
|
// if (!open[totalCost]) open[totalCost] = [];
|
||||||
|
// open[totalCost].push(to);
|
||||||
|
//
|
||||||
|
// predecessors[to] = node;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (typeof costs[end] === 'undefined') return null;
|
||||||
|
//
|
||||||
|
// const nodes = [];
|
||||||
|
// let node = end;
|
||||||
|
// while (typeof node !== 'undefined') {
|
||||||
|
// nodes.push(node);
|
||||||
|
// node = predecessors[node];
|
||||||
|
// }
|
||||||
|
// nodes.reverse();
|
||||||
|
//
|
||||||
|
// const path = [];
|
||||||
|
// for (let i = 1; i < nodes.length; i ++) {
|
||||||
|
// const from = nodes[i - 1];
|
||||||
|
// const to = nodes[i];
|
||||||
|
//
|
||||||
|
// const connection = map[from].connects.find(connect => connect.to === to);
|
||||||
|
// path.push(connection);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return path;
|
||||||
|
// }
|
||||||
|
|
||||||
function findClosestPointOnLine(a, b, c) {
|
function containLineInPath(path, start, end, vertices) {
|
||||||
const b_ = subtract(b, a);
|
const line = [start];
|
||||||
const c_ = subtract(c, a);
|
|
||||||
|
|
||||||
const lambda = dot(normalize(b_), c_) / length(b_);
|
for (const { edge: [indexA, indexB] } of path) {
|
||||||
|
const vertexA = vertices[indexA];
|
||||||
|
const vertexB = vertices[indexB];
|
||||||
|
|
||||||
if (lambda >= 1) {
|
const intersection = lineIntersection(start, end, vertexA, vertexB);
|
||||||
return b;
|
if (!intersection) {
|
||||||
} else if (lambda > 0) {
|
const lastPoint = line[line.length - 1];
|
||||||
return add(a, scale(b_, lambda));
|
const distanceA = distanceTo(lastPoint, vertexA) + distanceTo(vertexA, end);
|
||||||
} else {
|
const distanceB = distanceTo(lastPoint, vertexB) + distanceTo(vertexB, end);
|
||||||
return a;
|
|
||||||
|
line.push(distanceA < distanceB ? vertexA : vertexB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line.push(end);
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -52,7 +52,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 +72,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 +96,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