Doodle3D-Slicer/src/sliceActions/intersectionsToShapes.js
casperlamboo a4d8e255cc mesh now slices geometry again
No need for doodle3d-core import
2017-12-19 12:38:58 +01:00

142 lines
4.6 KiB
JavaScript

import { subtract, normal, normalize, dot, distanceTo, clone } from './helpers/VectorUtils.js';
export default function intersectionsToShapes(intersectionLayers, faces, openObjectIndexes, settings) {
const layers = [];
for (let layer = 0; layer < intersectionLayers.length; layer ++) {
const fillShapes = [];
const lineShapesOpen = [];
const lineShapesClosed = [];
const { points, faceIndexes } = intersectionLayers[layer];
if (faceIndexes.length === 0) continue;
const shapes = {};
for (let i = 0; i < faceIndexes.length; i ++) {
const { lineIndexes, objectIndex, flatNormal } = faces[faceIndexes[i]];
const a = points[lineIndexes[0]];
const b = points[lineIndexes[1]];
const c = points[lineIndexes[2]];
const lineSegment = [];
if (a && b) {
lineSegment.push(a, b);
} else if (b && c) {
lineSegment.push(b, c);
} else if (c && a) {
lineSegment.push(c, a);
} else {
continue;
}
const segmentNormal = normalize(normal(subtract(lineSegment[1], lineSegment[0])));
if (dot(segmentNormal, flatNormal) < 0) lineSegment.reverse();
if (!shapes[objectIndex]) shapes[objectIndex] = { lineSegments: [] };
const shape = shapes[objectIndex];
shape.lineSegments.push(lineSegment)
}
for (const objectIndex in shapes) {
const shape = shapes[objectIndex];
const openShape = openObjectIndexes[objectIndex];
const lines = [shape.lineSegments.pop()];
loop: while (shape.lineSegments.length !== 0) {
for (let i = 0; i < lines.length; i ++) {
const line = lines[i];
const lastPoint = line[line.length - 1];
let closestSegmentEnd;
let endHit = false;
const distanceEnd = new WeakMap();
for (let i = 0; i < shape.lineSegments.length; i ++) {
const lineSegment = shape.lineSegments[i];
if (lastPoint === lineSegment[0]) {
closestSegmentEnd = lineSegment;
endHit = true;
break;
}
const distance = distanceTo(lastPoint, lineSegment[0]);
distanceEnd.set(lineSegment, distance);
}
if (!endHit) {
closestSegmentEnd = shape.lineSegments.sort((a, b) => {
const distanceA = distanceEnd.get(a);
const distanceB = distanceEnd.get(b);
if (distanceA === distanceB) return distanceTo(a[0], a[1]) - distanceTo(b[0], b[1]);
return distanceA - distanceB;
})[0];
if (distanceTo(closestSegmentEnd[0], lastPoint) < .001) endHit = true;
}
if (endHit) {
shape.lineSegments.splice(shape.lineSegments.indexOf(closestSegmentEnd), 1);
line.splice(line.length, 0, closestSegmentEnd[1]);
continue loop;
}
const firstPoint = line[0];
let closestSegmentStart;
let hitStart = false;
const distanceStart = new WeakMap();
for (let i = 0; i < shape.lineSegments.length; i ++) {
const lineSegment = shape.lineSegments[i];
if (firstPoint === lineSegment[1]) {
closestSegmentStart = lineSegment;
hitStart = true;
break;
}
const distance = distanceTo(firstPoint, lineSegment[1]);
distanceStart.set(lineSegment, distance);
}
if (!hitStart) {
closestSegmentStart = shape.lineSegments.sort((a, b) => {
const distanceA = distanceStart.get(a);
const distanceB = distanceStart.get(b);
if (distanceA === distanceB) return distanceTo(a[0], a[1]) - distanceTo(b[0], b[1]);
return distanceA - distanceB;
})[0];
if (distanceTo(closestSegmentStart[1], firstPoint) < .001) hitStart = true;
}
if (hitStart) {
shape.lineSegments.splice(shape.lineSegments.indexOf(closestSegmentStart), 1);
line.splice(0, 0, closestSegmentStart[0]);
continue loop;
}
}
lines.push(shape.lineSegments.pop());
}
if (openShape) {
for (const line of lines) {
const closed = distanceTo(line[0], line[line.length - 1]) < .001;
if (closed) {
lineShapesClosed.push(line);
} else {
lineShapesOpen.push(line);
}
}
} else {
fillShapes.push(...lines);
}
}
layers.push({ fillShapes, lineShapesOpen, lineShapesClosed });
}
return layers;
}