Better detection of open closed shapes

when a ‘single walled’,  ‘closed’ shape is sliced the shape will appear
to be closed by the slicer. This happens because the start and endpoint
of the 2d shape are connected. This commits fixes this.

In the new approach al parts of the geometry are split up into shapes.
Then the 3d shapes are places into two categories (closed and open
geometries).

Based on weather the 3d geometry is open or closed the 2d shape will be
open or closed

@mith @peteruithoven
This commit is contained in:
casperlamboo 2017-05-26 17:11:38 +02:00
parent 5f5b1254ad
commit 846ddcd97a
4 changed files with 88 additions and 9 deletions

View File

@ -13,7 +13,7 @@ function addLine(geometry, lineLookup, lines, a, b) {
return index; return index;
} }
export default function createLines(geometry, settings) { export default function createLines(geometry, settings, openClosed) {
console.log('constructing unique lines from geometry'); console.log('constructing unique lines from geometry');
const lines = []; const lines = [];
@ -21,6 +21,8 @@ export default function createLines(geometry, settings) {
for (let i = 0; i < geometry.faces.length; i ++) { for (let i = 0; i < geometry.faces.length; i ++) {
const face = geometry.faces[i]; const face = geometry.faces[i];
const open = openClosed[i];
if (face.normal.y !== 1 && face.normal.y !== -1) { if (face.normal.y !== 1 && face.normal.y !== -1) {
const normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize(); const normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
@ -42,6 +44,8 @@ export default function createLines(geometry, settings) {
lines[indexA].normals.push(normal); lines[indexA].normals.push(normal);
lines[indexB].normals.push(normal); lines[indexB].normals.push(normal);
lines[indexC].normals.push(normal); lines[indexC].normals.push(normal);
lines[indexA].open = open;
} }
} }

View File

@ -0,0 +1,71 @@
export default function detectOpenClosed(geometry) {
console.log('detecting open and closed lines');
const pools = getPools(geometry);
const openVertices = getOpenVertices(geometry);
const openFaces = [];
for (let i = 0; i < pools.length; i ++) {
const pool = pools[i];
const isOpen = pool.some(face => openVertices[face.a] || openVertices[face.b] || openVertices[face.c]);
if (isOpen) openFaces.splice(openFaces.length, 0, ...pool);
}
return geometry.faces.map(face => openFaces.includes(face));
}
function findPool(pools, faceA) {
for (let i = 0; i < pools.length; i ++) {
const pool = pools[i];
if (pool.find(faceB => faceA.a === faceB.a || faceA.a === faceB.b || faceA.a === faceB.c)) {
return pool;
}
}
const pool = [];
pools.push(pool);
return pool;
}
function getPools(geometry) {
const pools = [];
for (let i = 0; i < geometry.faces.length; i ++) {
const face = geometry.faces[i];
const pool = findPool(pools, face);
pool.push(face);
}
for (let i = 0; i < pools.length; i ++) {
const poolA = pools[i];
for (let j = i + 1; j < pools.length; j ++) {
const poolB = pools[j];
for (let k = 0; k < poolA.length; k ++) {
const faceA = poolA[k];
if (poolB.find(faceB => faceA.a === faceB.a || faceA.a === faceB.b || faceA.a === faceB.c)) {
poolA.splice(poolA.length, 0, ...poolB);
poolB.splice(0, poolB.length);
}
}
}
}
return pools.filter(pool => pool.length > 0);
}
function getOpenVertices(geometry) {
const vertices = Array(geometry.vertices.length).fill(0);
for (let i = 0; i < geometry.faces.length; i ++) {
const face = geometry.faces[i];
vertices[face.a] ++;
vertices[face.b] ++;
vertices[face.c] ++;
}
return vertices.map(numFaces => numFaces < 4);
}

View File

@ -22,8 +22,9 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt
const shape = []; const shape = [];
const firstPoints = [index]; const firstPoints = [index];
const { open: openGeometry } = lines[index];
let isFirstPoint = true; let isFirstPoint = true;
let closed = false; let openShape = true;
while (index !== -1) { while (index !== -1) {
const intersection = intersectionPoints[index]; const intersection = intersectionPoints[index];
@ -38,8 +39,8 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt
for (let i = 0; i < connects.length; i ++) { for (let i = 0; i < connects.length; i ++) {
index = connects[i]; index = connects[i];
if (firstPoints.indexOf(index) !== -1 && shape.length > 2) { if (firstPoints.includes(index) && shape.length > 2) {
closed = true; openShape = false;
index = -1; index = -1;
break; break;
} }
@ -82,7 +83,7 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt
isFirstPoint = false; isFirstPoint = false;
} }
if (!closed) { if (openShape) {
index = firstPoints[0]; index = firstPoints[0];
while (index !== -1) { while (index !== -1) {
@ -107,10 +108,11 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt
} }
} }
if (closed) { if (openGeometry) {
closedShapes.push(shape); if (!openShape) shape.push(shape[0].clone());
} else {
openShapes.push(shape); openShapes.push(shape);
} else {
closedShapes.push(shape);
} }
} }

View File

@ -8,12 +8,14 @@ import addBrim from './addBrim.js';
import optimizePaths from './optimizePaths.js'; import optimizePaths from './optimizePaths.js';
import shapesToSlices from './shapesToSlices.js'; import shapesToSlices from './shapesToSlices.js';
import slicesToGCode from './slicesToGCode.js'; import slicesToGCode from './slicesToGCode.js';
import detectOpenClosed from './detectOpenClosed.js';
import applyPrecision from './applyPrecision.js'; import applyPrecision from './applyPrecision.js';
import removePrecision from './removePrecision.js'; import removePrecision from './removePrecision.js';
export default function(geometry, settings) { export default function(geometry, settings) {
// get unique lines from geometry; // get unique lines from geometry;
const lines = createLines(geometry, settings); const openClosed = detectOpenClosed(geometry);
const lines = createLines(geometry, settings, openClosed);
const { const {
layerIntersectionIndexes, layerIntersectionIndexes,