Public
Edited
Jul 19, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
segmentPlaneIntersect = (v0, v1, plane) => {
let tEps = 0.00001;
let v0_dist_to_plane = plane.distanceToPoint(v0);
let v1_dist_to_plane = plane.distanceToPoint(v1);
let pointIntersect = v0_dist_to_plane * v1_dist_to_plane < 0;
let segmentIntersect = v0_dist_to_plane < tEps && v1_dist_to_plane < tEps;
if (pointIntersect) {
// NOTE: isect = v0 + t * (v1 - v0)
let denom = v0_dist_to_plane - v1_dist_to_plane;
if (Math.abs(denom) < tEps) {
return v0.clone();
}
let t = v0_dist_to_plane / denom;
let isect = new THREE.Vector3().copy(v0);
let rest = new THREE.Vector3().copy(v1).sub(v0).multiplyScalar(t);
return isect.add(rest);
}
}
Insert cell
Insert cell
Insert cell
Insert cell
calcContoursForLayerSegment = (segments, segIdx) => {
if (segments.length === 0) {
return [];
}
let contours = [];
// NOTE: define a contour as an ordered list of points
let currContour = [];
let unvisitedSegments = segments.slice();
let currSegment = unvisitedSegments[0];
let pointToPush = currSegment[0];
let pointForFindingNextSeg = currSegment[1];
while (unvisitedSegments.length > 0) {
currContour.push(pointToPush);
unvisitedSegments.splice(unvisitedSegments.indexOf(currSegment), 1);
let foundNextSegment = unvisitedSegments.some((potentialSegment) => {
if (potentialSegment[0].approxEqual(pointForFindingNextSeg)) {
currSegment = potentialSegment;
pointToPush = potentialSegment[0];
pointForFindingNextSeg = potentialSegment[1];
return true;
}
if (potentialSegment[1].approxEqual(pointForFindingNextSeg)) {
currSegment = potentialSegment;
pointToPush = potentialSegment[1];
pointForFindingNextSeg = potentialSegment[0];
return true;
}
});
if (!foundNextSegment) {
contours.push(currContour.slice());
currContour = [];
if (unvisitedSegments.length > 0) {
currSegment = unvisitedSegments[0];
pointToPush = currSegment[0];
pointForFindingNextSeg = currSegment[1];
}
}
}
return contours;
}
Insert cell
Insert cell
contourClockwise = (pts) => {
// SOURCE: https://discourse.threejs.org/t/how-to-collect-the-clockwise-and-anticlock-wise-points-from-reference-points/39309/6
// With modifications for use with THREE.Vector3
const len = pts.length;
let [minx, miny, mi] = [pts[0].x, pts[0].z, 0];
for (let i = 1; i < len; i++) {
const [pix, piy] = [pts[i].x, pts[i].z];
if (pix < minx || (pix == minx && piy < miny))
[minx, miny, mi] = [pix, piy, i];
}
const [mp, mn] = [mi != 0 ? mi - 1 : len - 1, mi != len - 1 ? mi + 1 : 0];
const [a, b, c] = [pts[mp], pts[mi], pts[mn]];
const det = (b.x - a.x) * (c.z - a.z) - (c.x - a.x) * (b.z - a.z);
return det < 0;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function downsampleContour(contour) {
if (contour.length < 2) {
return [];
}
let curve = new THREE.CatmullRomCurve3(contour);
let pts = curve.getSpacedPoints(Math.ceil(numDivisions));
return [contour[0]].concat(pts).concat(contour[contour.length - 1]);
}
Insert cell
Insert cell
Insert cell
numDivisions = 16
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function sliceLayersToInsts(sliceLayers) {
let round = (n) => Math.floor(n * 10000) / 10000;
const extrusionMultiplier = 0.2;
const defaultExtrusion = 1.5;
const retractDefault = 0.2;
const layerFeed = 1000;
const filamentHeight = 0.4;
return sliceLayers
.map((layer) => {
let contourInsts = layer.map((contour) => {
let firstPt = contour[0];
let travelToStart = `G0 X${round(firstPt.x)} Y${round(
firstPt.z
)} Z${round(firstPt.y)} E0 F${layerFeed}`;
let insts = [];
contour.forEach((_, i) => {
if (i === 0) {
return;
}
let prevPt = contour[i - 1];
let currPt = contour[i];
let dist = Math.sqrt(
(prevPt.x - currPt.x) ** 2 + (prevPt.y - currPt.y) ** 2
);
let extrusion = defaultExtrusion;
let printMove = `G1 X${round(currPt.x)} Y${round(currPt.z)} Z${
currPt.y + filamentHeight
} E${extrusion} F${layerFeed}`;
insts.push(printMove);
});
let returnToStart = `G1 X${round(firstPt.x)} Y${round(
firstPt.z
)} Z${round(firstPt.y)} E0`;
let retract = `G1 E${-retractDefault}`;
insts.push(returnToStart);
insts.push(retract);
insts.push("; end contour");
return insts;
});
return contourInsts;
})
.flat();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function layerToZigZag(layer, nextLayer) {
if (!nextLayer || nextLayer.length === 0) {
return [];
}
const retractAmount = 0.2;
const filamentHeight = 0.4;
const pauseTime = 1500;
const eVertical = 0.4;
const eHypotenuse = 1.75;
const fVertical = 250;
const fHypotenuse = 1500;
return layer
.map((contour, contourIdx) => {
return contour
.map((pt, i) => {
if (i < 2 || i > contour.length - 2) {
return null;
}
let nextLayerPt = nextLayer[contourIdx][i];
let thisLayerNextPt =
i + 2 < contour.length ? contour[i + 1] : contour[0];
let moveToPt = `G0 X${pt.x} Y${pt.y} Z${
pt.z + filamentHeight
} E0 F${fVertical}`;
let unretract = `G1 E${retractAmount}`;
let retract = `G1 E${-retractAmount}`;
let pause = `G4 P${pauseTime}`;
let vertical = `G0 Z${
nextLayerPt.y + filamentHeight
} E${eVertical} F${fVertical} ; vertical`;
let hypotenuse = `G0 X${pt.x} Y${pt.z} Z${
pt.y + filamentHeight
} E${eHypotenuse} F${fHypotenuse} ; hypotenuse`;
return [unretract, vertical, retract, pause, unretract, hypotenuse];
})
.flat();
})
.flat()
.filter((inst) => !!inst);
}
Insert cell
Insert cell
zigZags = downsampledContours.map((_, cIdx) => {
let currLayer = downsampledContours[cIdx];
let nextLayer =
cIdx + 1 < downsampledContours.length ? downsampledContours[cIdx + 1] : [];
return layerToZigZag(currLayer, nextLayer);
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
interleaved = downsampledTp
// You can edit this line to show only layers or zigzags
.map((layer, i) => [layer, zigZags[i]])
.flat()
.flat()
Insert cell
Insert cell
Insert cell
Insert cell
completeToolpath = {
let mainTp = interleaved.join("\n");
return preamble.concat(mainTp).concat(epilogue);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mutable test = 2
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
modelVizSpace.scene.add(testMesh);
testMesh.setRotationFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI);
// testMesh.position.set(25, 0, 25);
// testMesh.scale.set(0.5, 0.5, 0.5);
modelVizSpace.threeRenderScene();
invalidation.then((_) => {
modelVizSpace.scene.remove(testMesh);
});
return testMesh.position;
}
Insert cell
Insert cell
function forceLayerClockwise(layer) {
return layer.map((contour) => {
if (contour.length < 3) {
return contour;
}
});
}
Insert cell
downsampledContours.map((layer) => contourClockwise(layer[0]))
Insert cell
basicSliceTp = sliceLayersToInsts(sliceLayersBasic).flat()
Insert cell
Insert cell
Insert cell
crCurve = new THREE.CatmullRomCurve3(sliceLayersWireframe[0][0])
Insert cell
crCurve.getSpacedPoints(Math.ceil(numDivisions))
Insert cell
unpositionedDownsampledContours = sliceLayersWireframe.map((layer) => {
return layer
.map((contour) => downsampleContour(contour))
.filter((c) => c.length > 0)
.map((contour) =>
!contourClockwise(contour) ? [...contour].reverse() : contour
);
})
Insert cell
downsampledContours = offsetLayersToBed(
unpositionedDownsampledContours,
testMesh
)
Insert cell
downsampledTp = sliceLayersToInsts(downsampledContours)
Insert cell
sampleZigZag = layerToZigZag(downsampledContours[0], downsampledContours[1])
Insert cell
Insert cell
slicedTp = interleaved.slice(0, sliceEnd)
Insert cell
populateVizSpace(tssVizSpace, [slicedTp])
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more