mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-11-21 21:27:56 +01:00
140 lines
3.6 KiB
JavaScript
140 lines
3.6 KiB
JavaScript
import { pointIsInsideConvex, decompose, findClosestPath, containLineInPath } from './src/sliceActions/helpers/comb.js';
|
|
|
|
const canvas = document.createElement('canvas');
|
|
document.body.appendChild(canvas);
|
|
canvas.width = 610;
|
|
canvas.height = 610;
|
|
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: 30, y: 550 };
|
|
const END = { x: 400, y: 300 };
|
|
// const CONCAVE_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 CONCAVE_POLYGON = [
|
|
circle(300, 305, 305, true),
|
|
circle(40, 305, 105, false),
|
|
circle(40, 305, 205, false),
|
|
circle(40, 305, 305, false),
|
|
circle(40, 305, 405, false),
|
|
circle(40, 305, 505, false)
|
|
];
|
|
|
|
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 { convexPolygons, vertices } = decompose(CONCAVE_POLYGON);
|
|
const startPolygon = convexPolygons.findIndex(({ face }) => pointIsInsideConvex(START, face, vertices));
|
|
const endPolygon = convexPolygons.findIndex(({ face }) => pointIsInsideConvex(END, face, vertices));
|
|
if (startPolygon === -1 || endPolygon === -1) return;
|
|
|
|
const path = findClosestPath(convexPolygons, startPolygon, endPolygon);
|
|
if (!path) return;
|
|
const line = containLineInPath(path, START, END, vertices);
|
|
|
|
// draw
|
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
context.beginPath();
|
|
for (const shape of CONCAVE_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.fillStyle = 'black';
|
|
context.strokeStyle = 'black';
|
|
context.textAlign = 'center';
|
|
context.textBaseline = 'middle';
|
|
context.lineWidth = 1;
|
|
context.font = '14px arial';
|
|
for (let i = 0; i < convexPolygons.length; i ++) {
|
|
const { face, center } = convexPolygons[i];
|
|
|
|
context.beginPath();
|
|
for (const index of face) {
|
|
const vertex = vertices[index];
|
|
context.lineTo(vertex.x, vertex.y);
|
|
}
|
|
context.closePath();
|
|
context.stroke();
|
|
|
|
context.fillText(i, center.x, center.y);
|
|
}
|
|
|
|
if (path) {
|
|
context.beginPath();
|
|
for (const { edge: [indexA, indexB] } of path) {
|
|
const pointA = vertices[indexA];
|
|
const pointB = vertices[indexB];
|
|
context.moveTo(pointA.x, pointA.y);
|
|
context.lineTo(pointB.x, pointB.y);
|
|
}
|
|
context.strokeStyle = 'blue';
|
|
context.lineWidth = 3;
|
|
context.stroke();
|
|
}
|
|
|
|
if (line) {
|
|
context.beginPath();
|
|
for (const point of line) {
|
|
context.lineTo(point.x, point.y);
|
|
}
|
|
context.strokeStyle = 'green';
|
|
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();
|
|
}
|