mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-11-21 21:27:56 +01:00
share functions in comb.js
This commit is contained in:
parent
c642375295
commit
2c953496f7
214
comb.js
214
comb.js
@ -1,211 +1,5 @@
|
||||
import earcut from 'earcut';
|
||||
import { add, divide, distanceTo, normalize, subtract, normal, dot } from './src/sliceActions/helpers/vector2.js';
|
||||
|
||||
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))
|
||||
};
|
||||
|
||||
const intersectionA = subtract(intersection, a1);
|
||||
const directionA = subtract(a2, a1);
|
||||
const normalA = normalize(directionA);
|
||||
const distanceA = dot(normalA, intersectionA);
|
||||
if (distanceA < 0 || distanceA > dot(normalA, directionA)) return false;
|
||||
|
||||
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;
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
// const distanceMap = new WeakMap();
|
||||
// function findClosestPath(convexPolygons, start, end, visited = [], path = [], distance = 0) {
|
||||
// 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 (let i = 0; i < connects.length; i ++) {
|
||||
// const connect = connects[i];
|
||||
// if (visited.includes(connect.to)) continue;
|
||||
//
|
||||
// const positibiltyDistance = distance + connect.distance;
|
||||
// const posibility = findClosestPath(convexPolygons, connect.to, end, visited, [...path, connect], positibiltyDistance);
|
||||
// if (posibility) {
|
||||
// posibilities.push(posibility);
|
||||
// distanceMap.set(posibility, positibiltyDistance);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (posibilities.length === 0) {
|
||||
// return null;
|
||||
// } else if (posibilities.length === 1) {
|
||||
// return posibilities[0];
|
||||
// } else if (posibilities.length > 1) {
|
||||
// return posibilities.sort((a, b) => distanceMap.get(a) - distanceMap.get(b))[0];
|
||||
// }
|
||||
// }
|
||||
|
||||
const findKey = _key => ({ key }) => _key === key;
|
||||
function findClosestPath(map, start, end) {
|
||||
// dijkstra's algorithm
|
||||
const distances = { [start]: 0 };
|
||||
const open = [{ key: 0, nodes: [start] }];
|
||||
const predecessors = {};
|
||||
|
||||
while (open.length !== 0) {
|
||||
const key = Math.min(...open.map(n => n.key).sort());
|
||||
const bucket = open.find(findKey(key));
|
||||
const node = bucket.nodes.shift();
|
||||
const currentDistance = key;
|
||||
const { connects } = map[node];
|
||||
|
||||
if (bucket.nodes.length === 0) open.splice(open.indexOf(bucket), 1);
|
||||
|
||||
for (let i = 0; i < connects.length; i ++) {
|
||||
const { distance, to } = connects[i];
|
||||
const totalDistance = distance + currentDistance;
|
||||
const vertexDistance = distances[to];
|
||||
|
||||
if ((typeof vertexDistance === 'undefined') || (vertexDistance > totalDistance)) {
|
||||
distances[to] = totalDistance;
|
||||
|
||||
let openNode = open.find(findKey(totalDistance));
|
||||
if (!openNode) {
|
||||
openNode = { key: totalDistance, nodes: [] };
|
||||
open.push(openNode);
|
||||
}
|
||||
openNode.nodes.push(to);
|
||||
|
||||
predecessors[to] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof distances[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 containLineInPath(path, start, end, vertices) {
|
||||
const line = [start];
|
||||
|
||||
for (let i = 0; i < path.length; i ++) {
|
||||
const { edge: [indexA, indexB] } = path[i];
|
||||
const vertexA = vertices[indexA];
|
||||
const vertexB = vertices[indexB];
|
||||
|
||||
const intersection = lineIntersection(start, end, vertexA, vertexB);
|
||||
if (!intersection) {
|
||||
const lastPoint = line[line.length - 1];
|
||||
const distanceA = distanceTo(lastPoint, vertexA) + distanceTo(vertexA, end);
|
||||
const distanceB = distanceTo(lastPoint, vertexB) + distanceTo(vertexB, end);
|
||||
|
||||
line.push(distanceA < distanceB ? vertexA : vertexB);
|
||||
}
|
||||
}
|
||||
|
||||
line.push(end);
|
||||
return line;
|
||||
}
|
||||
|
||||
import { pointIsInsideConvex, decompose, findClosestPath, containLineInPath } from './src/sliceActions/helpers/comb.js';
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
document.body.appendChild(canvas);
|
||||
@ -228,8 +22,8 @@ function circle(radius = 10, x = 0, y = 0, clockWise = true, segments = 40) {
|
||||
return shape;
|
||||
}
|
||||
|
||||
const START = { x: 300, y: 40 };
|
||||
const END = { x: 300, y: 20 };
|
||||
const START = { x: 30, y: 550 };
|
||||
const END = { x: 400, y: 300 };
|
||||
// const CONCAVE_POLYGON = [[
|
||||
// { x: 10, y: 10 },
|
||||
// { x: 600, y: 10 },
|
||||
@ -240,7 +34,7 @@ const END = { x: 300, y: 20 };
|
||||
// { x: 160, y: 120 },
|
||||
// { x: 120, y: 400 },
|
||||
// { x: 400, y: 400 }
|
||||
// ], circle(50, 300, 100, false)];
|
||||
// ]];
|
||||
const CONCAVE_POLYGON = [
|
||||
circle(300, 305, 305, true),
|
||||
circle(40, 305, 105, false),
|
||||
|
@ -43,7 +43,7 @@ function lineIntersection(a1, a2, b1, b2) {
|
||||
return intersection;
|
||||
}
|
||||
|
||||
function pointIsInsideConvex(point, convex, vertices) {
|
||||
export 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]];
|
||||
@ -56,7 +56,7 @@ function pointIsInsideConvex(point, convex, vertices) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function decompose(polygon) {
|
||||
export function decompose(polygon) {
|
||||
const vertices = polygon.reduce((points, path) => {
|
||||
points.push(...path);
|
||||
return points;
|
||||
@ -114,7 +114,7 @@ function decompose(polygon) {
|
||||
}
|
||||
|
||||
// const distanceMap = new WeakMap();
|
||||
// function findClosestPath(convexPolygons, start, end, visited = [], path = [], distance = 0) {
|
||||
// export function findClosestPath(convexPolygons, start, end, visited = [], path = [], distance = 0) {
|
||||
// if (start === end) return [];
|
||||
//
|
||||
// visited = [...visited, start];
|
||||
@ -147,7 +147,7 @@ function decompose(polygon) {
|
||||
// }
|
||||
|
||||
const findKey = _key => ({ key }) => _key === key;
|
||||
function findClosestPath(map, start, end) {
|
||||
export function findClosestPath(map, start, end) {
|
||||
// dijkstra's algorithm
|
||||
const distances = { [start]: 0 };
|
||||
const open = [{ key: 0, nodes: [start] }];
|
||||
@ -204,7 +204,7 @@ function findClosestPath(map, start, end) {
|
||||
return path;
|
||||
}
|
||||
|
||||
function containLineInPath(path, start, end, vertices) {
|
||||
export function containLineInPath(path, start, end, vertices) {
|
||||
let line = [start];
|
||||
|
||||
for (let i = 0; i < path.length; i ++) {
|
||||
@ -215,7 +215,7 @@ function containLineInPath(path, start, end, vertices) {
|
||||
|
||||
const intersection = lineIntersection(lastPoint, end, vertexA, vertexB);
|
||||
if (!intersection) {
|
||||
line = containLineInPath(path.slice(0, i), start, lastPoint, vertices);
|
||||
// line = containLineInPath(path.slice(0, i), start, lastPoint, vertices);
|
||||
|
||||
const distanceA = distanceTo(lastPoint, vertexA) + distanceTo(vertexA, end);
|
||||
const distanceB = distanceTo(lastPoint, vertexB) + distanceTo(vertexB, end);
|
||||
|
Loading…
Reference in New Issue
Block a user