mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-11-22 21:47:59 +01:00
Merge branch 'feature/improved-open-closed-detection' into develop
This commit is contained in:
commit
4e38acd9bd
1
example/models/airplane.json
Normal file
1
example/models/airplane.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,5 +1,4 @@
|
|||||||
import 'three.js';
|
import 'three.js';
|
||||||
import 'three.js/loaders/STLLoader';
|
|
||||||
import { Settings, printerSettings, userSettings, Slicer } from 'src/index.js';
|
import { Settings, printerSettings, userSettings, Slicer } from 'src/index.js';
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
@ -8,18 +7,15 @@ const settings = new Settings({
|
|||||||
...userSettings
|
...userSettings
|
||||||
});
|
});
|
||||||
|
|
||||||
const stlLoader = new THREE.STLLoader();
|
const jsonLoader = new THREE.JSONLoader();
|
||||||
stlLoader.load('stl/traktor.stl', async (geometry) => {
|
jsonLoader.load('models/airplane.json', async geometry => {
|
||||||
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
|
|
||||||
|
|
||||||
geometry.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI / -2));
|
geometry.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI / -2));
|
||||||
geometry.applyMatrix(new THREE.Matrix4().setPosition(new THREE.Vector3(50, -0.1, 50)));
|
geometry.applyMatrix(new THREE.Matrix4().setPosition(new THREE.Vector3(50, 0.1, 50)));
|
||||||
geometry.mergeVertices();
|
|
||||||
geometry.computeFaceNormals();
|
geometry.computeFaceNormals();
|
||||||
|
|
||||||
const slicer = new Slicer().setGeometry(geometry);
|
const slicer = new Slicer().setGeometry(geometry);
|
||||||
const gcode = await slicer.slice(settings);
|
const gcode = slicer.sliceSync(settings);
|
||||||
|
|
||||||
const file = new File([gcode], 'traktor.gcode', { type: 'text/plain' });
|
const file = new File([gcode], 'gcode.gcode', { type: 'text/plain' });
|
||||||
saveAs(file);
|
saveAs(file);
|
||||||
});
|
});
|
||||||
|
55582
example/stl/Airplane.stl
55582
example/stl/Airplane.stl
File diff suppressed because it is too large
Load Diff
94222
example/stl/Rocket.stl
94222
example/stl/Rocket.stl
File diff suppressed because it is too large
Load Diff
Binary file not shown.
36906
example/stl/traktor.stl
36906
example/stl/traktor.stl
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,6 @@ SystemJS.config({
|
|||||||
"https": "npm:jspm-nodelibs-https@0.2.0",
|
"https": "npm:jspm-nodelibs-https@0.2.0",
|
||||||
"react-dom": "npm:react-dom@15.3.2",
|
"react-dom": "npm:react-dom@15.3.2",
|
||||||
"babel-plugin-transform-react-jsx": "npm:babel-plugin-transform-react-jsx@6.8.0",
|
"babel-plugin-transform-react-jsx": "npm:babel-plugin-transform-react-jsx@6.8.0",
|
||||||
"three.js/loaders/STLLoader": "github:mrdoob/three.js@r83/examples/js/loaders/STLLoader.js",
|
|
||||||
"file-saver": "npm:file-saver@1.3.3"
|
"file-saver": "npm:file-saver@1.3.3"
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
@ -139,16 +138,8 @@ SystemJS.config({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
meta: {
|
|
||||||
"three.js/loaders/STLLoader": {
|
|
||||||
"deps": [
|
|
||||||
"three.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
map: {
|
map: {
|
||||||
"babel": "npm:babel-core@5.8.38",
|
"babel": "npm:babel-core@5.8.38"
|
||||||
"three.js/loaders/STLLoader": "github:mrdoob/three.js@r75/examples/js/loaders/STLLoader.js"
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ export default function calculateLayersIntersections(lines, settings) {
|
|||||||
for (let lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
|
||||||
const line = lines[lineIndex].line;
|
const line = lines[lineIndex].line;
|
||||||
|
|
||||||
|
if (line.isFlat) continue;
|
||||||
|
|
||||||
const min = Math.ceil(Math.min(line.start.y, line.end.y) / layerHeight);
|
const min = Math.ceil(Math.min(line.start.y, line.end.y) / layerHeight);
|
||||||
const max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight);
|
const max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as THREE from 'three.js';
|
import * as THREE from 'three.js';
|
||||||
|
|
||||||
function addLine(geometry, lineLookup, lines, a, b) {
|
function addLine(geometry, lineLookup, lines, a, b, isFlat) {
|
||||||
const index = lines.length;
|
const index = lines.length;
|
||||||
lineLookup[`${a}_${b}`] = index;
|
lineLookup[`${a}_${b}`] = index;
|
||||||
|
|
||||||
@ -8,13 +8,13 @@ function addLine(geometry, lineLookup, lines, a, b) {
|
|||||||
line: new THREE.Line3(geometry.vertices[a], geometry.vertices[b]),
|
line: new THREE.Line3(geometry.vertices[a], geometry.vertices[b]),
|
||||||
connects: [],
|
connects: [],
|
||||||
normals: [],
|
normals: [],
|
||||||
open: false
|
isFlat
|
||||||
});
|
});
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function createLines(geometry, settings, openClosed) {
|
export default function createLines(geometry, settings) {
|
||||||
console.log('constructing unique lines from geometry');
|
console.log('constructing unique lines from geometry');
|
||||||
|
|
||||||
const lines = [];
|
const lines = [];
|
||||||
@ -22,34 +22,28 @@ export default function createLines(geometry, settings, openClosed) {
|
|||||||
|
|
||||||
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) {
|
const lookupA = lineLookup[`${face.b}_${face.a}`];
|
||||||
const normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
|
const lookupB = lineLookup[`${face.c}_${face.b}`];
|
||||||
|
const lookupC = lineLookup[`${face.a}_${face.c}`];
|
||||||
|
|
||||||
const lookupA = lineLookup[`${face.b}_${face.a}`];
|
const isFlat = face.normal.y !== 1 && face.normal.y !== -1;
|
||||||
const lookupB = lineLookup[`${face.c}_${face.b}`];
|
|
||||||
const lookupC = lineLookup[`${face.a}_${face.c}`];
|
|
||||||
|
|
||||||
// only add unique lines
|
// only add unique lines
|
||||||
// returns index of said line
|
// returns index of said line
|
||||||
const indexA = typeof lookupA !== 'undefined' ? lookupA : addLine(geometry, lineLookup, lines, face.a, face.b);
|
const lineIndexA = typeof lookupA !== 'undefined' ? lookupA : addLine(geometry, lineLookup, lines, face.a, face.b, isFlat);
|
||||||
const indexB = typeof lookupB !== 'undefined' ? lookupB : addLine(geometry, lineLookup, lines, face.b, face.c);
|
const lineIndexB = typeof lookupB !== 'undefined' ? lookupB : addLine(geometry, lineLookup, lines, face.b, face.c, isFlat);
|
||||||
const indexC = typeof lookupC !== 'undefined' ? lookupC : addLine(geometry, lineLookup, lines, face.c, face.a);
|
const lineIndexC = typeof lookupC !== 'undefined' ? lookupC : addLine(geometry, lineLookup, lines, face.c, face.a, isFlat);
|
||||||
|
|
||||||
// set connecting lines (based on face)
|
// set connecting lines (based on face)
|
||||||
lines[indexA].connects.push(indexB, indexC);
|
lines[lineIndexA].connects.push(lineIndexB, lineIndexC);
|
||||||
lines[indexB].connects.push(indexC, indexA);
|
lines[lineIndexB].connects.push(lineIndexC, lineIndexA);
|
||||||
lines[indexC].connects.push(indexA, indexB);
|
lines[lineIndexC].connects.push(lineIndexA, lineIndexB);
|
||||||
|
|
||||||
lines[indexA].normals.push(normal);
|
const normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
|
||||||
lines[indexB].normals.push(normal);
|
lines[lineIndexA].normals.push(normal);
|
||||||
lines[indexC].normals.push(normal);
|
lines[lineIndexB].normals.push(normal);
|
||||||
|
lines[lineIndexC].normals.push(normal);
|
||||||
lines[indexA].open = open;
|
|
||||||
lines[indexB].open = open;
|
|
||||||
lines[indexC].open = open;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
|
@ -1,42 +1,45 @@
|
|||||||
export default function detectOpenClosed(geometry) {
|
export default function detectOpenClosed(lines) {
|
||||||
console.log('detecting open and closed lines');
|
console.log('detecting open and closed lines');
|
||||||
|
|
||||||
const pools = getPools(geometry);
|
const pools = getPools(lines);
|
||||||
const openVertices = getOpenVertices(geometry);
|
const openLines = lines.map(line => line.connects.length === 2);
|
||||||
|
|
||||||
const openFaces = [];
|
|
||||||
for (let i = 0; i < pools.length; i ++) {
|
for (let i = 0; i < pools.length; i ++) {
|
||||||
const pool = pools[i];
|
const pool = pools[i];
|
||||||
|
|
||||||
const isOpen = pool.some(face => openVertices[face.a] || openVertices[face.b] || openVertices[face.c]);
|
const isOpenGeometry = pool.some(lineIndex => openLines[lineIndex]);
|
||||||
|
|
||||||
if (isOpen) openFaces.splice(openFaces.length, 0, ...pool);
|
for (let j = 0; j < pool.length; j ++) {
|
||||||
|
const lineIndex = pool[j];
|
||||||
|
const line = lines[lineIndex];
|
||||||
|
line.openGeometry = isOpenGeometry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return geometry.faces.map(face => openFaces.includes(face));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findPool(pools, faceA) {
|
function findPool(pools, lines, lineIndex) {
|
||||||
|
const { connects } = lines[lineIndex];
|
||||||
for (let i = 0; i < pools.length; i ++) {
|
for (let i = 0; i < pools.length; i ++) {
|
||||||
const pool = pools[i];
|
const pool = pools[i];
|
||||||
|
|
||||||
if (pool.find(faceB => faceA.a === faceB.a || faceA.a === faceB.b || faceA.a === faceB.c)) {
|
if (pool.find(lineIndex => connects.includes(lineIndex))) {
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no pool found
|
||||||
|
// create new pool
|
||||||
const pool = [];
|
const pool = [];
|
||||||
pools.push(pool);
|
pools.push(pool);
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPools(geometry) {
|
function getPools(lines) {
|
||||||
const pools = [];
|
const pools = [];
|
||||||
|
|
||||||
for (let i = 0; i < geometry.faces.length; i ++) {
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
|
||||||
const face = geometry.faces[i];
|
const pool = findPool(pools, lines, lineIndex);
|
||||||
const pool = findPool(pools, face);
|
pool.push(lineIndex);
|
||||||
pool.push(face);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < pools.length; i ++) {
|
for (let i = 0; i < pools.length; i ++) {
|
||||||
@ -46,8 +49,9 @@ function getPools(geometry) {
|
|||||||
const poolB = pools[j];
|
const poolB = pools[j];
|
||||||
|
|
||||||
for (let k = 0; k < poolA.length; k ++) {
|
for (let k = 0; k < poolA.length; k ++) {
|
||||||
const faceA = poolA[k];
|
const { connects } = lines[poolA[k]];
|
||||||
if (poolB.find(faceB => faceA.a === faceB.a || faceA.a === faceB.b || faceA.a === faceB.c)) {
|
|
||||||
|
if (poolB.find(lineIndex => connects.includes(lineIndex))) {
|
||||||
poolA.splice(poolA.length, 0, ...poolB);
|
poolA.splice(poolA.length, 0, ...poolB);
|
||||||
poolB.splice(0, poolB.length);
|
poolB.splice(0, poolB.length);
|
||||||
}
|
}
|
||||||
@ -57,15 +61,3 @@ function getPools(geometry) {
|
|||||||
|
|
||||||
return pools.filter(pool => pool.length > 0);
|
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);
|
|
||||||
}
|
|
||||||
|
@ -22,7 +22,7 @@ export default function intersectionsToShapes(layerIntersectionIndexes, layerInt
|
|||||||
const shape = [];
|
const shape = [];
|
||||||
|
|
||||||
const firstPoints = [index];
|
const firstPoints = [index];
|
||||||
const { open: openGeometry } = lines[index];
|
const { openGeometry } = lines[index];
|
||||||
let isFirstPoint = true;
|
let isFirstPoint = true;
|
||||||
let openShape = true;
|
let openShape = true;
|
||||||
|
|
||||||
|
@ -13,12 +13,11 @@ 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) {
|
||||||
geometry.mergeVertices();
|
|
||||||
geometry.computeFaceNormals();
|
geometry.computeFaceNormals();
|
||||||
|
|
||||||
// get unique lines from geometry;
|
// get unique lines from geometry;
|
||||||
const openClosed = detectOpenClosed(geometry);
|
const lines = createLines(geometry, settings);
|
||||||
const lines = createLines(geometry, settings, openClosed);
|
const openClosed = detectOpenClosed(lines);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
layerIntersectionIndexes,
|
layerIntersectionIndexes,
|
||||||
|
Loading…
Reference in New Issue
Block a user