Merge branch 'develop'

This commit is contained in:
casperlamboo 2017-07-18 14:02:45 +02:00
commit a5384b3de1
84 changed files with 189130 additions and 456104 deletions

23
.gitignore vendored
View File

@ -1,23 +1,8 @@
.DS_Store
*.DS_Store
.DS_Store
jspm_packages/*
src/.DS_Store
node_modules/*
src/.DS_Store
src/library/.DS_Store
.DS_Store
src/script/.DS_Store
src/.DS_Store
bower_components/
src/oldcode.js
test.html
print_manager.html
bundle.js

View File

@ -1,32 +1,25 @@
# Doodle3D-Slicer
The Doodle3D Slicer is designed for developers to make it easier to export 3d models to the Doodle3D WiFi-Box. The slicers includes a gcode slicer and a class designed for communication with the WiFi-Box. All the classes are in the D3D name space.
Three.js, Clipper.js and jQuery are required to run the Doodl3D slicer. All are included in the source.
This is an example of code.
JavaScript gcode slicer, Intended to use with the Doodle3D WiFi-Box
# Usage
```javascript
var localIp = "192.168.5.1";
var doodleBox = new D3D.Box(localIp);
import * as THREE from 'three';
import { defaultSettings, Slicer } from 'Doodle3D/Doodle3D-Slicer';
doodleBox.onload = function () {
"use strict";
var printer = new D3D.Printer(printerSettings, userSettings);
var geometry = new THREE.BoxGeometry(20, 20, 20, 1, 1, 1);
var material = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 100;
mesh.position.z = 100;
mesh.position.y = 10;
var slicer = new D3D.Slicer().setMesh(mesh);
var gcode = slicer.getGcode(printer);
doodleBox.print(gcode);
const settings = {
...defaultSettings.base,
...defaultSettings.material.pla,
...defaultSettings.printer.ultimaker2go,
...defaultSettings.quality.high
};
```
For more information see http://www.doodle3d.com/
const geometry = new THREE.TorusGeometry(20, 10, 30, 30);
const slicer = new SLICER.Slicer();
slicer.setGeometry(geometry);
const gcode = await slicer.slice(settings)
.progress(({ done, total, action }) => {
const percentage = `${(done / total * 100).toFixed()}%`
console.log(action, percentage);
});
```

View File

@ -1,149 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Doedel Drie Dee</title>
<!--<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>-->
<script src="library/jquery.js"></script>
<script src="library/three.js"></script>
<script src="src/utils.js"></script>
<script src="src/box.js"></script>
<script src="src/printer.js"></script>
<script src="src/slicer.js"></script>
<script src="gcode/testgcode.js"></script>
<script src="gcode/easterbunny.js"></script>
</head>
<body>
<script>
var localIp = location.hash.substring(1);
var doodleBox, drawing;
$(document).ready(function () {
"use strict";
doodleBox = new D3D.Box(localIp);
CAL.Scene.setCanvas(document.getElementById("canvas"));
var shape = new CAL.Shape({
shapeColor: false,
closePath: false,
points: [
new CAL.Vector(20, 180),
new CAL.Vector(180, 100),
new CAL.Vector(20, 80),
new CAL.Vector(180, 60)
]
});
CAL.Scene.add(shape);
drawing = new Drawing(shape);
CAL.Scene.add(drawing);
});
function Drawing (shape) {
this.shape = shape;
this.active = true;
this.mouse = false;
}
Drawing.prototype.mouseDown = function (mouse) {
this.mouse = mouse;
};
Drawing.prototype.mouseUp = function (mouse) {
this.mouse = false;
};
Drawing.prototype.generateGcode = function () {
var gcode = doodleBox.printer.getStartCode();
var extruder = 0.0;
var points = this.shape.points;
var normalSpeed = doodleBox.printer["printer.speed"] * 60;
var bottomSpeed = doodleBox.printer["printer.bottomLayerSpeed"] * 60;
var firstLayerSlow = doodleBox.printer["printer.firstLayerSlow"] * 60;
var bottomFlowRate = doodleBox.printer["printer.bottomFlowRate"];
var travelSpeed = doodleBox.printer["printer.travelSpeed"] * 60;
var filamentThickness = doodleBox.printer["printer.filamentThickness"];
var wallThickness = doodleBox.printer["printer.wallThickness"];
var screenToMillimeterScale = doodleBox.printer["printer.screenToMillimeterScale"];
var layerHeight = doodleBox.printer["printer.layerHeight"];
var useSubLayers = doodleBox.printer["printer.useSubLayers"];
var enableTraveling = doodleBox.printer["printer.enableTraveling"];
var retractionEnabled = doodleBox.printer["printer.retraction.enabled"];
var retractionspeed = doodleBox.printer["printer.retraction.speed"] * 60;
var retractionminDistance = doodleBox.printer["printer.retraction.minDistance"];
var retractionamount = doodleBox.printer["printer.retraction.amount"];
var speed = bottomSpeed.toFixed(3);
for (var layer = 0; layer < 10; layer ++) {
var lastPoint;
//turn on fan on layer 2
if (layer === 2) {
gcode.push("M106");
speed = normalSpeed.toFixed(3);
}
for (var i = 0; i < points.length; i ++) {
var point = points[i];
var x = point.x.toFixed(3);
var y = point.y.toFixed(3);
var z = ((layer + 1) * layerHeight).toFixed(3);
if (i === 0) {
if (layer >= 2 && retractionEnabled) {
gcode.push("G0 E" + (extruder - retractionamount).toFixed(3) + " F" + (retractionspeed * 60).toFixed(3));
}
gcode.push("G0 X" + x + " Y" + y + " Z" + z + " F" + travelSpeed);
if (layer >= 2 && retractionEnabled) {
gcode.push("G0 E" + extruder.toFixed(3) + " F" + (retractionspeed * 60).toFixed(3));
}
}
else {
var distance = point.subtract(lastPoint).length();
var flowRate = (layer < 2) ? bottomFlowRate : 1;
var filamentSurfaceArea = Math.pow((filamentThickness/2), 2) * Math.PI;
//extruder code from gcodeGenerating.js
extruder += distance * wallThickness * layerHeight / filamentSurfaceArea * flowRate;
gcode.push("G1 X" + x + " Y" + y + " Z" + z + " F" + speed + " E" + extruder.toFixed(3));
}
lastPoint = point;
}
}
gcode = gcode.concat(doodleBox.printer.getEndCode());
return gcode;
};
Drawing.prototype.step = function (dt, group) {
if (this.mouse) {
this.shape.addPoint(new CAL.Vector(this.mouse.x, this.mouse.y));
group.drawCanvas = true;
group.clearCanvas = true;
}
};
(function loop () {
requestAnimFrame(loop);
CAL.Scene.cycle();
})();
</script>
<canvas id="canvas" width="200" height="200"></canvas>
</body>
</html>

128
example/SlicerViewer.js Normal file
View File

@ -0,0 +1,128 @@
import React from 'react';
import { PRECISION } from '../src/constants.js';
export default class SlicerViewer extends React.Component {
state = {
layer: 0,
render: {
renderIntersectionPoints: false,
renderShape1: false,
renderShape2: true,
renderOuterLine: true,
renderInnerLine: true,
renderFill: true
}
};
changeSlider = (event) => {
this.setState({
layer: parseInt(event.target.value)
});
};
onControl = (event) => {
const section = event.target.value;
this.setState({
render: {
...this.state.render,
[section]: !this.state.render[section]
}
});
};
render() {
const { layer, render } = this.state;
const { layerIntersectionPoints, settings, layerShapes, slices } = this.props;
const numLayers = settings.dimensionsZ / settings.layerHeight;
const intersectionPoints = layerIntersectionPoints[layer + 1];
const shape = layerShapes[layer];
const slice = slices[layer];
return (
<div>
<svg viewBox={`-20 -20 ${settings.dimensionsX + 40} ${settings.dimensionsX + 40}`}>
<rect
width={settings.dimensionsX}
height={settings.dimensionsY}
fill="lightGrey"
/>
{render.renderIntersectionPoints && intersectionPoints.map(({ x, y }, i) => (
<circle key={i} cx={x} cy={y} r="0.3"/>
))}
{render.renderShape1 && shape && shape.closedShapes.map((closedShape, i) => (
<polygon
key={i}
points={closedShape.map(({ x, y }) => `${x} ${y}`).join(' ')}
fill="rgba(255, 0, 0, 0.5)"
/>
))}
{slice && slice.parts.map((slicePart, i) => (
<g key={i}>
{render.renderShape2 && <ClipperShapeSVG
shape={slicePart.shape}
scale={PRECISION}
color="rgba(0, 0, 0, 0.5)"
fill
/>}
{render.renderOuterLine && <ClipperShapeSVG
shape={slicePart.outerLine}
scale={1.0}
color="blue"
strokeWidth={settings.nozzleDiameter * 0.9}
/>}
{render.renderInnerLine && slicePart.innerLines.map((innerLine, i) => (
<ClipperShapeSVG
key={i}
shape={innerLine}
scale={1.0}
color="red"
strokeWidth={settings.nozzleDiameter * 0.9}
/>
))}
{render.renderFill && <ClipperShapeSVG
shape={slicePart.fill}
scale={1.0}
color="yellow"
strokeWidth={settings.nozzleDiameter * 0.9}
/>}
</g>
))}
</svg>
<div id="controls">
<input onChange={this.changeSlider} value={layer} type="range" min="0" max={numLayers} />
<p>Layer: {layer}</p>
<p><label><input type="checkbox" value="renderIntersectionPoints" onChange={this.onControl} checked={render.renderIntersectionPoints} />Render Intersection Points</label></p>
<p><label><input type="checkbox" value="renderShape1" onChange={this.onControl} checked={render.renderShape1} />Render Shape 1</label></p>
<p><label><input type="checkbox" value="renderShape2" onChange={this.onControl} checked={render.renderShape2} />Render Shape 2</label></p>
<p><label><input type="checkbox" value="renderOuterLine" onChange={this.onControl} checked={render.renderOuterLine} />Render Out Line</label></p>
<p><label><input type="checkbox" value="renderInnerLine" onChange={this.onControl} checked={render.renderInnerLine} />Render Inner Lines</label></p>
<p><label><input type="checkbox" value="renderFill" onChange={this.onControl} checked={render.renderFill} />Render Fill</label></p>
</div>
</div>
);
}
}
class ClipperShapeSVG extends React.Component {
render() {
const { shape, color = 'black', strokeWidth, scale, fill } = this.props;
const data = shape.paths.map(path => {
const pathData = path.map(({ X, Y }, i) => `${i === 0 ? 'M' : 'L '}${X * scale} ${Y * scale}`);
if (shape.closed) pathData.push('Z');
return pathData.join(' ');
}).join(' ');
return (
<path
d={data}
strokeWidth={typeof strokeWidth === 'number' ? strokeWidth : 1.0}
vectorEffect={typeof strokeWidth === 'number' ? 'none' : 'non-scaling-stroke'}
fill={fill ? color : 'none'}
stroke={!fill ? color : 'none'}
/>
);
}
}

View File

@ -0,0 +1,54 @@
import calculateLayersIntersections from 'src/sliceActions/calculateLayersIntersections.js';
import createLines from 'src/sliceActions/createLines.js';
import generateInfills from 'src/sliceActions/generateInfills.js';
import generateInnerLines from 'src/sliceActions/generateInnerLines.js';
import generateSupport from 'src/sliceActions/generateSupport.js';
import intersectionsToShapes from 'src/sliceActions/intersectionsToShapes.js';
import addBrim from 'src/sliceActions/addBrim.js';
import optimizePaths from 'src/sliceActions/optimizePaths.js';
import shapesToSlices from 'src/sliceActions/shapesToSlices.js';
import slicesToGCode from 'src/sliceActions/slicesToGCode.js';
import applyPrecision from 'src/sliceActions/applyPrecision.js';
import removePrecision from 'src/sliceActions/removePrecision.js';
export default function generateRawData(geometry, settings) {
const rawData = {};
const lines = createLines(geometry, settings);
const {
layerIntersectionIndexes,
layerIntersectionPoints
} = calculateLayersIntersections(lines, settings);
rawData.layerIntersectionPoints = layerIntersectionPoints
.map(intersectionPoints => intersectionPoints.map(intersectionPoint => intersectionPoint.clone()));
const layerShapes = intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings);
rawData.layerShapes = layerShapes
.map(({ closedShapes, openShapes }) => ({
closedShapes: closedShapes.map(closedShape => closedShape.map(vector => vector.clone())),
openShapes: openShapes.map(openShape => openShape.map(vector => vector.clone()))
}));
applyPrecision(layerShapes);
const slices = shapesToSlices(layerShapes, settings);
generateInnerLines(slices, settings);
generateInfills(slices, settings);
generateSupport(slices, settings);
addBrim(slices, settings);
optimizePaths(slices, settings);
removePrecision(slices);
rawData.slices = slices;
const gcode = slicesToGCode(slices, settings);
rawData.gcode = gcode;
return rawData;
}

11
example/index.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE>
<html>
<head>
<title>Doodle3D Slicer</title>
</head>
<body>
<p><a href="./viewer.html">Viewer</a></p>
<p><a href="./save.html">Save</a></p>
</body>
</html>

21
example/main.css Normal file
View File

@ -0,0 +1,21 @@
* {
margin: 0;
padding: 0;
}
#container {
position: relative;
}
#container, svg {
width: 100%;
height: 100%;
}
svg, #controls {
position: absolute;
}
input[type=range] {
width: 100%;
}

File diff suppressed because one or more lines are too long

19
example/save.html Normal file
View File

@ -0,0 +1,19 @@
<!DOCTYPE>
<html>
<head>
<title>Doodle3D Slicer - Save</title>
<script type="text/javascript" src="../jspm_packages/system.js"></script>
<script type="text/javascript" src="../jspm.config.js"></script>
<script type="text/javascript">
System.import('./save.js');
</script>
</head>
<body>
</body>
</html>

27
example/save.js Normal file
View File

@ -0,0 +1,27 @@
import * as THREE from 'three';
import { defaultSettings, Slicer } from 'src/index.js';
import { saveAs } from 'file-saver';
const settings = {
...defaultSettings.base,
...defaultSettings.material.pla,
...defaultSettings.printer.ultimaker2go,
...defaultSettings.quality.high
};
const jsonLoader = new THREE.JSONLoader();
jsonLoader.load('models/airplane.json', async geometry => {
geometry.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI / -2));
geometry.applyMatrix(new THREE.Matrix4().setPosition(new THREE.Vector3(50, -0.1, 50)));
geometry.computeFaceNormals();
const slicer = new Slicer().setGeometry(geometry);
const gcode = await slicer.slice(settings)
.progress(({ done, total, action }) => {
const percentage = `${(done / total * 100).toFixed()}%`
document.write(`<p>${action}, ${percentage}</p>`);
});
const file = new File([gcode], 'gcode.gcode', { type: 'text/plain' });
saveAs(file);
});

55582
example/stl/Airplane.stl Normal file

File diff suppressed because it is too large Load Diff

94222
example/stl/Rocket.stl Normal file

File diff suppressed because it is too large Load Diff

BIN
example/stl/castle.stl Normal file

Binary file not shown.

36906
example/stl/traktor.stl Normal file

File diff suppressed because it is too large Load Diff

29
example/viewer.html Normal file
View File

@ -0,0 +1,29 @@
<!DOCTYPE>
<html>
<head>
<title>Doodle3D Slicer - Viewer</title>
<style>
#gcode {
font-family: monospace;
}
</style>
<script type="text/javascript" src="../jspm_packages/system.js"></script>
<script type="text/javascript" src="../jspm.config.js"></script>
<link href="main.css" rel="stylesheet"/>
<script type="text/javascript">
System.import('example/viewer.js');
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>

35
example/viewer.js Normal file
View File

@ -0,0 +1,35 @@
import 'three.js';
import 'three.js/loaders/STLLoader';
import React from 'react';
import ReactDOM, { render } from 'react-dom';
import * as SLICER from 'src/index.js';
import generateRawData from './generateRawData.js';
import SlicerViewer from './SlicerViewer.js';
const settings = new SLICER.Settings({
...SLICER.printerSettings['ultimaker2go'],
...SLICER.userSettings
});
const stlLoader = new THREE.STLLoader();
stlLoader.load('stl/Airplane.stl', (geometry) => {
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
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().scale(0.8));
geometry.mergeVertices();
geometry.computeFaceNormals();
const rawData = generateRawData(geometry, settings);
render(
<SlicerViewer
layerIntersectionPoints={rawData.layerIntersectionPoints}
layerShapes={rawData.layerShapes}
slices={rawData.slices}
settings={settings}
/>,
document.getElementById('container')
);
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,83 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Doedel Drie Dee</title>
<script src="library/jquery.js"></script>
<script src="library/three.js"></script>
<script src="src/utils.js"></script>
<script src="src/box.js"></script>
<script src="src/printer.js"></script>
</head>
<body>
<script>
var api = "http://connect.doodle3d.com/api/";
var printers = [];
$(document).ready(function () {
"use strict";
var listDoodle = $("#printers-doodle");
var listSliceTest = $("#printers-slicetest");
var listSliceWebworker = $("#printers-webworker");
listDoodle.append("<li><a href='doodle.html#192.168.5.1'>Wired Printer</a></li>");
listSliceTest.append("<li><a href='slice_test.html#192.168.5.1'>Wired Printer</a></li>");
listSliceWebworker.append("<li><a href='webworker_test.html#192.168.5.1'>Wired Printer</a></li>");
listDoodle.append("<li><a href='doodle.html#" + window.location.host + ":3000'>Node Server</a></li>");
listSliceTest.append("<li><a href='slice_test.html#" + window.location.host + ":3000'>Node Server</a></li>");
listSliceWebworker.append("<li><a href='webworker_test.html#" + window.location.host + ":3000'>Node Server</a></li>");
/*
printers.push({
name: "wired box",
d3dbox: new D3D.Box("192.168.5.1")
});
*/
getAPI(api + "list.php", function (boxes) {
for (var i = 0; i < boxes.length; i ++) {
var box = boxes[i];
/*
printers.push({
name: box.wifiboxid,
d3dbox: new D3D.Box(box.localip)
});
*/
listDoodle.append("<li><a href='doodle.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>");
listSliceTest.append("<li><a href='slice_test.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>");
listSliceWebworker.append("<li><a href='webworker_test.html#" + box.localip + "'>" + box.wifiboxid + "</a></li>");
}
});
});
</script>
<p>Doodle</p>
<ul id="printers-doodle"></ul>
<p>Slice Test</p>
<ul id="printers-slicetest"></ul>
<p>Webworkers</p>
<ul id="printers-webworker"></ul>
<!--
<table>
<tr>
<th>localip</th>
<th>wifiboxid</th>
<th>date</th>
</tr>
<tr style="display: none">
<td>localip</td>
<td>wifiboxid</td>
<td>date</td>
</tr>
</table>
-->
</body>
</html>

479
jspm.config.js Normal file
View File

@ -0,0 +1,479 @@
SystemJS.config({
paths: {
"github:": "jspm_packages/github/",
"npm:": "jspm_packages/npm/",
"example/": "example/",
"slicer/": "src/"
},
browserConfig: {
"baseURL": "/"
},
devConfig: {
"map": {
"babel-runtime": "npm:babel-runtime@5.8.38",
"core-js": "npm:core-js@1.2.7",
"plugin-babel": "npm:systemjs-plugin-babel@0.0.12",
"react": "npm:react@15.3.2",
"domain": "github:jspm/nodelibs-domain@0.2.0-alpha",
"zlib": "github:jspm/nodelibs-zlib@0.2.0-alpha",
"https": "github:jspm/nodelibs-https@0.2.0-alpha",
"react-dom": "npm:react-dom@15.3.2",
"babel-plugin-transform-react-jsx": "npm:babel-plugin-transform-react-jsx@6.8.0",
"file-saver": "npm:file-saver@1.3.3"
},
"packages": {
"npm:babel-runtime@5.8.38": {
"map": {}
},
"npm:react@15.3.2": {
"map": {
"object-assign": "npm:object-assign@4.1.0",
"loose-envify": "npm:loose-envify@1.2.0",
"fbjs": "npm:fbjs@0.8.5"
}
},
"npm:fbjs@0.8.5": {
"map": {
"loose-envify": "npm:loose-envify@1.2.0",
"object-assign": "npm:object-assign@4.1.0",
"promise": "npm:promise@7.1.1",
"isomorphic-fetch": "npm:isomorphic-fetch@2.2.1",
"ua-parser-js": "npm:ua-parser-js@0.7.10",
"immutable": "npm:immutable@3.8.1",
"core-js": "npm:core-js@1.2.7"
}
},
"npm:loose-envify@1.2.0": {
"map": {
"js-tokens": "npm:js-tokens@1.0.3"
}
},
"npm:promise@7.1.1": {
"map": {
"asap": "npm:asap@2.0.5"
}
},
"npm:isomorphic-fetch@2.2.1": {
"map": {
"whatwg-fetch": "npm:whatwg-fetch@1.0.0",
"node-fetch": "npm:node-fetch@1.6.3"
}
},
"npm:node-fetch@1.6.3": {
"map": {
"encoding": "npm:encoding@0.1.12",
"is-stream": "npm:is-stream@1.1.0"
}
},
"npm:encoding@0.1.12": {
"map": {
"iconv-lite": "npm:iconv-lite@0.4.13"
}
},
"npm:browserify-zlib@0.1.4": {
"map": {
"readable-stream": "npm:readable-stream@2.1.5",
"pako": "npm:pako@0.2.9"
}
},
"npm:babel-plugin-transform-react-jsx@6.8.0": {
"map": {
"babel-helper-builder-react-jsx": "npm:babel-helper-builder-react-jsx@6.9.0",
"babel-plugin-syntax-jsx": "npm:babel-plugin-syntax-jsx@6.13.0",
"babel-runtime": "npm:babel-runtime@6.11.6"
}
},
"npm:babel-helper-builder-react-jsx@6.9.0": {
"map": {
"babel-runtime": "npm:babel-runtime@6.11.6",
"esutils": "npm:esutils@2.0.2",
"babel-types": "npm:babel-types@6.16.0",
"lodash": "npm:lodash@4.16.4"
}
},
"npm:babel-runtime@6.11.6": {
"map": {
"core-js": "npm:core-js@2.4.1",
"regenerator-runtime": "npm:regenerator-runtime@0.9.5"
}
},
"npm:babel-types@6.16.0": {
"map": {
"lodash": "npm:lodash@4.16.4",
"babel-runtime": "npm:babel-runtime@6.11.6",
"esutils": "npm:esutils@2.0.2",
"to-fast-properties": "npm:to-fast-properties@1.0.2"
}
},
"github:jspm/nodelibs-zlib@0.2.0-alpha": {
"map": {
"zlib-browserify": "npm:browserify-zlib@0.1.4"
}
},
"github:jspm/nodelibs-domain@0.2.0-alpha": {
"map": {
"domain-browserify": "npm:domain-browser@1.1.7"
}
}
}
},
transpiler: "plugin-babel",
packages: {
"slicer": {
"main": "index.js"
},
"example": {
"main": "example/index.js",
"format": "esm",
"meta": {
"*.js": {
"loader": "plugin-babel",
"babelOptions": {
"stage1": true,
"plugins": [
"babel-plugin-transform-react-jsx"
]
}
}
}
}
},
map: {
"babel": "npm:babel-core@5.8.38"
}
});
SystemJS.config({
packageConfigPaths: [
"npm:@*/*.json",
"npm:*.json",
"github:*/*.json"
],
map: {
"three": "npm:three@0.83.0",
"progress-promise": "npm:progress-promise@0.0.6",
"text": "github:systemjs/plugin-text@0.0.11",
"js-yaml": "npm:js-yaml@3.9.0",
"clipper-js": "github:Doodle3D/clipper-js@1.0.2",
"assert": "github:jspm/nodelibs-assert@0.2.0-alpha",
"buffer": "github:jspm/nodelibs-buffer@0.2.0-alpha",
"child_process": "github:jspm/nodelibs-child_process@0.2.0-alpha",
"constants": "github:jspm/nodelibs-constants@0.2.0-alpha",
"crypto": "github:jspm/nodelibs-crypto@0.2.0-alpha",
"events": "github:jspm/nodelibs-events@0.2.2",
"fs": "github:jspm/nodelibs-fs@0.2.0-alpha",
"http": "github:jspm/nodelibs-http@0.2.0-alpha",
"json": "github:systemjs/plugin-json@0.1.2",
"Doodle3D/clipper-js": "github:Doodle3D/clipper-js@master",
"module": "npm:jspm-nodelibs-module@0.2.0",
"os": "github:jspm/nodelibs-os@0.2.2",
"path": "github:jspm/nodelibs-path@0.2.3",
"process": "github:jspm/nodelibs-process@0.2.0-alpha",
"stream": "github:jspm/nodelibs-stream@0.2.0-alpha",
"string_decoder": "github:jspm/nodelibs-string_decoder@0.2.0-alpha",
"tty": "npm:jspm-nodelibs-tty@0.2.0",
"url": "github:jspm/nodelibs-url@0.2.0-alpha",
"util": "github:jspm/nodelibs-util@0.2.0-alpha",
"vm": "github:jspm/nodelibs-vm@0.2.0-alpha",
"worker": "github:casperlamboo/plugin-worker@master"
},
packages: {
"github:Doodle3D/clipper-js@master": {
"map": {
"clipper-lib": "npm:clipper-lib@1.0.0"
}
},
"npm:clipper-lib@1.0.0": {
"map": {}
},
"npm:stream-browserify@2.0.1": {
"map": {
"inherits": "npm:inherits@2.0.3",
"readable-stream": "npm:readable-stream@2.3.3"
}
},
"npm:buffer@4.9.1": {
"map": {
"base64-js": "npm:base64-js@1.2.1",
"isarray": "npm:isarray@1.0.0",
"ieee754": "npm:ieee754@1.1.8"
}
},
"npm:url@0.11.0": {
"map": {
"querystring": "npm:querystring@0.2.0",
"punycode": "npm:punycode@1.3.2"
}
},
"npm:readable-stream@2.1.5": {
"map": {
"string_decoder": "npm:string_decoder@0.10.31",
"inherits": "npm:inherits@2.0.3",
"isarray": "npm:isarray@1.0.0",
"buffer-shims": "npm:buffer-shims@1.0.0",
"core-util-is": "npm:core-util-is@1.0.2",
"process-nextick-args": "npm:process-nextick-args@1.0.7",
"util-deprecate": "npm:util-deprecate@1.0.2"
}
},
"npm:public-encrypt@4.0.0": {
"map": {
"randombytes": "npm:randombytes@2.0.5",
"create-hash": "npm:create-hash@1.1.3",
"parse-asn1": "npm:parse-asn1@5.1.0",
"bn.js": "npm:bn.js@4.11.7",
"browserify-rsa": "npm:browserify-rsa@4.0.1"
}
},
"npm:diffie-hellman@5.0.2": {
"map": {
"randombytes": "npm:randombytes@2.0.5",
"bn.js": "npm:bn.js@4.11.7",
"miller-rabin": "npm:miller-rabin@4.0.0"
}
},
"npm:browserify-cipher@1.0.0": {
"map": {
"browserify-des": "npm:browserify-des@1.0.0",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"browserify-aes": "npm:browserify-aes@1.0.6"
}
},
"npm:create-ecdh@4.0.0": {
"map": {
"elliptic": "npm:elliptic@6.4.0",
"bn.js": "npm:bn.js@4.11.7"
}
},
"npm:browserify-des@1.0.0": {
"map": {
"inherits": "npm:inherits@2.0.3",
"cipher-base": "npm:cipher-base@1.0.4",
"des.js": "npm:des.js@1.0.0"
}
},
"npm:evp_bytestokey@1.0.0": {
"map": {
"create-hash": "npm:create-hash@1.1.3"
}
},
"npm:browserify-aes@1.0.6": {
"map": {
"create-hash": "npm:create-hash@1.1.3",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"inherits": "npm:inherits@2.0.3",
"cipher-base": "npm:cipher-base@1.0.4",
"buffer-xor": "npm:buffer-xor@1.0.3"
}
},
"npm:browserify-rsa@4.0.1": {
"map": {
"bn.js": "npm:bn.js@4.11.7",
"randombytes": "npm:randombytes@2.0.5"
}
},
"npm:miller-rabin@4.0.0": {
"map": {
"bn.js": "npm:bn.js@4.11.7",
"brorand": "npm:brorand@1.1.0"
}
},
"npm:des.js@1.0.0": {
"map": {
"inherits": "npm:inherits@2.0.3",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0"
}
},
"npm:stream-http@2.4.0": {
"map": {
"inherits": "npm:inherits@2.0.3",
"readable-stream": "npm:readable-stream@2.1.5",
"to-arraybuffer": "npm:to-arraybuffer@1.0.1",
"builtin-status-codes": "npm:builtin-status-codes@2.0.0",
"xtend": "npm:xtend@4.0.1"
}
},
"github:Doodle3D/clipper-js@1.0.2": {
"map": {
"Breush/clipper-lib": "github:Breush/clipper-lib@patch-1",
"clipper-lib": "npm:clipper-lib@6.2.1"
}
},
"npm:js-yaml@3.9.0": {
"map": {
"argparse": "npm:argparse@1.0.9",
"esprima": "npm:esprima@4.0.0"
}
},
"npm:argparse@1.0.9": {
"map": {
"sprintf-js": "npm:sprintf-js@1.0.3"
}
},
"github:jspm/nodelibs-buffer@0.2.0-alpha": {
"map": {
"buffer-browserify": "npm:buffer@4.9.1"
}
},
"github:jspm/nodelibs-crypto@0.2.0-alpha": {
"map": {
"crypto-browserify": "npm:crypto-browserify@3.11.1"
}
},
"npm:crypto-browserify@3.11.1": {
"map": {
"browserify-cipher": "npm:browserify-cipher@1.0.0",
"browserify-sign": "npm:browserify-sign@4.0.4",
"create-ecdh": "npm:create-ecdh@4.0.0",
"create-hash": "npm:create-hash@1.1.3",
"create-hmac": "npm:create-hmac@1.1.6",
"diffie-hellman": "npm:diffie-hellman@5.0.2",
"inherits": "npm:inherits@2.0.3",
"pbkdf2": "npm:pbkdf2@3.0.12",
"public-encrypt": "npm:public-encrypt@4.0.0",
"randombytes": "npm:randombytes@2.0.5"
}
},
"npm:browserify-sign@4.0.4": {
"map": {
"create-hash": "npm:create-hash@1.1.3",
"create-hmac": "npm:create-hmac@1.1.6",
"inherits": "npm:inherits@2.0.3",
"elliptic": "npm:elliptic@6.4.0",
"bn.js": "npm:bn.js@4.11.7",
"parse-asn1": "npm:parse-asn1@5.1.0",
"browserify-rsa": "npm:browserify-rsa@4.0.1"
}
},
"npm:create-hash@1.1.3": {
"map": {
"inherits": "npm:inherits@2.0.3",
"ripemd160": "npm:ripemd160@2.0.1",
"sha.js": "npm:sha.js@2.4.8",
"cipher-base": "npm:cipher-base@1.0.4"
}
},
"npm:create-hmac@1.1.6": {
"map": {
"create-hash": "npm:create-hash@1.1.3",
"inherits": "npm:inherits@2.0.3",
"ripemd160": "npm:ripemd160@2.0.1",
"safe-buffer": "npm:safe-buffer@5.1.1",
"sha.js": "npm:sha.js@2.4.8",
"cipher-base": "npm:cipher-base@1.0.4"
}
},
"npm:randombytes@2.0.5": {
"map": {
"safe-buffer": "npm:safe-buffer@5.1.1"
}
},
"npm:pbkdf2@3.0.12": {
"map": {
"create-hmac": "npm:create-hmac@1.1.6",
"ripemd160": "npm:ripemd160@2.0.1",
"safe-buffer": "npm:safe-buffer@5.1.1",
"sha.js": "npm:sha.js@2.4.8",
"create-hash": "npm:create-hash@1.1.3"
}
},
"npm:ripemd160@2.0.1": {
"map": {
"inherits": "npm:inherits@2.0.3",
"hash-base": "npm:hash-base@2.0.2"
}
},
"npm:sha.js@2.4.8": {
"map": {
"inherits": "npm:inherits@2.0.3"
}
},
"npm:elliptic@6.4.0": {
"map": {
"inherits": "npm:inherits@2.0.3",
"bn.js": "npm:bn.js@4.11.7",
"hmac-drbg": "npm:hmac-drbg@1.0.1",
"hash.js": "npm:hash.js@1.1.3",
"brorand": "npm:brorand@1.1.0",
"minimalistic-crypto-utils": "npm:minimalistic-crypto-utils@1.0.1",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0"
}
},
"npm:parse-asn1@5.1.0": {
"map": {
"browserify-aes": "npm:browserify-aes@1.0.6",
"create-hash": "npm:create-hash@1.1.3",
"evp_bytestokey": "npm:evp_bytestokey@1.0.0",
"pbkdf2": "npm:pbkdf2@3.0.12",
"asn1.js": "npm:asn1.js@4.9.1"
}
},
"npm:cipher-base@1.0.4": {
"map": {
"safe-buffer": "npm:safe-buffer@5.1.1",
"inherits": "npm:inherits@2.0.3"
}
},
"npm:hash-base@2.0.2": {
"map": {
"inherits": "npm:inherits@2.0.3"
}
},
"npm:hmac-drbg@1.0.1": {
"map": {
"hash.js": "npm:hash.js@1.1.3",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0",
"minimalistic-crypto-utils": "npm:minimalistic-crypto-utils@1.0.1"
}
},
"npm:hash.js@1.1.3": {
"map": {
"inherits": "npm:inherits@2.0.3",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0"
}
},
"npm:asn1.js@4.9.1": {
"map": {
"bn.js": "npm:bn.js@4.11.7",
"inherits": "npm:inherits@2.0.3",
"minimalistic-assert": "npm:minimalistic-assert@1.0.0"
}
},
"github:jspm/nodelibs-stream@0.2.0-alpha": {
"map": {
"stream-browserify": "npm:stream-browserify@2.0.1"
}
},
"npm:readable-stream@2.3.3": {
"map": {
"inherits": "npm:inherits@2.0.3",
"isarray": "npm:isarray@1.0.0",
"safe-buffer": "npm:safe-buffer@5.1.1",
"string_decoder": "npm:string_decoder@1.0.3",
"util-deprecate": "npm:util-deprecate@1.0.2",
"process-nextick-args": "npm:process-nextick-args@1.0.7",
"core-util-is": "npm:core-util-is@1.0.2"
}
},
"npm:string_decoder@1.0.3": {
"map": {
"safe-buffer": "npm:safe-buffer@5.1.1"
}
},
"github:jspm/nodelibs-string_decoder@0.2.0-alpha": {
"map": {
"string_decoder-browserify": "npm:string_decoder@0.10.31"
}
},
"github:jspm/nodelibs-http@0.2.0-alpha": {
"map": {
"http-browserify": "npm:stream-http@2.4.0"
}
},
"github:jspm/nodelibs-url@0.2.0-alpha": {
"map": {
"url-browserify": "npm:url@0.11.0"
}
}
}
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4
library/jquery.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,433 +0,0 @@
/**
* @author aleeper / http://adamleeper.com/
* @author mrdoob / http://mrdoob.com/
* @author gero3 / https://github.com/gero3
*
* Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.
*
* Supports both binary and ASCII encoded files, with automatic detection of type.
*
* Limitations:
* Binary decoding supports "Magics" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL).
* There is perhaps some question as to how valid it is to always assume little-endian-ness.
* ASCII decoding assumes file is UTF-8. Seems to work for the examples...
*
* Usage:
* var loader = new THREE.STLLoader();
* loader.load( './models/stl/slotted_disk.stl', function ( geometry ) {
* scene.add( new THREE.Mesh( geometry ) );
* });
*
* For binary STLs geometry might contain colors for vertices. To use it:
* // use the same code to load STL as above
* if (geometry.hasColors) {
* material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREE.VertexColors });
* } else { .... }
* var mesh = new THREE.Mesh( geometry, material );
*/
THREE.STLLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.STLLoader.prototype = {
constructor: THREE.STLLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.XHRLoader( scope.manager );
loader.setCrossOrigin( this.crossOrigin );
loader.setResponseType('arraybuffer');
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
parse: function ( data ) {
var isBinary = function () {
var expect, face_size, n_faces, reader;
reader = new DataView( binData );
face_size = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8);
n_faces = reader.getUint32(80, true);
expect = 80 + (32 / 8) + (n_faces * face_size);
if ( expect === reader.byteLength ) {
return true;
}
// some binary files will have different size from expected,
// checking characters higher than ASCII to confirm is binary
var fileLength = reader.byteLength;
for ( var index = 0; index < fileLength; index ++ ) {
if ( reader.getUint8(index, false) > 127 ) {
return true;
}
}
return false;
};
var binData = this.ensureBinary( data );
return isBinary()
? this.parseBinary( binData )
: this.parseASCII( this.ensureString( data ) );
},
parseBinary: function ( data ) {
var reader = new DataView( data );
var faces = reader.getUint32( 80, true );
var r, g, b, hasColors = false, colors;
var defaultR, defaultG, defaultB, alpha;
// process STL header
// check for default color in header ("COLOR=rgba" sequence).
for ( var index = 0; index < 80 - 10; index ++ ) {
if ((reader.getUint32(index, false) == 0x434F4C4F /*COLO*/) &&
(reader.getUint8(index + 4) == 0x52 /*'R'*/) &&
(reader.getUint8(index + 5) == 0x3D /*'='*/)) {
hasColors = true;
colors = new Float32Array( faces * 3 * 3);
defaultR = reader.getUint8(index + 6) / 255;
defaultG = reader.getUint8(index + 7) / 255;
defaultB = reader.getUint8(index + 8) / 255;
alpha = reader.getUint8(index + 9) / 255;
}
}
var dataOffset = 84;
var faceLength = 12 * 4 + 2;
var offset = 0;
var geometry = new THREE.BufferGeometry();
var vertices = new Float32Array( faces * 3 * 3 );
var normals = new Float32Array( faces * 3 * 3 );
for ( var face = 0; face < faces; face ++ ) {
var start = dataOffset + face * faceLength;
var normalX = reader.getFloat32(start, true);
var normalY = reader.getFloat32(start + 4, true);
var normalZ = reader.getFloat32(start + 8, true);
if (hasColors) {
var packedColor = reader.getUint16(start + 48, true);
if ((packedColor & 0x8000) === 0) { // facet has its own unique color
r = (packedColor & 0x1F) / 31;
g = ((packedColor >> 5) & 0x1F) / 31;
b = ((packedColor >> 10) & 0x1F) / 31;
} else {
r = defaultR;
g = defaultG;
b = defaultB;
}
}
for ( var i = 1; i <= 3; i ++ ) {
var vertexstart = start + i * 12;
vertices[ offset ] = reader.getFloat32( vertexstart, true );
vertices[ offset + 1 ] = reader.getFloat32( vertexstart + 4, true );
vertices[ offset + 2 ] = reader.getFloat32( vertexstart + 8, true );
normals[ offset ] = normalX;
normals[ offset + 1 ] = normalY;
normals[ offset + 2 ] = normalZ;
if (hasColors) {
colors[ offset ] = r;
colors[ offset + 1 ] = g;
colors[ offset + 2 ] = b;
}
offset += 3;
}
}
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
if (hasColors) {
geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
geometry.hasColors = true;
geometry.alpha = alpha;
}
return geometry;
},
parseASCII: function ( data ) {
var geometry, length, normal, patternFace, patternNormal, patternVertex, result, text;
geometry = new THREE.Geometry();
patternFace = /facet([\s\S]*?)endfacet/g;
while ( ( result = patternFace.exec( data ) ) !== null ) {
text = result[0];
patternNormal = /normal[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;
while ( ( result = patternNormal.exec( text ) ) !== null ) {
normal = new THREE.Vector3( parseFloat( result[ 1 ] ), parseFloat( result[ 3 ] ), parseFloat( result[ 5 ] ) );
}
patternVertex = /vertex[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;
while ( ( result = patternVertex.exec( text ) ) !== null ) {
geometry.vertices.push( new THREE.Vector3( parseFloat( result[ 1 ] ), parseFloat( result[ 3 ] ), parseFloat( result[ 5 ] ) ) );
}
length = geometry.vertices.length;
geometry.faces.push( new THREE.Face3( length - 3, length - 2, length - 1, normal ) );
}
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
return geometry;
},
ensureString: function ( buf ) {
if (typeof buf !== "string") {
var array_buffer = new Uint8Array(buf);
var str = '';
for (var i = 0; i < buf.byteLength; i ++) {
str += String.fromCharCode(array_buffer[i]); // implicitly assumes little-endian
}
return str;
} else {
return buf;
}
},
ensureBinary: function ( buf ) {
if (typeof buf === "string") {
var array_buffer = new Uint8Array(buf.length);
for (var i = 0; i < buf.length; i ++) {
array_buffer[i] = buf.charCodeAt(i) & 0xff; // implicitly assumes little-endian
}
return array_buffer.buffer || array_buffer;
} else {
return buf;
}
}
};
if ( typeof DataView === 'undefined') {
DataView = function(buffer, byteOffset, byteLength) {
this.buffer = buffer;
this.byteOffset = byteOffset || 0;
this.byteLength = byteLength || buffer.byteLength || buffer.length;
this._isString = typeof buffer === "string";
}
DataView.prototype = {
_getCharCodes:function(buffer,start,length) {
start = start || 0;
length = length || buffer.length;
var end = start + length;
var codes = [];
for (var i = start; i < end; i ++) {
codes.push(buffer.charCodeAt(i) & 0xff);
}
return codes;
},
_getBytes: function (length, byteOffset, littleEndian) {
var result;
// Handle the lack of endianness
if (littleEndian === undefined) {
littleEndian = this._littleEndian;
}
// Handle the lack of byteOffset
if (byteOffset === undefined) {
byteOffset = this.byteOffset;
} else {
byteOffset = this.byteOffset + byteOffset;
}
if (length === undefined) {
length = this.byteLength - byteOffset;
}
// Error Checking
if (typeof byteOffset !== 'number') {
throw new TypeError('DataView byteOffset is not a number');
}
if (length < 0 || byteOffset + length > this.byteLength) {
throw new Error('DataView length or (byteOffset+length) value is out of bounds');
}
if (this.isString) {
result = this._getCharCodes(this.buffer, byteOffset, byteOffset + length);
} else {
result = this.buffer.slice(byteOffset, byteOffset + length);
}
if (!littleEndian && length > 1) {
if (!(result instanceof Array)) {
result = Array.prototype.slice.call(result);
}
result.reverse();
}
return result;
},
// Compatibility functions on a String Buffer
getFloat64: function (byteOffset, littleEndian) {
var b = this._getBytes(8, byteOffset, littleEndian),
sign = 1 - (2 * (b[7] >> 7)),
exponent = ((((b[7] << 1) & 0xff) << 3) | (b[6] >> 4)) - ((1 << 10) - 1),
// Binary operators such as | and << operate on 32 bit values, using + and Math.pow(2) instead
mantissa = ((b[6] & 0x0f) * Math.pow(2, 48)) + (b[5] * Math.pow(2, 40)) + (b[4] * Math.pow(2, 32)) +
(b[3] * Math.pow(2, 24)) + (b[2] * Math.pow(2, 16)) + (b[1] * Math.pow(2, 8)) + b[0];
if (exponent === 1024) {
if (mantissa !== 0) {
return NaN;
} else {
return sign * Infinity;
}
}
if (exponent === -1023) { // Denormalized
return sign * mantissa * Math.pow(2, -1022 - 52);
}
return sign * (1 + mantissa * Math.pow(2, -52)) * Math.pow(2, exponent);
},
getFloat32: function (byteOffset, littleEndian) {
var b = this._getBytes(4, byteOffset, littleEndian),
sign = 1 - (2 * (b[3] >> 7)),
exponent = (((b[3] << 1) & 0xff) | (b[2] >> 7)) - 127,
mantissa = ((b[2] & 0x7f) << 16) | (b[1] << 8) | b[0];
if (exponent === 128) {
if (mantissa !== 0) {
return NaN;
} else {
return sign * Infinity;
}
}
if (exponent === -127) { // Denormalized
return sign * mantissa * Math.pow(2, -126 - 23);
}
return sign * (1 + mantissa * Math.pow(2, -23)) * Math.pow(2, exponent);
},
getInt32: function (byteOffset, littleEndian) {
var b = this._getBytes(4, byteOffset, littleEndian);
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
},
getUint32: function (byteOffset, littleEndian) {
return this.getInt32(byteOffset, littleEndian) >>> 0;
},
getInt16: function (byteOffset, littleEndian) {
return (this.getUint16(byteOffset, littleEndian) << 16) >> 16;
},
getUint16: function (byteOffset, littleEndian) {
var b = this._getBytes(2, byteOffset, littleEndian);
return (b[1] << 8) | b[0];
},
getInt8: function (byteOffset) {
return (this.getUint8(byteOffset) << 24) >> 24;
},
getUint8: function (byteOffset) {
return this._getBytes(1, byteOffset)[0];
}
};
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,506 +0,0 @@
solid OpenSCAD_Model
facet normal 0 0 0
outer loop
vertex 24 0 45.03
vertex 12 0 54.03
vertex 20.7846 -12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 8.48528 8.48528 54.03
vertex 12 0 54.03
vertex 20.7846 12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 -20.7846 45.03
vertex -20.7846 -12 45
vertex -12 -20.7846 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 1.46953e-015 54.03
vertex 8.48528 8.48528 54.03
vertex 7.34764e-016 12 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 0 54.03
vertex -8.48528 -8.48528 54.03
vertex 8.48528 -8.48528 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 0 54.03
vertex 8.48528 -8.48528 54.03
vertex 20.7846 -12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 0 54.03
vertex 8.48528 8.48528 54.03
vertex -8.48528 -8.48528 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 7.34764e-016 12 54.03
vertex 1.46953e-015 24 45.03
vertex -12 20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 20.7846 45.03
vertex 20.7846 12 45
vertex 12 20.7846 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 7.34764e-016 12 54.03
vertex 8.48528 8.48528 54.03
vertex 12 20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.15 -0.259808 15
vertex 0.15 0.259808 15
vertex 0.15 -0.259808 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 -12 45.03
vertex 12 -20.7846 45
vertex 20.7846 -12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 1.46953e-015 54.03
vertex -20.7846 12 45.03
vertex -24 2.93906e-015 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -24 2.93906e-015 45.03
vertex -20.7846 -12 45
vertex -20.7846 -12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 8.48528 8.48528 54.03
vertex 20.7846 12 45.03
vertex 12 20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -20.7846 -12 45
vertex -12 -20.7846 45.03
vertex -20.7846 -12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.15 0.259808 15
vertex -12 20.7846 45
vertex 1.46953e-015 24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 0.15 0.259808 15
vertex 20.7846 12 45
vertex 0.3 0 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -2.20429e-015 -12 54.03
vertex -4.40858e-015 -24 45.03
vertex 12 -20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -2.20429e-015 -12 54.03
vertex -8.48528 -8.48528 54.03
vertex -12 -20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -24 2.93906e-015 45
vertex -20.7846 12 45.03
vertex -20.7846 12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.15 0.259808 15
vertex -0.15 -0.259808 15
vertex -0.3 3.67382e-017 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 12 45
vertex 20.7846 12 45.03
vertex 24 0 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 12 45.03
vertex 12 0 54.03
vertex 24 0 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -8.48528 -8.48528 54.03
vertex 8.48528 8.48528 54.03
vertex -12 1.46953e-015 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 12 45.03
vertex 20.7846 12 45
vertex 12 20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 1.46953e-015 24 45.03
vertex -12 20.7846 45
vertex -12 20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 7.34764e-016 12 54.03
vertex -12 20.7846 45.03
vertex -8.48528 8.48528 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 12 45
vertex 0.15 0.259808 15
vertex 12 20.7846 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 1.46953e-015 24 45.03
vertex 7.34764e-016 12 54.03
vertex 12 20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -4.40858e-015 -24 45.03
vertex 12 -20.7846 45
vertex 12 -20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 8.48528 -8.48528 54.03
vertex -8.48528 -8.48528 54.03
vertex -2.20429e-015 -12 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 20.7846 45
vertex 1.46953e-015 24 45.03
vertex 1.46953e-015 24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -4.40858e-015 -24 45.03
vertex -2.20429e-015 -12 54.03
vertex -12 -20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.15 -0.259808 15
vertex -20.7846 -12 45
vertex -0.3 3.67382e-017 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.15 0.259808 15
vertex 0.15 0.259808 15
vertex -0.15 -0.259808 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 0.15 -0.259808 15
vertex 0.3 0 15
vertex 20.7846 -12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -20.7846 -12 45
vertex -0.15 -0.259808 15
vertex -12 -20.7846 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 -20.7846 45
vertex 20.7846 -12 45.03
vertex 12 -20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 0.15 -0.259808 15
vertex 0.15 0.259808 15
vertex 0.3 0 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -24 2.93906e-015 45.03
vertex -20.7846 12 45.03
vertex -24 2.93906e-015 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 1.46953e-015 54.03
vertex -24 2.93906e-015 45.03
vertex -20.7846 -12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 20.7846 45
vertex -20.7846 12 45.03
vertex -12 20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 1.46953e-015 54.03
vertex 7.34764e-016 12 54.03
vertex -8.48528 8.48528 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 1.46953e-015 24 45.03
vertex 12 20.7846 45
vertex 1.46953e-015 24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 1.46953e-015 24 45.03
vertex 12 20.7846 45.03
vertex 12 20.7846 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 -12 45.03
vertex 8.48528 -8.48528 54.03
vertex 12 -20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 8.48528 -8.48528 54.03
vertex -2.20429e-015 -12 54.03
vertex 12 -20.7846 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 20.7846 45
vertex 0.15 0.259808 15
vertex 1.46953e-015 24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 0.15 0.259808 15
vertex -0.15 0.259808 15
vertex 1.46953e-015 24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 -20.7846 45
vertex -4.40858e-015 -24 45.03
vertex -4.40858e-015 -24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -4.40858e-015 -24 45.03
vertex -12 -20.7846 45.03
vertex -12 -20.7846 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -4.40858e-015 -24 45.03
vertex -12 -20.7846 45
vertex -4.40858e-015 -24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 -20.7846 45
vertex -0.15 -0.259808 15
vertex -4.40858e-015 -24 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 -20.7846 45
vertex -4.40858e-015 -24 45
vertex 0.15 -0.259808 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -4.40858e-015 -24 45
vertex -0.15 -0.259808 15
vertex 0.15 -0.259808 15
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.15 0.259808 15
vertex -0.3 3.67382e-017 15
vertex -20.7846 12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.3 3.67382e-017 15
vertex -24 2.93906e-015 45
vertex -20.7846 12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 -20.7846 45.03
vertex -8.48528 -8.48528 54.03
vertex -20.7846 -12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -8.48528 -8.48528 54.03
vertex -12 1.46953e-015 54.03
vertex -20.7846 -12 45.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 20.7846 45.03
vertex -20.7846 12 45.03
vertex -8.48528 8.48528 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -20.7846 12 45.03
vertex -12 1.46953e-015 54.03
vertex -8.48528 8.48528 54.03
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 0.3 0 15
vertex 20.7846 12 45
vertex 24 0 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 12 -20.7846 45
vertex 0.15 -0.259808 15
vertex 20.7846 -12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -0.3 3.67382e-017 15
vertex -20.7846 -12 45
vertex -24 2.93906e-015 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -20.7846 -12 45
vertex -24 2.93906e-015 45.03
vertex -24 2.93906e-015 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 12 45
vertex 24 0 45.03
vertex 24 0 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 24 0 45.03
vertex 20.7846 -12 45.03
vertex 20.7846 -12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 24 0 45.03
vertex 20.7846 -12 45
vertex 24 0 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 20.7846 -12 45
vertex 0.3 0 15
vertex 24 0 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -20.7846 12 45.03
vertex -12 20.7846 45
vertex -20.7846 12 45
endloop
endfacet
facet normal 0 0 0
outer loop
vertex -12 20.7846 45
vertex -0.15 0.259808 15
vertex -20.7846 12 45
endloop
endfacet
endsolid OpenSCAD_Model

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

92
package.json Normal file
View File

@ -0,0 +1,92 @@
{
"jspm": {
"name": "slicer",
"main": "index.js",
"directories": {
"lib": "src"
},
"dependencies": {
"Doodle3D/clipper-js": "github:Doodle3D/clipper-js@master",
"clipper-js": "github:Doodle3D/clipper-js@1.0.2",
"js-yaml": "npm:js-yaml@^3.9.0",
"json": "github:systemjs/plugin-json@^0.1.2",
"progress-promise": "npm:progress-promise@^0.0.6",
"text": "github:systemjs/plugin-text@^0.0.11",
"three": "npm:three@0.83.0",
"worker": "github:casperlamboo/plugin-worker@master"
},
"devDependencies": {
"babel-plugin-transform-react-jsx": "npm:babel-plugin-transform-react-jsx@^6.8.0",
"babel-runtime": "npm:babel-runtime@^5.1.13",
"core-js": "npm:core-js@^1.2.0",
"file-saver": "npm:file-saver@^1.3.3",
"domain": "github:jspm/nodelibs-domain@^0.2.0-alpha",
"https": "github:jspm/nodelibs-https@^0.2.0-alpha",
"plugin-babel": "npm:systemjs-plugin-babel@^0.0.12",
"react": "npm:react@^15.3.2",
"react-dom": "npm:react-dom@^15.3.2",
"zlib": "github:jspm/nodelibs-zlib@^0.2.0-alpha"
},
"peerDependencies": {
"assert": "github:jspm/nodelibs-assert@^0.2.0-alpha",
"buffer": "github:jspm/nodelibs-buffer@^0.2.0-alpha",
"child_process": "github:jspm/nodelibs-child_process@^0.2.0-alpha",
"constants": "github:jspm/nodelibs-constants@^0.2.0-alpha",
"crypto": "github:jspm/nodelibs-crypto@^0.2.0-alpha",
"events": "github:jspm/nodelibs-events@^0.2.0-alpha",
"fs": "github:jspm/nodelibs-fs@^0.2.0-alpha",
"http": "github:jspm/nodelibs-http@^0.2.0-alpha",
"module": "npm:jspm-nodelibs-module@^0.2.0",
"os": "github:jspm/nodelibs-os@^0.2.0-alpha",
"path": "github:jspm/nodelibs-path@^0.2.0-alpha",
"process": "github:jspm/nodelibs-process@^0.2.0-alpha",
"stream": "github:jspm/nodelibs-stream@^0.2.0-alpha",
"string_decoder": "github:jspm/nodelibs-string_decoder@^0.2.0-alpha",
"tty": "npm:jspm-nodelibs-tty@^0.2.0",
"url": "github:jspm/nodelibs-url@^0.2.0-alpha",
"util": "github:jspm/nodelibs-util@^0.2.0-alpha",
"vm": "github:jspm/nodelibs-vm@^0.2.0-alpha"
},
"overrides": {
"npm:babel-runtime@5.8.38": {
"main": false,
"dependencies": {},
"optionalDependencies": {
"core-js": "^1.2.0"
}
},
"npm:browserify-zlib@0.1.4": {
"dependencies": {
"readable-stream": "^2.0.2",
"pako": "~0.2.0"
},
"map": {
"_stream_transform": "readable-stream/transform"
}
},
"npm:inherits@2.0.3": {
"ignore": [
"test.js"
]
},
"npm:lodash@4.16.4": {
"map": {
"buffer": "@empty",
"process": "@empty"
}
},
"npm:pbkdf2@3.0.12": {
"main": "browser.js"
},
"npm:safe-buffer@5.1.1": {
"browser": "index.js"
}
}
},
"dependencies": {
"js-yaml": "^3.9.0"
},
"devDependencies": {
"jspm": "^0.17.0-beta.28"
}
}

View File

@ -1,47 +0,0 @@
{
"ultimaker": {
"printer.baudrate": "115200",
"printer.dimensions.x": 200,
"printer.dimensions.y": 200,
"printer.dimensions.z": 200,
"printer.endcode": "M107 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;disable axes / steppers\nG90 ;absolute positioning\nM104 S{preheatTemp}\n{if heatedBed}M140 S{preheatBedTemp}\nM117 Done ;display message (20 characters to clear whole screen)",
"printer.filamentThickness": 2.85,
"printer.heatedbed": false,
"printer.heatup.bed.temperature": 70,
"printer.heatup.enabled": true,
"printer.heatup.temperature": 180,
"printer.nozzleDiameter": 0.4,
"printer.startcode": ";Generated with Doodle3D (default)\nM109 S{printingTemp} ;set target temperature \n{if heatedBed}M190 S{printingBedTemp} ;set target bed temperature\nG21 ;metric values\nG91 ;relative positioning\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E10 ;extrude 10mm of feed stock\nG92 E0 ;zero the extruded length again\nG92 E0 ;zero the extruded length again\nG1 F9000\nG90 ;absolute positioning\nM117 Printing Doodle... ;display message (20 characters to clear whole screen)",
"printer.type": "ultimaker"
},
"ultimaker2": {
"printer.baudrate": "115200",
"printer.dimensions.x": 223,
"printer.dimensions.y": 223,
"printer.dimensions.z": 205,
"printer.endcode": "M107 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+5.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 ;home the printer\nM84 ;disable axes / steppers\nG90 ;absolute positioning\nM104 S{preheatTemp}\n{if heatedBed}M140 S{preheatBedTemp}\nM117 Done ;display message (20 characters to clear whole screen)",
"printer.filamentThickness": 2.85,
"printer.heatedbed": true,
"printer.heatup.bed.temperature": 70,
"printer.heatup.enabled": true,
"printer.heatup.temperature": 180,
"printer.nozzleDiameter": 0.4,
"printer.startcode": ";Generated with Doodle3D (ultimaker2)\nM109 S{printingTemp} ;set target temperature \n{if heatedBed}M190 S{printingBedTemp} ;set target bed temperature\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nG28 ; home to endstops\nG1 Z15 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E10 ;extrude 10mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nM117 Printing Doodle... ;display message (20 characters to clear whole screen)",
"printer.type": "ultimaker2"
},
"ultimaker2go": {
"printer.baudrate": "115200",
"printer.dimensions.x": 120,
"printer.dimensions.y": 120,
"printer.dimensions.z": 115,
"printer.endcode": "M107 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+5.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 ;home the printer\nM84 ;disable axes / steppers\nG90 ;absolute positioning\nM104 S{preheatTemp}\n{if heatedBed}M140 S{preheatBedTemp}\nM117 Done ;display message (20 characters to clear whole screen)",
"printer.filamentThickness": 2.85,
"printer.heatedbed": false,
"printer.heatup.bed.temperature": 70,
"printer.heatup.enabled": true,
"printer.heatup.temperature": 180,
"printer.nozzleDiameter": 0.4,
"printer.startcode": ";Generated with Doodle3D (ultimaker2)\nM109 S{printingTemp} ;set target temperature \n{if heatedBed}M190 S{printingBedTemp} ;set target bed temperature\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nG28 ; home to endstops\nG1 Z15 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E10 ;extrude 10mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nM117 Printing Doodle... ;display message (20 characters to clear whole screen)",
"printer.type": "ultimaker2g0"
}
}

View File

@ -1,24 +0,0 @@
{
"printer.normalFlowRate": 1.0,
"printer.bottomFlowRate": 2.0,
"printer.bottomLayerSpeed": 35.0,
"printer.bottomThickness": 0.4,
"printer.fillSize": 5.0,
"printer.firstLayerSlow": true,
"printer.layerHeight": 0.2,
"printer.retraction.amount": 3.0,
"printer.retraction.enabled": true,
"printer.retraction.speed": 50,
"printer.retraction.minDistance": 5.0,
"printer.shellThickness": 0.4,
"printer.speed": 50.0,
"printer.temperature": 210.0,
"printer.topThickness": 0.8,
"printer.travelSpeed": 200.0,
"printer.support.accaptanceSize": 1.5,
"printer.support.distanceY": 0.4,
"printer.support.use": true,
"printer.support.gritSize": 6.0,
"printer.support.margin": 2.0,
"printer.support.plateSize": 4.0
}

15
simpleExample/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE>
<html>
<head>
<title>Doodle3D Slicer - Simple example</title>
<script type="text/javascript" src="../jspm_packages/system.js"></script>
<script type="text/javascript" src="../jspm.config.js"></script>
<script type="text/javascript">
System.import('simpleExample/index.js');
</script>
</head>
<body>
<div id="gcode"></div>
</body>
</html>

16
simpleExample/index.js Normal file
View File

@ -0,0 +1,16 @@
import 'three.js';
import * as SLICER from 'src/index.js';
const settings = new SLICER.Settings({
...SLICER.printerSettings['ultimaker2go'],
...SLICER.userSettings.low
});
const geometry = new THREE.TorusGeometry(20, 10, 30, 30).clone();
const slicer = new SLICER.Slicer();
slicer.setGeometry(geometry);
slicer.slice(settings, false).then(gcode => {
document.getElementById('gcode').innerHTML = gcode.replace(/(?:\r\n|\r|\n)/g, '<br />');
});

View File

@ -1,182 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Doedel Drie Dee || Slice Test</title>
<!--<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>-->
<script src="library/jquery.js"></script>
<script src="library/three.js"></script>
<script src="library/stl_loader.js"></script>
<script src="library/clipper.js"></script>
<script src="src/utils.js"></script>
<script src="src/box.js"></script>
<script src="src/printer.js"></script>
<script src="src/paths.js"></script>
<script src="src/gcode.js"></script>
<script src="src/slicer.js"></script>
<style>
canvas {border: 1px solid black;}
</style>
</head>
<body>
<canvas id="3d-preview" height="400" width="400"></canvas>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
var USER_SETTINGS, PRINTER_SETTINGS, doodleBox, gcode;
function init () {
"use strict";
var scene = createScene();
var localIp = location.hash.substring(1);
//doodleBox = new D3D.Box(localIp);
var printer = new D3D.Printer().updateConfig(USER_SETTINGS).updateConfig(PRINTER_SETTINGS["ultimaker"]);
var loader = new THREE.STLLoader();
loader.load('models/support_test.stl', function (geometry) {
//var geometry = new THREE.BoxGeometry(10, 10, 10, 1, 1, 1);
//var geometry = new THREE.SphereGeometry(10, 20, 10);
//var geometry = new THREE.TorusGeometry(20, 10, 30, 30);
/*
var geometry = (function () {
"use strict";
var circle = new THREE.Shape();
circle.absarc(0, 0, 10, 0, Math.PI*2, false);
var hole = new THREE.Path();
hole.absarc(0, 0, 5, 0, Math.PI*2, true );
circle.holes.push(hole);
var matrix = new THREE.Matrix4();
matrix.makeRotationX(Math.PI*1.5);
var geometry = new THREE.ExtrudeGeometry(circle, {
amount: 10,
bevelEnabled: false,
steps: 1
});
geometry.applyMatrix(matrix);
return geometry;
})();
*/
var material = new THREE.MeshPhongMaterial({color: 0x00ff00, wireframe: false});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -Math.PI/2;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 1;
mesh.position.y = -0.1;
mesh.position.x = 60;
mesh.position.z = 60;
mesh.updateMatrix();
scene.add(mesh);
var slicer = new D3D.Slicer().setMesh(mesh.geometry, mesh.matrix);
//var canvas = document.getElementById("canvas");
//var context = canvas.getContext("2d");
//var img = slicer.drawPaths(printer, 0, 1);
//context.drawImage(img, 0, 0);
gcode = slicer.getGCode(printer);
});
}
function createScene () {
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer({canvas: document.getElementById("3d-preview"), antialias: true});
renderer.setClearColor(0xffffff, 1);
var camera = new THREE.PerspectiveCamera(75, renderer.domElement.width/renderer.domElement.height, 1, 10000);
scene.add(camera);
var light = new THREE.AmbientLight(0x404040);
scene.add(light);
var directionalLight = new THREE.PointLight(0xffffff, 0.5);
camera.add(directionalLight);
applyMouseControls(renderer, camera, new THREE.Vector3(100, 0, 100), 1000);
function applyMouseControls (renderer, camera, center, maxDistance) {
var distance = 20;
var rotX = 0;
var rotY = 0;
var moveCamera = false;
function updateCamera () {
camera.position.set(
Math.cos(rotY)*Math.sin(rotX)*distance,
Math.sin(rotY)*distance,
Math.cos(rotY)*Math.cos(rotX)*distance
).add(center);
camera.lookAt(center);
}
$(renderer.domElement).on("mousedown", function (e) {
moveCamera = true;
}).on("wheel", function (e) {
var event = e.originalEvent;
event.preventDefault();
distance = THREE.Math.clamp(distance - event.wheelDelta, 1, maxDistance);
updateCamera();
});
$(window).on("mouseup", function (e) {
moveCamera = false;
}).on("mousemove", function (e) {
var event = e.originalEvent;
if (moveCamera === true) {
rotX = (rotX - event.webkitMovementX/100) % (2*Math.PI);
rotY = THREE.Math.clamp(rotY + event.webkitMovementY/100, -Math.PI/2, Math.PI/2);
updateCamera();
}
});
updateCamera();
}
(function animate () {
requestAnimationFrame(animate);
renderer.render(scene, camera);
})();
return scene;
}
//loadSettings;
(function () {
var loadedItems = 0;
function loaded () {
loadedItems ++;
if (loadedItems === 2) {
init();
}
}
loadSettings("settings/user_settings.json", function (data) {
USER_SETTINGS = data;
loaded();
});
loadSettings("settings/printer_settings.json", function (data) {
PRINTER_SETTINGS = data;
loaded();
});
})();
</script>
</body>
</html>

182
src/GCode.js Normal file
View File

@ -0,0 +1,182 @@
import * as THREE from 'three';
const MOVE = 'G';
const M_COMMAND = 'M';
const FAN_SPEED = 'S';
const SPEED = 'F';
const EXTRUDER = 'E';
const POSITION_X = 'X';
const POSITION_Y = 'Y';
const POSITION_Z = 'Z';
export default class {
constructor(settings) {
this._gcode = '';
this._currentValues = {};
this._settings = settings;
this._nozzlePosition = new THREE.Vector2(0, 0);
this._extruder = 0.0;
this._isRetracted = false;
this._isFanOn = false;
this.bottom = true;
}
_addGCode(command) {
let str = '';
let first = true;
for (const action in command) {
const value = command[action];
const currentValue = this._currentValues[action];
if (first) {
str = action + value;
first = false;
} else if (currentValue !== value) {
str += ` ${action}${value}`;
this._currentValues[action] = value;
}
}
this._gcode += `${str}\n`;
}
turnFanOn(fanSpeed) {
this._isFanOn = true;
const gcode = { [M_COMMAND]: 106 }
if (typeof fanSpeed !== 'undefined') gcode[FAN_SPEED] = fanSpeed;
this._addGCode(gcode);
return this;
}
turnFanOff() {
this._isFanOn = false;
this._addGCode({ [M_COMMAND]: 107 });
return this;
}
moveTo(x, y, layer) {
const {
layerHeight,
travelSpeed
} = this._settings;
const z = layer * layerHeight + 0.2;
const speed = travelSpeed * 60;
this._addGCode({
[MOVE]: 0,
[POSITION_X]: x.toFixed(3),
[POSITION_Y]: y.toFixed(3),
[POSITION_Z]: z.toFixed(3),
[SPEED]: speed.toFixed(3)
});
this._nozzlePosition.set(x, y);
return this;
}
lineTo(x, y, layer, type) {
const newNozzlePosition = new THREE.Vector2(x, y);
const {
layerHeight,
nozzleDiameter,
filamentThickness,
travelSpeed
} = this._settings;
const profile = this._settings[(this.bottom ? 'bottom' : type)];
let {
speed,
flowRate
} = profile;
speed *= 60;
const z = layer * layerHeight + 0.2;
const lineLength = this._nozzlePosition.distanceTo(newNozzlePosition);
const filamentSurfaceArea = Math.pow((filamentThickness / 2), 2) * Math.PI;
this._extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate;
this._addGCode({
[MOVE]: 1,
[POSITION_X]: x.toFixed(3),
[POSITION_Y]: y.toFixed(3),
[POSITION_Z]: z.toFixed(3),
[SPEED]: speed.toFixed(3),
[EXTRUDER]: this._extruder.toFixed(3)
});
this._nozzlePosition.copy(newNozzlePosition);
return this;
}
unRetract() {
const {
retraction: {
enabled: retractionEnabled,
minDistance: retractionMinDistance,
speed: retractionSpeed
}
} = this._settings;
if (this._isRetracted && retractionEnabled) {
this._isRetracted = false;
const speed = retractionSpeed * 60;
if (this._extruder > retractionMinDistance) {
this._addGCode({
[MOVE]: 0,
[EXTRUDER]: this._extruder.toFixed(3),
[SPEED]: speed.toFixed(3)
});
}
}
return this;
}
retract() {
const {
retraction: {
amount: retractionAmount,
enabled: retractionEnabled,
minDistance: retractionMinDistance,
speed: retractionSpeed
}
} = this._settings;
if (!this._isRetracted && retractionEnabled) {
this._isRetracted = true;
const speed = retractionSpeed * 60;
if (this._extruder > retractionMinDistance && retractionEnabled) {
this._addGCode({
[MOVE]: 0,
[EXTRUDER]: (this._extruder - retractionAmount).toFixed(3),
[SPEED]: speed.toFixed(3)
});
}
}
return this;
}
getGCode() {
return this._gcode;
}
}

24
src/Slice.js Normal file
View File

@ -0,0 +1,24 @@
import Shape from 'Doodle3D/clipper-js';
export default class {
constructor() {
this.parts = [];
}
getOutline() {
return this.parts.reduce((shape, part) => {
if (part.outerLine) shape.join(part.outerLine);
return shape;
}, new Shape([], true));
}
add(shape) {
const part = { shape };
if (shape.closed) {
part.innerLines = [];
part.outerLine = new Shape([], true);
part.fill = new Shape([], false);
}
this.parts.push(part);
}
}

63
src/Slicer.js Normal file
View File

@ -0,0 +1,63 @@
import * as THREE from 'three';
import slice from './sliceActions/slice.js';
import SlicerWorker from './slicerWorker.js!worker';
import ProgressPromise from 'progress-promise';
export default class {
setMesh(mesh) {
mesh.updateMatrix();
this.setGeometry(mesh.geometry, mesh.matrix);
return this;
}
setGeometry(geometry, matrix) {
if (geometry.isBufferGeometry) {
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
} else if (geometry.isGeometry) {
geometry = geometry.clone();
} else {
throw new Error('Geometry is not an instance of BufferGeometry or Geometry');
}
if (matrix) {
geometry.applyMatrix(matrix);
}
this.geometry = geometry;
return this;
}
sliceSync(settings, onprogress) {
return slice(this.geometry, settings, onprogress);
}
slice(settings) {
const slicerWorker = new SlicerWorker();
const geometry = this.geometry.toJSON();
return new ProgressPromise((resolve, reject, progress) => {
slicerWorker.onerror = reject;
slicerWorker.addEventListener('message', (event) => {
const { message, data } = event.data;
switch (message) {
case 'SLICE': {
slicerWorker.terminate();
resolve(data.gcode);
break;
}
case 'PROGRESS': {
progress(data);
break;
}
}
});
slicerWorker.postMessage({
message: 'SLICE',
data: { geometry, settings }
});
});
}
}

View File

@ -1,387 +0,0 @@
/******************************************************
*
* Box
* Representation of de Doodle3DBox
* Handles all communication with the doodle box
* JavaScript shell for api communication
* Check http://www.doodle3d.com/help/api-documentation
*
******************************************************/
//TODO
//Als meerdere clients met box zouden verbinden zal de api te veel requests krijgen waardoor hij crasht
//implimentatie van het veranderen van onder andere naam, netwerkverbinding etc
D3D.Box = function (localIp) {
"use strict";
var scope = this;
this.batchSize = 512;
this.maxBufferedLines = 4096;
this.localIp = localIp;
this.api = "http://" + localIp + "/d3dapi/";
this.config = {};
this.status = {};
this.printBatches = [];
this.currentBatch = 0;
this.loaded = false;
this.getConfigAll(function (data) {
scope.updateConfig(data);
scope.update();
scope.loaded = true;
if (scope.onload !== undefined) {
scope.onload();
}
});
};
D3D.Box.prototype.updateConfig = function (config) {
"use strict";
for (var i in config) {
this.config[i] = config[i];
}
return this;
};
D3D.Box.prototype.update = function () {
"use strict";
var scope = this;
//TODO
//Code is zo op gezet dat maar api call te gelijk is
//Bij error wordt gelijk zelfde data opnieuw gestuurd
//Als DoodleBox ontkoppeld wordt komt er een error in de loop waardoor pagina breekt en ververst moet worden
if (this.printBatches.length > 0 && (this.status["buffered_lines"] + this.batchSize) <= this.maxBufferedLines) {
//if (this.printBatches.length > 0 ) {
this.printBatch();
}
else {
setTimeout(function () {
scope.updateState();
}, 1000);
}
};
D3D.Box.prototype.updateState = function () {
//que api calls so they don't overload the d3d box
"use strict";
var scope = this;
this.getInfoStatus(function (data) {
scope.status = data;
if (scope.onupdate !== undefined) {
scope.onupdate(data);
}
scope.update();
});
};
D3D.Box.prototype.print = function (gcode) {
"use strict";
this.currentBatch = 0;
//clone gcode to remove array links
gcode = gcode.clone();
//gcode split in batches
while (gcode.length > 0) {
var gcodeBatch = gcode.splice(0, Math.min(this.batchSize, gcode.length));
this.printBatches.push(gcodeBatch);
}
return this;
};
D3D.Box.prototype.printBatch = function () {
"use strict";
var scope = this;
var gcode = this.printBatches.shift();
this.setPrinterPrint({
"start": ((this.currentBatch === 0) ? true : false),
"first": ((this.currentBatch === 0) ? true : false),
"gcode": gcode.join("\n"),
"last": ((this.printBatches.length === 0) ? true : false) //only for debug purposes
}, function (data) {
console.log("batch sent: " + scope.currentBatch, data);
if (scope.printBatches.length > 0) {
//sent new batch
scope.currentBatch ++;
}
else {
//finish sending
}
scope.updateState();
});
};
D3D.Box.prototype.stopPrint = function (printer) {
"use strict";
this.printBatches = [];
this.currentBatch = 0;
this.setPrinterStop({
"gcode": printer.getEndCode().join("\n")
}, function (data) {
console.log("Printer stop command sent");
});
return this;
};
//COMMUNICATION SHELL
//see http://www.doodle3d.com/help/api-documentation
D3D.Box.prototype.getConfig = function (keys, callback) {
"use strict";
getAPI(this.api + "config/?" + keys.join("=&") + "=", callback);
return this;
};
D3D.Box.prototype.getConfigAll = function (callback) {
"use strict";
getAPI(this.api + "config/all", callback);
return this;
};
D3D.Box.prototype.setConfig = function (data, callback) {
"use strict";
var scope = this;
sendAPI(this.api + "config", data, function (response) {
for (var i in response.validation) {
if (response.validation[i] === "ok") {
scope[i] = data[i];
}
}
if (callback !== undefined) {
callback(response);
}
});
return this;
};
D3D.Box.prototype.getInfo = function (callback) {
"use strict";
getAPI(this.api + "info", callback);
return this;
};
D3D.Box.prototype.getInfoStatus = function (callback) {
"use strict";
getAPI(this.api + "info/status", callback);
return this;
};
D3D.Box.prototype.downloadInfoLogFiles = function () {
//works in google chrome... not tested in other browsers
//some browsers may redirect using this code
"use strict";
window.location = this.api + "info/logfiles";
};
D3D.Box.prototype.getInfoAcces = function (callback) {
"use strict";
getAPI(this.api + "info/access", callback);
return this;
};
D3D.Box.prototype.getNetworkScan = function (callback) {
"use strict";
getAPI(this.api + "network/scan", callback);
return this;
};
D3D.Box.prototype.getNetworkKnown = function (callback) {
"use strict";
getAPI(this.api + "network/known", callback);
return this;
};
D3D.Box.prototype.getNetworkStatus = function (callback) {
"use strict";
getAPI(this.api + "network/status", callback);
return this;
};
D3D.Box.prototype.setNetworkAssosiate = function (data, callback) {
"use strict";
sendAPI(this.api + "network/associate", data, callback);
return this;
};
D3D.Box.prototype.setNetworkDisassosiate = function (callback) {
//not tested
"use strict";
sendAPI(this.api + "network/disassociate", {}, callback);
return this;
};
D3D.Box.prototype.setNetworkOpenAP = function (callback) {
//not tested
"use strict";
sendAPI(this.api + "network/openap", {}, callback);
return this;
};
D3D.Box.prototype.setNetworkRemove = function (ssid, callback) {
"use strict";
sendAPI(this.api + "network/remove", {
"ssid": ssid
}, callback);
return this;
};
D3D.Box.prototype.getNetworkSignin = function (callback) {
"use strict";
getAPI(this.api + "network/signin", callback);
return this;
};
D3D.Box.prototype.getNetworkAlive = function (callback) {
"use strict";
getAPI(this.api + "network/alive", callback);
return this;
};
D3D.Box.prototype.getPrinterTemperature = function (callback) {
"use strict";
getAPI(this.api + "printer/temperature", callback);
return this;
};
D3D.Box.prototype.getPrinterProgress = function (callback) {
"use strict";
getAPI(this.api + "printer/progress", callback);
return this;
};
D3D.Box.prototype.getPrinterState = function (callback) {
"use strict";
getAPI(this.api + "printer/state", callback);
return this;
};
D3D.Box.prototype.getPrinterListAll = function (callback) {
"use strict";
getAPI(this.api + "printer/listall", callback);
return this;
};
D3D.Box.prototype.setPrinterHeatup = function (callback) {
"use strict";
sendAPI(this.api + "printer/heatup", {}, callback);
return this;
};
D3D.Box.prototype.setPrinterPrint = function (data, callback) {
"use strict";
sendAPI(this.api + "printer/print", data, callback);
return this;
};
D3D.Box.prototype.setPrinterStop = function (data, callback) {
"use strict";
sendAPI(this.api + "printer/stop", data, callback);
return this;
};
D3D.Box.prototype.getSketch = function (id, callback) {
"use strict";
getAPI(this.api + "sketch/?id=" + id, callback);
return this;
};
D3D.Box.prototype.setSketch = function (data, callback) {
"use strict";
sendAPI(this.api + "sketch", {
"data": data
}, callback);
return this;
};
D3D.Box.prototype.getSketchStatus = function (callback) {
"use strict";
getAPI(this.api + "sketch/status", callback);
return this;
};
D3D.Box.prototype.setSketchClear = function (callback) {
"use strict";
sendAPI(this.api + "sketch/clear", callback);
return this;
};
D3D.Box.prototype.getSystemVersions = function (callback) {
"use strict";
getAPI(this.api + "system/fwversions", callback);
return this;
};
D3D.Box.prototype.getUpdateStatus = function (callback) {
"use strict";
getAPI(this.api + "update/status", callback);
return this;
};
D3D.Box.prototype.setUpdateDownload = function (callback) {
//not tested
"use strict";
sendAPI(this.api + "update/download", {}, callback);
return this;
};
D3D.Box.prototype.setUpdateInstall = function (callback) {
//not tested
"use strict";
sendAPI(this.api + "update/install", {}, callback);
return this;
};
D3D.Box.prototype.setUpdateClear = function (callback) {
//not tested
"use strict";
sendAPI(this.api + "update/clear", {}, callback);
return this;
};

2
src/constants.js Normal file
View File

@ -0,0 +1,2 @@
export const CLEAN_DELTA = 0.05;
export const PRECISION = 0.01;

View File

@ -1,184 +0,0 @@
/******************************************************
*
* GCode
*
* Manages the gcode
* Also handles different flavours of gcode
* TODO
* calculate extrusion length and total time
*
******************************************************/
D3D.GCode = function () {
"use strict";
this.gcode = [];
this.current = {};
this.extruder = 0.0;
this.bottom = true;
this.isRetracted = false;
this.isFanOn = false;
this.nozzlePosition = new THREE.Vector2(0, 0);
};
D3D.GCode.prototype.addGCode = function (command) {
"use strict";
var str = [];
for (var i in command) {
if (i === "G") {
str.push(i + command[i]);
}
else if (this.current[i] !== command[i]) {
str.push(i + command[i]);
this.current[i] = command[i];
}
}
str = str.join(" ");
if (str.length > 0) {
this.gcode.push(str);
}
};
D3D.GCode.prototype.setSettings = function (printer) {
"use strict";
this.settings = printer;
return this;
};
D3D.GCode.prototype.turnFanOn = function (fanSpeed) {
"use strict";
this.isFanOn = true;
var gcode = {
"M": 106
};
if (fanSpeed !== undefined) {
gcode["S"] = fanSpeed;
}
this.addGCode(gcode);
return this;
};
D3D.GCode.prototype.turnFanOff = function () {
"use strict";
this.isFanOn = false;
this.addGCode({
"M": 107
});
return this;
};
D3D.GCode.prototype.moveTo = function (extrude, x, y, layer) {
"use strict";
var layerHeight = this.settings.config["printer.layerHeight"];
var firstLayerSlow = this.settings.config["printer.firstLayerSlow"];
var normalSpeed = this.settings.config["printer.speed"];
var bottomSpeed = this.settings.config["printer.bottomLayerSpeed"];
var normalSpeed = this.settings.config["printer.speed"];
var bottomSpeed = this.settings.config["printer.bottomLayerSpeed"];
var nozzleDiameter = this.settings.config["printer.nozzleDiameter"];
var filamentThickness = this.settings.config["printer.filamentThickness"];
var bottomFlowRate = this.settings.config["printer.bottomFlowRate"];
var normalFlowRate = this.settings.config["printer.normalFlowRate"];
var travelSpeed = this.settings.config["printer.travelSpeed"];
if (this.bottom) {
var speed = bottomSpeed * 60;
var flowRate = bottomFlowRate;
}
else {
var speed = normalSpeed * 60;
var flowRate = normalFlowRate;
}
var z = (layer + 1) * layerHeight;
if (extrude) {
var lineLength = this.nozzlePosition.distanceTo(new THREE.Vector2(x, y));
var filamentSurfaceArea = Math.pow((filamentThickness/2), 2) * Math.PI;
this.extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate;
this.addGCode({
"G": 1,
"X": x.toFixed(3), "Y": y.toFixed(3), "Z": z.toFixed(3),
"F": speed.toFixed(3),
"E": this.extruder.toFixed(3)
});
}
else {
var speed = travelSpeed * 60;
this.addGCode({
"G": 0,
"X": x.toFixed(3), "Y": y.toFixed(3), "Z": z.toFixed(3),
"F": speed.toFixed(3)
});
}
this.nozzlePosition = new THREE.Vector2(x, y);
return this;
};
D3D.GCode.prototype.unRetract = function () {
"use strict";
if (this.isRetracted) {
this.isRetracted = false;
var retractionAmount = this.settings.config["printer.retraction.amount"];
var retractionEnabled = this.settings.config["printer.retraction.enabled"];
var retractionMinDistance = this.settings.config["printer.retraction.minDistance"];
var retractionSpeed = this.settings.config["printer.retraction.speed"];
var speed = retractionSpeed * 60;
if (this.extruder > retractionMinDistance && retractionEnabled) {
this.addGCode({
"G": 0,
"E": this.extruder.toFixed(3),
"F": speed.toFixed(3)
});
}
return this;
}
};
D3D.GCode.prototype.retract = function () {
"use strict";
if (!this.isRetracted) {
this.isRetracted = true;
var retractionAmount = this.settings.config["printer.retraction.amount"];
var retractionEnabled = this.settings.config["printer.retraction.enabled"];
var retractionMinDistance = this.settings.config["printer.retraction.minDistance"];
var retractionSpeed = this.settings.config["printer.retraction.speed"];
var speed = retractionSpeed * 60;
if (this.extruder > retractionMinDistance && retractionEnabled) {
this.addGCode({
"G": 0,
"E": (this.extruder - retractionAmount).toFixed(3),
"F": speed.toFixed(3)
});
}
return this;
}
};
D3D.GCode.prototype.getGCode = function () {
"use strict";
return this.settings.getStartCode().concat(this.gcode, this.settings.getEndCode());
};

18
src/index.js Normal file
View File

@ -0,0 +1,18 @@
import Slicer from './Slicer.js';
import baseSettings from './settings/default.yml!text';
import printerSettings from './settings/printer.yml!text';
import materialSettings from './settings/material.yml!text';
import qualitySettings from './settings/quality.yml!text';
import yaml from 'js-yaml';
const defaultSettings = {
base: yaml.safeLoad(baseSettings),
printer: yaml.safeLoad(printerSettings),
material: yaml.safeLoad(materialSettings),
quality: yaml.safeLoad(qualitySettings)
};
export {
Slicer,
defaultSettings
};

View File

@ -1,242 +0,0 @@
/******************************************************
*
* Path
*
* Abstraction layer for annoying clipper js
* ! inherrits from Array !
*
******************************************************/
D3D.Paths = function (paths, closed) {
"use strict";
Array.call(this);
this.setPaths(paths || []);
this.closed = (closed !== undefined) ? closed : true;
};
D3D.Paths.prototype = Object.create(Array.prototype);
D3D.Paths.prototype.setPaths = function (paths) {
"use strict";
for (var i = 0; i < paths.length; i ++) {
var path = paths[i];
if (path.length > 0) {
this.push(path);
}
}
return this;
};
D3D.Paths.prototype.clip = function (path, type) {
"use strict";
var solution = new ClipperLib.Paths();
var clipper = new ClipperLib.Clipper();
clipper.AddPaths(this, ClipperLib.PolyType.ptSubject, this.closed);
clipper.AddPaths(path, ClipperLib.PolyType.ptClip, path.closed);
clipper.Execute(type, solution);
return new D3D.Paths(solution, this.closed);
};
D3D.Paths.prototype.union = function (path) {
"use strict";
return this.clip(path, ClipperLib.ClipType.ctUnion);
};
D3D.Paths.prototype.difference = function (path) {
"use strict";
return this.clip(path, ClipperLib.ClipType.ctDifference);
};
D3D.Paths.prototype.intersect = function (path) {
"use strict";
return this.clip(path, ClipperLib.ClipType.ctIntersection);
};
D3D.Paths.prototype.xor = function () {
"use strict";
return this.clip(path, ClipperLib.ClipType.ctXor);
};
D3D.Paths.prototype.offset = function (offset) {
"use strict";
var solution = new ClipperLib.Paths();
var co = new ClipperLib.ClipperOffset(1, 1);
co.AddPaths(this, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
co.Execute(solution, offset);
return new D3D.Paths(solution);
};
D3D.Paths.prototype.scaleUp = function (factor) {
"use strict";
var path = ClipperLib.JS.ScaleUpPaths(this, factor);
return this;
};
D3D.Paths.prototype.scaleDown = function (factor) {
"use strict";
var path = ClipperLib.JS.ScaleDownPaths(this, factor);
return this;
};
D3D.Paths.prototype.lastPoint = function () {
"use strict";
var lastPath = this[this.length - 1];
var lastPoint = this.closed ? lastPath[0] : lastPath[lastPath.length - 1];
return new THREE.Vector2(lastPoint.X, lastPoint.Y);
};
D3D.Paths.prototype.optimizePath = function (start) {
"use strict";
var optimizedPaths = new D3D.Paths([], this.closed);
var donePaths = [];
while (optimizedPaths.length !== this.length) {
var minLength = false;
var reverse;
var minPath;
var offset;
var pathIndex;
for (var i = 0; i < this.length; i ++) {
var path = this[i];
if (donePaths.indexOf(i) === -1) {
if (this.closed) {
for (var j = 0; j < path.length; j ++) {
var point = new THREE.Vector2(path[j].X, path[j].Y);
var length = point.sub(start).length();
if (minLength === false || length < minLength) {
minPath = path;
minLength = length;
offset = j;
pathIndex = i;
}
}
}
else {
var startPoint = new THREE.Vector2(path[0].X, path[0].Y);
var length = startPoint.sub(start).length();
if (minLength === false || length < minLength) {
minPath = path;
minLength = length;
reverse = false;
pathIndex = i;
}
var endPoint = new THREE.Vector2(path[path.length - 1].X, path[path.length - 1].Y);
var length = endPoint.sub(start).length();
if (length < minLength) {
minPath = path;
minLength = length;
reverse = true;
pathIndex = i;
}
}
}
}
if (this.closed) {
minPath = minPath.concat(minPath.splice(0, offset));
var point = minPath[0];
}
else {
if (reverse) {
minPath.reverse();
}
var point = minPath[minPath.length - 1];
}
donePaths.push(pathIndex);
start = new THREE.Vector2(point.X, point.Y);
optimizedPaths.push(minPath);
}
return optimizedPaths;
};
D3D.Paths.prototype.areas = function () {
"use strict";
var areas = [];
for (var i = 0; i < this.length; i ++) {
var shape = this[i];
var area = Math.abs(ClipperLib.Clipper.Area(shape));
areas.push(area);
}
return areas;
};
D3D.Paths.prototype.tresholdArea = function (minArea) {
//code not tested yet
"use strict";
for (var i = 0; i < this.length; i ++) {
var shape = this[i];
var area = ClipperLib.Clipper.Area(shape);
if (area < minArea) {
this.splice(i, 1);
i --;
}
}
return areas;
};
D3D.Paths.prototype.join = function (path) {
"use strict";
for (var i = 0; i < path.length; i ++) {
this.push(path[i]);
}
return this;
};
D3D.Paths.prototype.clone = function () {
"use strict";
return new D3D.Paths(ClipperLib.JS.Clone(this), this.closed);
};
D3D.Paths.prototype.bounds = function () {
"use strict";
return ClipperLib.Clipper.GetBounds(this);
};
D3D.Paths.prototype.boundSize = function () {
"use strict";
var bounds = this.bounds();
var width = bounds.right - bounds.left;
var height = bounds.top - bounds.bottom;
return width * height;
};
D3D.Paths.prototype.draw = function (context, color) {
"use strict";
context.strokeStyle = color;
for (var i = 0; i < this.length; i ++) {
var shape = this[i];
//var point = shape[0];
//context.fillText(i, point.X*2, point.Y*2);
context.beginPath();
var length = this.closed ? (shape.length + 1) : shape.length;
for (var j = 0; j < length; j ++) {
var point = shape[j % shape.length];
context.lineTo(point.X*2, point.Y*2);
}
context.stroke();
}
};

View File

@ -1,68 +0,0 @@
/******************************************************
*
* Printer
* Representation of the connected printer
*
******************************************************/
D3D.Printer = function () {
"use strict";
this.config = {};
};
D3D.Printer.prototype.updateConfig = function (config) {
"use strict";
for (var i in config) {
if (i.indexOf("printer") === 0) {
this.config[i] = config[i];
}
}
return this;
};
D3D.Printer.prototype.getStartCode = function () {
"use strict";
var gcode = this.config["printer.startcode"];
gcode = this.subsituteVariables(gcode);
return gcode.split("\n");
};
D3D.Printer.prototype.getEndCode = function () {
"use strict";
var gcode = this.config["printer.endcode"];
gcode = this.subsituteVariables(gcode);
return gcode.split("\n");
};
D3D.Printer.prototype.subsituteVariables = function (gcode) {
"use strict";
var temperature = this.config["printer.temperature"];
var bedTemperature = this.config["printer.bed.temperature"];
var preheatTemperature = this.config["printer.heatup.temperature"];
var preheatBedTemperature = this.config["printer.heatup.bed.temperature"];
var printerType = this.config["printer.type"];
var heatedbed = this.config["printer.heatedbed"];
switch (printerType) {
case "makerbot_replicator2": printerType = "r2"; break;
case "makerbot_replicator2x": printerType = "r2x"; break;
case "makerbot_thingomatic": printerType = "t6"; break;
case "makerbot_generic": printerType = "r2"; break;
case "_3Dison_plus": printerType = "r2"; break;
}
var heatedBedReplacement = heatedbed ? "" : ";";
gcode = gcode.replace(/{printingTemp}/gi, temperature);
gcode = gcode.replace(/{printingBedTemp}/gi, bedTemperature);
gcode = gcode.replace(/{preheatTemp}/gi, preheatTemperature);
gcode = gcode.replace(/{preheatBedTemp}/gi, preheatBedTemperature);
gcode = gcode.replace(/{printerType}/gi, printerType);
gcode = gcode.replace(/{if heatedBed}/gi, heatedBedReplacement);
return gcode;
};

51
src/settings/default.yml Normal file
View File

@ -0,0 +1,51 @@
dimensions:
x: 200
y: 200
z: 200
temperature: 210
bedTemperature: 70
# heatBedTemperature: 20
# heatTemperature: 20
# heatupEnabled: true
travelSpeed: 200.0
layerHeight: 0.15
heatedBed: false
nozzleDiameter: 0.4
filamentThickness: 2.85
retraction:
amount: 3.0
enabled: true
speed: 50.0
minDistance: 0.0
support:
acceptanceMargin: 1.5
distanceY: 0.4
enabled: false
gridSize: 6.0
margin: 2.0
plateSize: 4.0
flowRate: 0.8
speed: 40.0
outerLine:
flowRate: 1.0
speed: 40.0
innerLine:
flowRate: 1.0
speed: 50.0
fill:
flowRate: 1.0
speed: 50.0
overlap: 0.0
gridSize: 5.0
brim:
flowRate: 1.0
speed: 40.0
offset: 4.0
top:
thickness: 1.2
bottom:
flowRate: 1.2
speed: 40.0
thickness: 0.4
shell:
thickness: 0.4

View File

@ -0,0 +1,6 @@
pla:
title: PLA
temperature: 210
abs:
title: ABS
temperature: 240

171
src/settings/printer.yml Normal file
View File

@ -0,0 +1,171 @@
_3Dison_plus:
title: 3Dison plus
dimensions:
x: 227
y: 147
z: 150
bigbuilder3d:
title: Big Builder 3D
builder3d:
title: Builder 3D
bukobot:
title: Bukobot
cartesio:
title: Cartesio
colido_2_0_plus:
title: ColiDo 2.0 Plus
heatedBed: true
dimensions:
x: 230
y: 150
z: 140
colido_compact:
title: ColiDo Compact
dimensions:
x: 130
y: 130
z: 115
colido_diy:
title: ColiDo DIY
dimensions:
z: 170
colido_m2020:
title: ColiDo M2020
heatedBed: true
colido_x3045:
title: ColiDo X3045
heatedBed: true
dimensions:
x: 300
y: 300
z: 450
craftbot_plus:
title: CraftBot PLUS
heatedBed: true
filamentThickness: 1.75
dimensions:
x: 250
cyrus:
title: Cyrus
delta_rostockmax:
title: Delta RostockMax
dimensions:
x: 0
y: 0
deltamaker:
title: Deltamaker
dimensions:
x: 0
y: 0
doodle_dream:
title: Doodle Dream
filamentThickness: 1.75
dimensions:
x: 120
y: 120
z: 80
eventorbot:
title: EventorBot
felix:
title: Felix
gigabot:
title: Gigabot
kossel:
title: Kossel
dimensions:
x: 0
y: 0
leapfrog_creatr:
title: LeapFrog Creatr
lulzbot_aO_101:
title: LulzBot AO-101
lulzbot_taz_4:
title: LulzBot TAZ 4
dimensions:
x: 298
y: 275
z: 250
heatedBed: true
makerbot_generic:
title: Generic Makerbot Printer
makerbot_replicator2:
title: MakerBot Replicator2
makerbot_replicator2x:
title: MakerBot Replicator2x
heatedBed: true
makerbot_thingomatic:
title: MakerBot Thing-o-matic
makergear_m2:
title: MakerGear M2
makergear_prusa:
title: MakerGear Prusa
makibox:
title: Makibox
mamba3d:
title: Mamba3D
marlin_generic:
title: Generic Marlin Printer
minifactory:
title: miniFactory
dimensions:
x: 150
y: 150
z: 155
heatedBed: true
orca_0_3:
title: Orca 0.3
ord_bot_hadron:
title: ORD Bot Hadron
printrbot:
title: Printrbot
printxel_3d:
title: Printxel 3D
prusa_i3:
title: Prusa I3
prusa_iteration_2:
title: Prusa Iteration 2
rapman:
title: RapMan
renkforce_rf100:
title: Renkforce RF100
filamentThickness: 1.75
dimensions:
x: 100
y: 100
z: 100
reprappro_huxley:
title: RepRapPro Huxley
reprappro_mendel:
title: RepRapPro Mendel
rigidbot:
title: Rigidbot
robo_3d_printer:
title: RoBo 3D Printer
shapercube:
title: ShaperCube
tantillus:
title: Tantillus
ultimaker:
title: Ultimaker Original
ultimaker2:
title: Ultimaker 2
heatedBed: true
ultimaker2go:
title: Ultimaker 2 Go
dimensions:
x: 120
y: 120
z: 112
ultimaker_original_plus:
title: Ultimaker Original Plus
heatedBed: true
vision_3d_printer:
title: Vision 3D Printer
wanhao_duplicator4:
title: Wanhao Duplicator 4
filamentThickness: 1.75
heatedBed: true
dimensions:
x: 210
y: 140
z: 140

11
src/settings/quality.yml Normal file
View File

@ -0,0 +1,11 @@
low:
title: "Low"
layerHeight: .2
fill:
gridSize: 15.0
medium:
title: "Medium"
layerHeight: .15
high:
title: "High"
layerHeight: .1

View File

@ -0,0 +1,23 @@
import Shape from 'Doodle3D/clipper-js';
import { PRECISION } from '../constants.js';
const offsetOptions = {
jointType: 'jtRound',
miterLimit: 2.0,
roundPrecision: 0.25
};
export default function addBrim(slices, settings) {
let { brim: { offset: brimOffset } } = settings;
brimOffset /= PRECISION;
const [firstLayer] = slices;
firstLayer.brim = firstLayer.parts.reduce((brim, { shape }) => {
brim.join(shape.offset(brimOffset, {
...offsetOptions,
endType: shape.closed ? 'etClosedPolygon' : 'etOpenRound'
}));
return brim;
}, new Shape([], true)).simplify('pftNonZero');
}

View File

@ -0,0 +1,22 @@
import { PRECISION } from '../constants.js'
export default function applyPrecision(shapes) {
for (let i = 0; i < shapes.length; i ++) {
const { closedShapes, openShapes } = shapes[i];
scaleUpShape(closedShapes);
scaleUpShape(openShapes);
}
}
function scaleUpShape(shape) {
for (let i = 0; i < shape.length; i ++) {
const path = shape[i];
for (let i = 0; i < path.length; i ++) {
const point = path[i];
point.copy(point.divideScalar(PRECISION));
}
}
}

View File

@ -0,0 +1,43 @@
import * as THREE from 'three';
export default function calculateLayersIntersections(lines, settings) {
const { layerHeight, dimensions: { z: dimensionsZ } } = settings;
const numLayers = Math.floor(dimensionsZ / layerHeight);
const layerIntersectionIndexes = Array.from(Array(numLayers)).map(() => []);
const layerIntersectionPoints = Array.from(Array(numLayers)).map(() => []);
for (let lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
const line = lines[lineIndex].line;
if (line.isFlat) continue;
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);
for (let layerIndex = min; layerIndex <= max; layerIndex ++) {
if (layerIndex >= 0 && layerIndex < numLayers) {
layerIntersectionIndexes[layerIndex].push(lineIndex);
const y = layerIndex * layerHeight;
let x, z;
if (line.start.y === line.end.y) {
x = line.start.x;
z = line.start.z;
} else {
const alpha = (y - line.start.y) / (line.end.y - line.start.y);
const alpha1 = 1 - alpha;
x = line.end.x * alpha + line.start.x * alpha1;
z = line.end.z * alpha + line.start.z * alpha1;
}
layerIntersectionPoints[layerIndex][lineIndex] = new THREE.Vector2(z, x);
}
}
}
return { layerIntersectionIndexes, layerIntersectionPoints };
}

View File

@ -0,0 +1,48 @@
import * as THREE from 'three';
function addLine(geometry, lineLookup, lines, a, b, isFlat) {
const index = lines.length;
lineLookup[`${a}_${b}`] = index;
lines.push({
line: new THREE.Line3(geometry.vertices[a], geometry.vertices[b]),
connects: [],
normals: [],
isFlat
});
return index;
}
export default function createLines(geometry, settings) {
const lines = [];
const lineLookup = {};
for (let i = 0; i < geometry.faces.length; i ++) {
const face = geometry.faces[i];
const lookupA = lineLookup[`${face.b}_${face.a}`];
const lookupB = lineLookup[`${face.c}_${face.b}`];
const lookupC = lineLookup[`${face.a}_${face.c}`];
const isFlat = face.normal.y !== 1 && face.normal.y !== -1;
// only add unique lines
// returns index of said line
const lineIndexA = typeof lookupA !== 'undefined' ? lookupA : addLine(geometry, lineLookup, lines, face.a, face.b, isFlat);
const lineIndexB = typeof lookupB !== 'undefined' ? lookupB : addLine(geometry, lineLookup, lines, face.b, face.c, isFlat);
const lineIndexC = typeof lookupC !== 'undefined' ? lookupC : addLine(geometry, lineLookup, lines, face.c, face.a, isFlat);
// set connecting lines (based on face)
lines[lineIndexA].connects.push(lineIndexB, lineIndexC);
lines[lineIndexB].connects.push(lineIndexC, lineIndexA);
lines[lineIndexC].connects.push(lineIndexA, lineIndexB);
const normal = new THREE.Vector2(face.normal.z, face.normal.x).normalize();
lines[lineIndexA].normals.push(normal);
lines[lineIndexB].normals.push(normal);
lines[lineIndexC].normals.push(normal);
}
return lines;
}

View File

@ -0,0 +1,61 @@
export default function detectOpenClosed(lines) {
const pools = getPools(lines);
const openLines = lines.map(line => line.connects.length === 2);
for (let i = 0; i < pools.length; i ++) {
const pool = pools[i];
const isOpenGeometry = pool.some(lineIndex => openLines[lineIndex]);
for (let j = 0; j < pool.length; j ++) {
const lineIndex = pool[j];
const line = lines[lineIndex];
line.openGeometry = isOpenGeometry;
}
}
}
function findPool(pools, lines, lineIndex) {
const { connects } = lines[lineIndex];
for (let i = 0; i < pools.length; i ++) {
const pool = pools[i];
if (pool.find(lineIndex => connects.includes(lineIndex))) {
return pool;
}
}
// no pool found
// create new pool
const pool = [];
pools.push(pool);
return pool;
}
function getPools(lines) {
const pools = [];
for (let lineIndex = 0; lineIndex < lines.length; lineIndex ++) {
const pool = findPool(pools, lines, lineIndex);
pool.push(lineIndex);
}
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 { connects } = lines[poolA[k]];
if (poolB.find(lineIndex => connects.includes(lineIndex))) {
poolA.splice(poolA.length, 0, ...poolB);
poolB.splice(0, poolB.length);
}
}
}
}
return pools.filter(pool => pool.length > 0);
}

View File

@ -0,0 +1,79 @@
import { PRECISION } from '../constants.js'
import getFillTemplate from './getFillTemplate.js';
import Shape from 'Doodle3D/clipper-js';
export default function generateInfills(slices, settings) {
let {
layerHeight,
fill: { gridSize: fillGridSize },
bottom: { thickness: bottomThickness },
top: { thickness: topThickness },
nozzleDiameter,
fill: { overlap: infillOverlap }
} = settings;
fillGridSize /= PRECISION;
nozzleDiameter /= PRECISION;
infillOverlap /= PRECISION;
const bottomSkinCount = Math.ceil(bottomThickness/layerHeight);
const topSkinCount = Math.ceil(topThickness/layerHeight);
const nozzleRadius = nozzleDiameter / 2;
const hightemplateSize = Math.sqrt(2 * Math.pow(nozzleDiameter, 2));
for (let layer = 0; layer < slices.length; layer ++) {
const slice = slices[layer];
let surroundingLayer;
if (layer - bottomSkinCount >= 0 && layer + topSkinCount < slices.length) {
const downSkin = slices[layer - bottomSkinCount].getOutline();
const upSkin = slices[layer + topSkinCount].getOutline();
surroundingLayer = upSkin.intersect(downSkin);
}
for (let i = 0; i < slice.parts.length; i ++) {
const part = slice.parts[i];
if (!part.shape.closed) {
continue;
}
const outerLine = part.outerLine;
if (outerLine.paths.length > 0) {
const inset = (part.innerLines.length > 0) ? part.innerLines[part.innerLines.length - 1] : outerLine;
const fillArea = inset.offset(-nozzleRadius);
let lowFillArea;
let highFillArea;
if (surroundingLayer) {
highFillArea = fillArea.difference(surroundingLayer);
if (infillOverlap > 0) {
highFillArea = highFillArea.offset(infillOverlap);
}
highFillArea = highFillArea.intersect(fillArea);
lowFillArea = fillArea.difference(highFillArea);
} else {
highFillArea = fillArea;
}
if (lowFillArea && lowFillArea.paths.length > 0) {
const bounds = lowFillArea.shapeBounds();
const lowFillTemplate = getFillTemplate(bounds, fillGridSize, true, true);
part.fill.join(lowFillTemplate.intersect(lowFillArea));
}
if (highFillArea.paths.length > 0) {
const bounds = highFillArea.shapeBounds();
const even = (layer % 2 === 0);
const highFillTemplate = getFillTemplate(bounds, hightemplateSize, even, !even);
part.fill.join(highFillTemplate.intersect(highFillArea));
}
}
}
}
}

View File

@ -0,0 +1,45 @@
import { PRECISION } from '../constants.js'
const offsetOptions = {
jointType: 'jtSquare',
endType: 'etClosedPolygon',
miterLimit: 2.0,
roundPrecision: 0.25
};
export default function generateInnerLines(slices, settings) {
// need to scale up everything because of clipper rounding errors
let { layerHeight, nozzleDiameter, shell: { thickness: shellThickness } } = settings;
nozzleDiameter /= PRECISION;
shellThickness /= PRECISION;
const nozzleRadius = nozzleDiameter / 2;
const shells = Math.round(shellThickness / nozzleDiameter);
for (let layer = 0; layer < slices.length; layer ++) {
const slice = slices[layer];
for (let i = 0; i < slice.parts.length; i ++) {
const part = slice.parts[i];
if (!part.shape.closed) continue;
const outerLine = part.shape.offset(-nozzleRadius, offsetOptions);
if (outerLine.paths.length > 0) {
part.outerLine.join(outerLine);
for (let shell = 1; shell < shells; shell += 1) {
const offset = shell * nozzleDiameter;
const innerLine = outerLine.offset(-offset, offsetOptions);
if (innerLine.paths.length > 0) {
part.innerLines.push(innerLine);
} else {
break;
}
}
}
}
}
}

View File

@ -0,0 +1,76 @@
import getFillTemplate from './getFillTemplate.js';
import Shape from 'Doodle3D/clipper-js';
import { PRECISION } from '../constants.js';
export default function generateSupport(slices, settings) {
if (!settings.support.enabled) return;
let {
layerHeight,
support: {
gridSize: supportGridSize,
margin: AcceptanceMargin,
plateSize: plateSize,
distanceY: DistanceY
},
nozzleDiameter
} = settings;
supportGridSize /= PRECISION;
supportMargin /= PRECISION;
plateSize /= PRECISION;
nozzleDiameter /= PRECISION;
var supportDistanceLayers = Math.max(Math.ceil(supportDistanceY / layerHeight), 1);
var supportAreas = new Shape([], true);
for (var layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
var currentSlice = slices[layer];
if (supportAreas.length > 0) {
if (layer >= supportDistanceLayers) {
var sliceSkin = slices[layer - supportDistanceLayers].getOutline();
sliceSkin = sliceSkin;
var supportAreasSlimmed = supportAreas.difference(sliceSkin.offset(supportMargin));
if (supportAreasSlimmed.area() < 100.0) {
supportAreas = supportAreas.difference(sliceSkin);
}
else {
supportAreas = supportAreasSlimmed;
}
}
var supportTemplate = getFillTemplate(supportAreas.bounds(), supportGridSize, true, true);
var supportFill = supportTemplate.intersect(supportAreas);
if (supportFill.length === 0) {
currentSlice.support = supportAreas.clone();
}
else {
currentSlice.support = supportFill;
}
}
var supportSkin = slices[layer + supportDistanceLayers - 1].getOutline();
var slice = slices[layer + supportDistanceLayers];
for (var i = 0; i < slice.parts.length; i ++) {
var slicePart = slice.parts[i];
if (slicePart.intersect.closed) {
var outerLine = slicePart.outerLine;
}
else {
var outerLine = slicePart.intersect.offset(supportAcceptanceMargin);
}
var overlap = supportSkin.offset(supportAcceptanceMargin).intersect(outerLine);
var overhang = outerLine.difference(overlap);
if (overlap.length === 0 || overhang.length > 0) {
supportAreas = supportAreas.join(overhang);
}
}
}
}

View File

@ -0,0 +1,31 @@
import Shape from 'Doodle3D/clipper-js';
export default function getFillTemplate(bounds, size, even, uneven) {
const paths = [];
const left = Math.floor(bounds.left / size) * size;
const right = Math.ceil(bounds.right / size) * size;
const top = Math.floor(bounds.top / size) * size;
const bottom = Math.ceil(bounds.bottom / size) * size;
const width = right - left;
if (even) {
for (let y = top; y <= bottom + width; y += size) {
paths.push([
{ x: left, y },
{ x: right, y: y - width }
]);
}
}
if (uneven) {
for (let y = top - width; y <= bottom; y += size) {
paths.push([
{ x: left, y },
{ x: right, y: y + width }
]);
}
}
return new Shape(paths, false, true, true);
}

View File

@ -0,0 +1,121 @@
import * as THREE from 'three';
import Shape from 'Doodle3D/clipper-js';
export default function intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings) {
const layers = [];
for (let layer = 1; layer < layerIntersectionIndexes.length; layer ++) {
const intersectionIndexes = layerIntersectionIndexes[layer];
const intersectionPoints = layerIntersectionPoints[layer];
if (intersectionIndexes.length === 0) continue;
const closedShapes = [];
const openShapes = [];
for (let i = 0; i < intersectionIndexes.length; i ++) {
let index = intersectionIndexes[i];
if (typeof intersectionPoints[index] === 'undefined') continue;
const shape = [];
const firstPoints = [index];
const { openGeometry } = lines[index];
let isFirstPoint = true;
let openShape = true;
while (index !== -1) {
const intersection = intersectionPoints[index];
// uppercase X and Y because clipper vector
shape.push(intersection);
delete intersectionPoints[index];
const connects = lines[index].connects;
const faceNormals = lines[index].normals;
for (let i = 0; i < connects.length; i ++) {
index = connects[i];
if (firstPoints.includes(index) && shape.length > 2) {
openShape = false;
index = -1;
break;
}
// Check if index has an intersection or is already used
if (typeof intersectionPoints[index] !== 'undefined') {
const faceNormal = faceNormals[Math.floor(i / 2)];
const a = new THREE.Vector2(intersection.x, intersection.y);
const b = new THREE.Vector2(intersectionPoints[index].x, intersectionPoints[index].y);
// can't calculate normal between points if distance is smaller as 0.0001
if ((faceNormal.x === 0 && faceNormal.y === 0) || a.distanceTo(b) < 0.0001) {
if (isFirstPoint) {
firstPoints.push(index);
}
delete intersectionPoints[index];
connects.push(...lines[index].connects);
faceNormals.push(...lines[index].normals);
index = -1;
} else {
// make sure the path goes the right direction
// THREE.Vector2.normal is not yet implimented
// const normal = a.sub(b).normal().normalize();
const normal = a.sub(b);
normal.set(-normal.y, normal.x).normalize();
if (normal.dot(faceNormal) > 0) {
break;
} else {
index = -1;
}
}
} else {
index = -1;
}
}
isFirstPoint = false;
}
if (openShape) {
index = firstPoints[0];
while (index !== -1) {
if (!firstPoints.includes(index)) {
const intersection = intersectionPoints[index];
shape.unshift(intersection);
delete intersectionPoints[index];
}
const connects = lines[index].connects;
for (let i = 0; i < connects.length; i ++) {
index = connects[i];
if (typeof intersectionPoints[index] !== 'undefined') {
break;
} else {
index = -1;
}
}
}
}
if (openGeometry) {
if (!openShape) shape.push(shape[0].clone());
openShapes.push(shape);
} else {
closedShapes.push(shape);
}
}
layers.push({ closedShapes, openShapes });
}
return layers;
}

View File

@ -0,0 +1,150 @@
import * as THREE from 'three';
import Shape from 'Doodle3D/clipper-js';
export default function optimizePaths(slices, settings) {
const start = new THREE.Vector2(0, 0);
for (let layer = 0; layer < slices.length; layer ++) {
const slice = slices[layer];
if (typeof slice.brim !== 'undefined' && slice.brim.paths.length > 0) {
slice.brim = optimizeShape(slice.brim, start);
start.copy(slice.brim.lastPoint(true));
}
const parts = [];
while (slice.parts.length > 0) {
let closestDistance = Infinity;
let closestPart;
for (let i = 0; i < slice.parts.length; i ++) {
const part = slice.parts[i];
let bounds;
if (part.shape.closed) {
bounds = part.outerLine.shapeBounds();
} else {
bounds = part.shape.shapeBounds();
}
const top = bounds.top - start.y;
const bottom = start.y - bounds.bottom;
const left = bounds.left - start.x;
const right = start.x - bounds.right;
const distance = Math.max(top, bottom, left, right);
if (distance < closestDistance) {
closestDistance = distance;
closestPart = i;
}
}
const part = slice.parts.splice(closestPart, 1)[0];
parts.push(part);
if (part.shape.closed) {
if (part.outerLine.paths.length > 0) {
part.outerLine = optimizeShape(part.outerLine, start);
start.copy(part.outerLine.lastPoint(true));
}
for (let i = 0; i < part.innerLines.length; i ++) {
const innerLine = part.innerLines[i];
if (innerLine.paths.length > 0) {
part.innerLines[i] = optimizeShape(innerLine, start);
start.copy(part.innerLines[i].lastPoint(true));
}
}
if (part.fill.paths.length > 0) {
part.fill = optimizeShape(part.fill, start);
start.copy(part.fill.lastPoint(true));
}
} else {
part.shape = optimizeShape(part.shape, start);
start.copy(part.shape.lastPoint(true));
}
}
slice.parts = parts;
if (typeof slice.support !== 'undefined' && slice.support.length > 0) {
slice.support = optimizeShape(slice.support, start);
start.copy(slice.support.lastPoint(true));
}
}
}
function optimizeShape(shape, start) {
start = start.clone();
const inputPaths = shape.mapToLower();
const optimizedPaths = [];
const donePaths = [];
while (optimizedPaths.length !== inputPaths.length) {
let minLength = false;
let reverse;
let minPath;
let offset;
let pathIndex;
for (let i = 0; i < inputPaths.length; i ++) {
if (donePaths.includes(i)) continue;
const path = inputPaths[i];
if (shape.closed) {
for (let j = 0; j < path.length; j += 1) {
const point = new THREE.Vector2().copy(path[j]);
const length = point.sub(start).length();
if (minLength === false || length < minLength) {
minPath = path;
minLength = length;
offset = j;
pathIndex = i;
}
}
} else {
const startPoint = new THREE.Vector2().copy(path[0]);
const lengthToStart = startPoint.sub(start).length();
if (minLength === false || lengthToStart < minLength) {
minPath = path;
minLength = lengthToStart;
reverse = false;
pathIndex = i;
}
const endPoint = new THREE.Vector2().copy(path[path.length - 1]);
const lengthToEnd = endPoint.sub(start).length();
if (lengthToEnd < minLength) {
minPath = path;
minLength = lengthToEnd;
reverse = true;
pathIndex = i;
}
}
}
let point;
if (shape.closed) {
minPath = minPath.concat(minPath.splice(0, offset));
point = minPath[0];
} else {
if (reverse) {
minPath.reverse();
}
point = minPath[minPath.length - 1];
}
donePaths.push(pathIndex);
start.copy(point);
optimizedPaths.push(minPath);
}
return new Shape(optimizedPaths, shape.closed, true, false);
}

View File

@ -0,0 +1,31 @@
import { PRECISION } from '../constants.js';
const inversePrecision = 1 / PRECISION;
export default function removePrecision(slices) {
for (let layer = 0; layer < slices.length; layer ++) {
const slice = slices[layer];
for (let i = 0; i < slice.parts.length; i ++) {
const part = slice.parts[i];
if (part.shape.closed) {
part.outerLine.scaleDown(inversePrecision);
for (let i = 0; i < part.innerLines.length; i ++) {
const innerLine = part.innerLines[i];
innerLine.scaleDown(inversePrecision);
}
part.fill.scaleDown(inversePrecision);
} else {
part.shape.scaleDown(inversePrecision);
}
}
if (typeof slice.support !== 'undefined') {
slice.support.scaleDown(inversePrecision);
}
if (typeof slice.brim !== 'undefined') {
slice.brim.scaleDown(inversePrecision);
}
}
}

View File

@ -0,0 +1,45 @@
import Shape from 'Doodle3D/clipper-js';
import Slice from '../Slice.js';
import { CLEAN_DELTA, PRECISION } from '../constants.js';
const cleanDelta = CLEAN_DELTA / PRECISION;
export default function shapesToSlices(shapes, settings) {
const sliceLayers = [];
for (let layer = 0; layer < shapes.length; layer ++) {
let { closedShapes, openShapes } = shapes[layer];
closedShapes = new Shape(closedShapes, true, true, true, true)
.fixOrientation()
.simplify('pftNonZero')
.clean(cleanDelta)
.seperateShapes();
openShapes = new Shape(openShapes, false, true, true, true);
// .clean(cleanDelta);
// TODO
// Cleaning is actually wanted here but there is a bug in the clean function
// https://sourceforge.net/p/jsclipper/tickets/16/
const slice = new Slice();
for (let i = 0; i < closedShapes.length; i ++) {
const closedShape = closedShapes[i];
slice.add(closedShape);
// if (openShapes.path.length > 0) {
// openShapes = openShapes.difference(closedShape);
// }
}
if (openShapes.paths.length > 0) {
slice.add(openShapes);
}
sliceLayers.push(slice);
}
return sliceLayers;
}

65
src/sliceActions/slice.js Normal file
View File

@ -0,0 +1,65 @@
import calculateLayersIntersections from './calculateLayersIntersections.js';
import createLines from './createLines.js';
import generateInfills from './generateInfills.js';
import generateInnerLines from './generateInnerLines.js';
import generateSupport from './generateSupport.js';
import intersectionsToShapes from './intersectionsToShapes.js';
import addBrim from './addBrim.js';
import optimizePaths from './optimizePaths.js';
import shapesToSlices from './shapesToSlices.js';
import slicesToGCode from './slicesToGCode.js';
import detectOpenClosed from './detectOpenClosed.js';
import applyPrecision from './applyPrecision.js';
import removePrecision from './removePrecision.js';
export default function(geometry, settings, onProgress) {
const totalStages = 11;
let current = -1;
const updateProgress = (action) => {
current ++;
if (onProgress) onProgress({ done: current, total: totalStages, action });
};
geometry.computeFaceNormals();
// get unique lines from geometry;
updateProgress('Constructing unique lines from geometry');
const lines = createLines(geometry, settings);
updateProgress('Detecting open vs closed shapes');
const openClosed = detectOpenClosed(lines);
updateProgress('Calculating layer intersections');
const {
layerIntersectionIndexes,
layerIntersectionPoints
} = calculateLayersIntersections(lines, settings);
updateProgress('Constructing shapes from intersections');
const shapes = intersectionsToShapes(layerIntersectionIndexes, layerIntersectionPoints, lines, settings);
applyPrecision(shapes);
updateProgress('Constructing slices from shapes');
const slices = shapesToSlices(shapes, settings);
updateProgress('Generating inner lines');
generateInnerLines(slices, settings);
updateProgress('Generating infills');
generateInfills(slices, settings);
updateProgress('Generating support');
generateSupport(slices, settings);
updateProgress('Adding brim');
addBrim(slices, settings);
updateProgress('Optimizing paths');
optimizePaths(slices, settings);
removePrecision(slices);
updateProgress('Constructing gcode');
const gcode = slicesToGCode(slices, settings);
updateProgress('Finished');
return gcode;
}

View File

@ -0,0 +1,72 @@
import GCode from '../GCode.js';
export default function slicesToGCode(slices, settings) {
const gcode = new GCode(settings);
for (let layer = 0; layer < slices.length; layer ++) {
const slice = slices[layer];
if (layer === 1) {
gcode.turnFanOn();
gcode.bottom = false;
}
if (typeof slice.brim !== 'undefined') {
pathToGCode(gcode, slice.brim, true, true, layer, 'brim');
}
for (let i = 0; i < slice.parts.length; i ++) {
const part = slice.parts[i];
if (part.shape.closed) {
pathToGCode(gcode, part.outerLine, false, true, layer, 'outerLine');
for (let i = 0; i < part.innerLines.length; i ++) {
const innerLine = part.innerLines[i];
pathToGCode(gcode, innerLine, false, false, layer, 'innerLine');
}
pathToGCode(gcode, part.fill, true, false, layer, 'fill');
} else {
const retract = !(slice.parts.length === 1 && typeof slice.support === 'undefined');
pathToGCode(gcode, part.shape, retract, retract, layer, 'outerLine');
}
}
if (typeof slice.support !== 'undefined') {
pathToGCode(gcode, slice.support, true, true, layer, 'support');
}
}
return gcode.getGCode();
}
function pathToGCode(gcode, shape, retract, unRetract, layer, type) {
const { closed } = shape;
const paths = shape.mapToLower();
for (let i = 0; i < paths.length; i ++) {
const line = paths[i];
const length = closed ? (line.length + 1) : line.length;
for (let i = 0; i < length; i ++) {
const point = line[i % line.length];
if (i === 0) {
// TODO
// moveTo should impliment combing
gcode.moveTo(point.x, point.y, layer);
if (unRetract) {
gcode.unRetract();
}
} else {
gcode.lineTo(point.x, point.y, layer, type);
}
}
}
if (retract) {
gcode.retract();
}
}

View File

@ -1,589 +0,0 @@
/******************************************************
*
* Slicer
*
******************************************************/
D3D.Slicer = function () {
"use strict";
this.progress = {
totalFaces: 0,
currentFace: 0,
totalLayers: 0,
sliceLayer: 0,
dataLayer: 0,
gcodeLayer: 0
};
};
D3D.Slicer.prototype.setMesh = function (geometry, matrix) {
"use strict";
//convert buffergeometry to geometry;
if (geometry instanceof THREE.BufferGeometry) {
geometry = new THREE.Geometry().fromBufferGeometry(geometry);
}
//apply mesh matrix on geometry;
geometry.applyMatrix(matrix);
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeBoundingBox();
/*
for (var i = 0; i < geometry.faces.length; i ++) {
var face = geometry.faces[i];
var normal = face.normal;
if (normal.x === 0 && normal.y === 0 && normal.z === 0) {
geometry.faces.splice(i, 1);
i --;
}
}
*/
this.geometry = geometry;
//get unique lines from geometry;
this.createLines();
return this;
};
D3D.Slicer.prototype.updateProgress = function () {
'use strict';
var faces = this.progress.currentFace / (this.progress.totalFaces - 1);
var slice = this.progress.sliceLayer / (this.progress.totalLayers - 1);
var data = this.progress.dataLayer / (this.progress.totalLayers - 2);
var gcode = this.progress.gcodeLayer / (this.progress.totalLayers - 2);
this.progress.procent = (faces + slice + data + gcode) / 4;
if (this.onProgress !== undefined) {
this.onProgress(this.progress);
}
};
D3D.Slicer.prototype.createLines = function () {
"use strict";
this.progress.totalFaces = this.geometry.faces.length;
this.lines = [];
var lineLookup = {};
var self = this;
function addLine (a, b) {
var index = lineLookup[b + "_" + a];
if (index === undefined) {
index = self.lines.length;
lineLookup[a + "_" + b] = index;
self.lines.push({
line: new THREE.Line3(self.geometry.vertices[a], self.geometry.vertices[b]),
connects: [],
normals: []
});
}
return index;
}
for (var i = 0; i < this.geometry.faces.length; i ++) {
var face = this.geometry.faces[i];
if (face.normal.y !== 1 && face.normal.y !== -1) {
var normal = new THREE.Vector2().set(face.normal.z, face.normal.x).normalize();
//check for only adding unique lines
//returns index of said line
var a = addLine(face.a, face.b);
var b = addLine(face.b, face.c);
var c = addLine(face.c, face.a);
//set connecting lines (based on face)
this.lines[a].connects.push(b, c);
this.lines[b].connects.push(c, a);
this.lines[c].connects.push(a, b);
this.lines[a].normals.push(normal);
this.lines[b].normals.push(normal);
this.lines[c].normals.push(normal);
}
this.progress.currentFace = i;
this.updateProgress();
}
};
D3D.Slicer.prototype.slice = function (layerHeight, height) {
"use strict";
var numLayers = height / layerHeight;
var layersIntersections = [];
for (var lineIndex = 0; lineIndex < this.lines.length; lineIndex ++) {
var line = this.lines[lineIndex].line;
var min = Math.ceil(Math.min(line.start.y, line.end.y) / layerHeight);
var max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight);
for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
if (layerIndex >= 0 && layerIndex < numLayers) {
if (layersIntersections[layerIndex] === undefined) {
layersIntersections[layerIndex] = [];
}
layersIntersections[layerIndex].push(lineIndex);
}
}
}
var slices = [];
//still error in first layer, so remove first layer & last layer
//see https://github.com/Doodle3D/Doodle3D-Slicer/issues/1
for (var layer = 0; layer < layersIntersections.length; layer ++) {
var layerIntersections = layersIntersections[layer];
var y = layer * layerHeight;
var intersections = [];
var log = [];
for (var i = 0; i < layerIntersections.length; i ++) {
var index = layerIntersections[i];
var line = this.lines[index].line;
if (line.start.y === line.end.y) {
var x = line.start.x;
var z = line.start.z;
}
else {
var alpha = (y - line.start.y) / (line.end.y - line.start.y);
var x = line.end.x * alpha + line.start.x * (1 - alpha);
var z = line.end.z * alpha + line.start.z * (1 - alpha);
}
intersections[index] = new THREE.Vector2(z, x);
log.push({x: z, y: x, index: index, connects: this.lines[index].connects});
}
var done = [];
var slice = [];
for (var i = 0; i < layerIntersections.length; i ++) {
var index = layerIntersections[i];
if (done.indexOf(index) === -1) {
var shape = [];
while (index !== -1) {
var intersection = intersections[index];
shape.push({X: intersection.x, Y: intersection.y});
var connects = this.lines[index].connects;
var faceNormals = this.lines[index].normals;
for (var j = 0; j < connects.length; j ++) {
index = connects[j];
if (intersections[index] !== undefined && done.indexOf(index) === -1) {
done.push(index);
var a = new THREE.Vector2(intersection.x, intersection.y);
var b = intersections[index];
if (a.distanceTo(b) === 0) {
connects = connects.concat(this.lines[index].connects);
faceNormals = faceNormals.concat(this.lines[index].normals);
index = -1;
}
else {
var normal = a.sub(b).normal().normalize();
var faceNormal = faceNormals[Math.floor(j/2)];
if (normal.dot(faceNormal) >= 0) {
//if (true) {
break;
}
else {
index = -1;
}
}
}
else {
index = -1;
}
}
}
/*
for (var i = 0; i < shape.length; i ++) {
var point = shape[i];
var previousPoint = shape[(i + shape.length - 1) % shape.length];
var nextPoint = shape[(i + 1) % shape.length];
var point = new THREE.Vector2(point.X, point.Y);
var previousPoint = new THREE.Vector2(previousPoint.X, previousPoint.Y);
var nextPoint = new THREE.Vector2(nextPoint.X, nextPoint.Y);
//var lineLength = nextPoint.sub(previousPoint).length();
var normal = nextPoint.sub(previousPoint).normal().normalize();
var distance = Math.abs(normal.dot(point.sub(previousPoint)));
//something better for offset check
if (distance <= 0.01) {
shape.splice(i, 1);
i --;
}
}
*/
//think this check is not nescesary, always higher as 0
if (shape.length > 0) {
slice.push(new D3D.Paths([shape], true));
}
}
}
var layerParts = [];
for (var i = 0; i < slice.length; i ++) {
var layerPart1 = slice[i];
var merge = false;
for (var j = 0; j < layerParts.length; j ++) {
var layerPart2 = layerParts[j];
if (layerPart2.intersect(layerPart1).length > 0) {
layerPart2.join(layerPart1);
merge = true;
break;
}
}
if (!merge) {
layerParts.push(layerPart1);
}
}
//stop when ther are no intersects
if (layerParts.length > 0) {
slices.push(layerParts);
}
else {
break;
}
this.progress.sliceLayer = layer;
this.updateProgress();
}
return slices;
};
D3D.Slicer.prototype.slicesToData = function (slices, printer) {
"use strict";
var scale = 100;
var layerHeight = printer.config["printer.layerHeight"];
var nozzleDiameter = printer.config["printer.nozzleDiameter"] * scale;
var shellThickness = printer.config["printer.shellThickness"] * scale;
var fillSize = printer.config["printer.fillSize"] * scale;
var brimOffset = printer.config["printer.brimOffset"] * scale;
var bottomThickness = printer.config["printer.bottomThickness"];
var topThickness = printer.config["printer.topThickness"];
var useSupport = printer.config["printer.support.use"];
var supportGritSize = printer.config["printer.support.gritSize"] * scale;
var supportAccaptanceSize = printer.config["printer.support.accaptanceSize"] * scale;
var supportMargin = printer.config["printer.support.margin"] * scale;
var plateSize = printer.config["printer.support.plateSize"] * scale;
var supportDistanceY = printer.config["printer.support.distanceY"];
var supportDistanceLayers = Math.ceil(supportDistanceY / layerHeight);
var bottomSkinCount = Math.ceil(bottomThickness/layerHeight);
var topSkinCount = Math.ceil(topThickness/layerHeight);
var nozzleRadius = nozzleDiameter / 2;
var lowFillTemplate = this.getFillTemplate({
left: this.geometry.boundingBox.min.z * scale,
top: this.geometry.boundingBox.min.x * scale,
right: this.geometry.boundingBox.max.z * scale,
bottom: this.geometry.boundingBox.max.x * scale
}, fillSize, true, true);
var data = [];
//generate outerLayer and insets
for (var layer = 0; layer < slices.length; layer ++) {
var slice = slices[layer];
var layerData = [];
data.push(layerData);
for (var i = 0; i < slice.length; i ++) {
var part = slice[i];
var outerLayer = part.clone().scaleUp(scale).offset(-nozzleRadius);
var insets = new D3D.Paths([], true);
if (outerLayer.length > 0) {
for (var offset = nozzleDiameter; offset <= shellThickness; offset += nozzleDiameter) {
var inset = outerLayer.offset(-offset);
insets.join(inset);
}
layerData.push({
outerLayer: outerLayer,
insets: insets
});
}
}
}
//generate infills
for (var layer = 0; layer < data.length; layer ++) {
var slice = data[layer];
var downSkin = new D3D.Paths([], true);
if (layer - bottomSkinCount >= 0) {
var downLayer = data[layer - bottomSkinCount];
for (var i = 0; i < downLayer.length; i ++) {
downSkin.join(downLayer[i].outerLayer);
}
}
var upSkin = new D3D.Paths([], true);
if (layer + topSkinCount < data.length) {
var upLayer = data[layer + topSkinCount];
for (var i = 0; i < upLayer.length; i ++) {
upSkin.join(upLayer[i].outerLayer);
}
}
var surroundingLayer = upSkin.intersect(downSkin);
var sliceData = [];
for (var i = 0; i < slice.length; i ++) {
var part = slice[i];
var outerLayer = part.outerLayer;
var insets = part.insets;
if (outerLayer.length > 0) {
var fillArea = ((insets.length > 0) ? insets : outerLayer).offset(-nozzleRadius);
var highFillArea = fillArea.difference(surroundingLayer);
var lowFillArea = fillArea.difference(highFillArea);
var fill = new D3D.Paths([], false);
if (lowFillTemplate.length > 0) {
fill.join(lowFillTemplate.intersect(lowFillArea));
}
if (highFillArea.length > 0) {
var bounds = highFillArea.bounds();
var even = (layer % 2 === 0);
var highFillTemplate = this.getFillTemplate(bounds, nozzleDiameter, even, !even);
fill.join(highFillTemplate.intersect(highFillArea));
}
part.fill = fill;
}
}
this.progress.dataLayer = layer;
this.updateProgress();
}
//generate support
if (useSupport) {
var supportTemplate = this.getFillTemplate({
left: this.geometry.boundingBox.min.z * scale,
top: this.geometry.boundingBox.min.x * scale,
right: this.geometry.boundingBox.max.z * scale,
bottom: this.geometry.boundingBox.max.x * scale
}, supportGritSize, true, true);
var supportAreas = new D3D.Paths([], true);
for (var layer = data.length - 1 - supportDistanceLayers; layer >= 0; layer --) {
if (supportAreas.length > 0) {
if (layer >= supportDistanceLayers) {
var sliceSkin = new D3D.Paths([], true);
var slice = data[layer - supportDistanceLayers];
for (var i = 0; i < slice.length; i ++) {
sliceSkin.join(slice[i].outerLayer);
}
sliceSkin = sliceSkin.offset(supportMargin);
supportAreas = supportAreas.difference(sliceSkin);
}
var currentSlice = data[layer];
if (layer === 0) {
supportAreas = supportAreas.offset(plateSize).difference(sliceSkin);
var template = this.getFillTemplate(supportAreas.bounds(), nozzleDiameter, true, false);
currentSlice[0].support = template.intersect(supportAreas);
}
else {
currentSlice[0].support = supportTemplate.intersect(supportAreas).join(supportAreas.clone());
}
}
var supportSlice = data[layer + supportDistanceLayers - 1];
var supportSkin = new D3D.Paths([], true);
for (var i = 0; i < supportSlice.length; i ++) {
//supportSkin = supportSkin.union(supportSlice[i].outerLayer);
supportSkin.join(supportSlice[i].outerLayer);
}
var slice = data[layer + supportDistanceLayers];
for (var i = 0; i < slice.length; i ++) {
var slicePart = slice[i];
var outerLayer = slicePart.outerLayer;
var overlap = supportSkin.offset(supportAccaptanceSize).intersect(outerLayer);
var overhang = outerLayer.difference(overlap);
if (overlap.length === 0 || overhang.length > 0) {
var supportArea = outerLayer.difference(supportSkin.intersect(outerLayer));
supportAreas = supportAreas.union(supportArea);
}
}
}
}
//finalize paths
var start = new THREE.Vector2(0, 0);
var order = ["outerLayer", "insets", "fill", "support"];
for (var layer = 0; layer < data.length; layer ++) {
var slice = data[layer];
for (var i = 0; i < slice.length; i ++) {
var part = slice[i];
for (var j = 0; j < order.length; j ++) {
var property = order[j];
if (part[property] !== undefined && part[property].length > 0) {
part[property] = part[property].optimizePath(start);
start = part[property].lastPoint();
}
}
part.outerLayer.scaleDown(100);
part.insets.scaleDown(100);
part.fill.scaleDown(100);
if (part.support !== undefined) {
part.support.scaleDown(100);
}
}
}
return data;
};
D3D.Slicer.prototype.getFillTemplate = function (bounds, size, even, uneven) {
"use strict";
var paths = new D3D.Paths([], false);
if (even) {
for (var length = Math.floor(bounds.left/size)*size; length <= Math.ceil(bounds.right/size)*size; length += size) {
paths.push([{X: length, Y: bounds.top}, {X: length, Y: bounds.bottom}]);
}
}
if (uneven) {
for (var length = Math.floor(bounds.top/size)*size; length <= Math.floor(bounds.bottom/size)*size; length += size) {
paths.push([{X: bounds.left, Y: length}, {X: bounds.right, Y: length}]);
}
}
//return paths;
return paths;
};
D3D.Slicer.prototype.dataToGCode = function (data, printer) {
"use strict";
var gcode = new D3D.GCode().setSettings(printer);
function sliceToGCode (path, retract, unRetract) {
for (var i = 0; i < path.length; i ++) {
var shape = path[i];
var length = path.closed ? (shape.length + 1) : shape.length;
for (var j = 0; j < length; j ++) {
var point = shape[j % shape.length];
if (j === 0) {
gcode.moveTo(false, point.X, point.Y, layer);
if (unRetract) {
gcode.unRetract();
}
}
else {
gcode.moveTo(true, point.X, point.Y, layer);
}
}
}
if (retract) {
gcode.retract();
}
}
for (var layer = 0; layer < data.length; layer ++) {
var slice = data[layer];
if (layer === 1) {
gcode.turnFanOn();
gcode.bottom = false;
}
for (var i = 0; i < slice.length; i ++) {
var layerPart = slice[i];
sliceToGCode(layerPart.outerLayer, false, true);
sliceToGCode(layerPart.insets, false, false);
sliceToGCode(layerPart.fill, true, false);
if (layerPart.support !== undefined) {
sliceToGCode(layerPart.support, true, true);
}
}
this.progress.gcodeLayer = layer;
this.updateProgress();
}
return gcode.getGCode();
};
D3D.Slicer.prototype.getGCode = function (printer) {
"use strict";
var layerHeight = printer.config["printer.layerHeight"];
var dimensionsZ = printer.config["printer.dimensions.z"];
this.progress.totalLayers = Math.floor(Math.min(this.geometry.boundingBox.max.y, dimensionsZ) / layerHeight);
this.progress.sliceLayer = 0;
this.progress.dataLayer = 0;
this.progress.gcodeLayer = 0;
var start = new Date().getTime();
var slices = this.slice(layerHeight, dimensionsZ);
var end = new Date().getTime();
console.log("Slicing: " + (end - start) + "ms");
start = new Date().getTime();
var data = this.slicesToData(slices, printer);
end = new Date().getTime();
console.log("Data: " + (end - start) + "ms");
start = new Date().getTime();
var gcode = this.dataToGCode(data, printer);
end = new Date().getTime();
console.log("Gcode: " + (end - start) + "ms");
return gcode;
};

30
src/slicerWorker.js Normal file
View File

@ -0,0 +1,30 @@
import slice from './sliceActions/slice.js';
import * as THREE from 'three';
const loader = new THREE.JSONLoader();
const onProgress = progress => {
self.postMessage({
message: 'PROGRESS',
data: progress
});
}
self.addEventListener('message', (event) => {
const { message, data } = event.data;
switch (message) {
case 'SLICE': {
const { geometry: JSONGeometry, settings } = data;
const { geometry } = new loader.parse(JSONGeometry.data);
const gcode = slice(geometry, settings, onProgress);
self.postMessage({
message: 'SLICE',
data: { gcode }
});
break;
}
}
}, false);

View File

@ -1,78 +0,0 @@
D3D.SlicerWorker = function () {
'use strict';
this.worker = new Worker('webworker/worker.js');
var scope = this;
this.worker.addEventListener('message', function (event) {
switch (event.data['cmd']) {
case 'PROGRESS':
if (scope.onprogress !== undefined) {
var progress = event.data['progress'];
scope.onprogress(progress);
}
break;
case 'GCODE':
if (scope.onfinish !== undefined) {
var gcode = event.data['gcode'];
scope.onfinish(gcode);
}
break;
}
}, false);
}
D3D.SlicerWorker.prototype.setSettings = function (USER_SETTINGS, PRINTER_SETTINGS) {
'use strict';
this.worker.postMessage({
'cmd': 'SET_SETTINGS',
'USER_SETTINGS': USER_SETTINGS,
'PRINTER_SETTINGS': PRINTER_SETTINGS
});
};
D3D.SlicerWorker.prototype.setMesh = function (mesh) {
'use strict';
if (mesh.geometry instanceof THREE.Geometry) {
var geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry);
}
else {
var geometry = mesh.geometry.clone();
}
var buffers = [];
for (var i = 0; i < geometry.attributesKeys.length; i ++) {
var key = geometry.attributesKeys[i];
buffers.push(geometry.attributes[key].array.buffer);
}
mesh.updateMatrix();
this.worker.postMessage({
'cmd': 'SET_MESH',
'geometry': {
'attributes': geometry.attributes,
'attributesKeys': geometry.attributesKeys
},
'matrix': mesh.matrix.toArray()
}, buffers);
};
D3D.SlicerWorker.prototype.slice = function () {
'use strict';
this.worker.postMessage({
'cmd': 'SLICE'
});
};
D3D.SlicerWorker.prototype.close = function () {
'use strict';
this.worker.postMessage({
'cmd': 'CLOSE'
});
};

View File

@ -1,151 +0,0 @@
/******************************************************
*
* Utils
* dependices Three.js
*
******************************************************/
var D3D = {
"version": "0.1",
"website": "http://www.doodle3d.com/",
"contact": "develop@doodle3d.com"
};
function sendAPI (url, data, callback) {
"use strict";
/*
var form = new FormData();
for (var i in data) {
form.append(i, JSON.stringify(data[i]));
}
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.send(data);
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var response = JSON.parse(request.responseText);
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
else {
console.log(request);
console.warn("Failed connecting to " + url);
//sendAPI(url, data, callback);
}
};
*/
$.ajax({
url: url,
type: "POST",
data: data,
dataType: "json",
timeout: 10000,
success: function (response) {
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
}).fail(function () {
console.warn("Failed connecting to " + url);
sendAPI(url, data, callback);
});
}
function getAPI (url, callback) {
"use strict";
/*
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.send();
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var response = JSON.parse(request.responseText);
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
else {
console.warn("Failed connecting to " + url);
sendAPI(url, callback);
}
};*/
$.ajax({
url: url,
dataType: "json",
timeout: 5000,
success: function (response) {
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
}).fail(function () {
console.warn("Failed connecting to " + url);
getAPI(url, callback);
});
}
function loadSettings (url, callback) {
"use strict";
$.ajax({
url: url,
dataType: "json",
success: function (response) {
if (callback !== undefined) {
callback(response);
}
}
});
}
function downloadFile (file, data) {
"use strict";
var blob = new Blob([data], {type:'text/plain'});
var button = document.createElement("a");
button.download = file;
button.href = window.URL.createObjectURL(blob);
button.click();
}
Array.prototype.clone = function () {
"use strict";
var array = [];
for (var i = 0; i < this.length; i ++) {
array[i] = this[i];
}
return array;
}

View File

@ -1,9 +0,0 @@
self.addEventListener("message", function (event) {
"use strict";
//console.log(event.data);
if (event.data === "close") {
self.close();
}
});

View File

@ -1,57 +0,0 @@
importScripts("../library/three.js");
importScripts("../library/clipper.js");
importScripts("../src/utils.js");
importScripts("../src/printer.js");
importScripts("../src/paths.js");
importScripts("../src/slicer.js");
importScripts("../src/gcode.js");
var printer = new D3D.Printer();
var slicer = new D3D.Slicer();
slicer.onProgress = function (progress) {
"use strict";
self.postMessage({
"cmd": "PROGRESS",
"progress": progress
});
};
self.addEventListener("message", function (event) {
"use strict";
switch (event.data["cmd"]) {
case "SET_MESH":
//hack...
//because boundings loses functions when converting
event.data["geometry"].boundingBox = event.data["geometry"].boundingSphere = null;
var geometry = new THREE.Geometry().fromBufferGeometry(event.data["geometry"]);
var matrix = new THREE.Matrix4().fromArray(event.data["matrix"]);
slicer.setMesh(geometry, matrix);
break;
case "SET_SETTINGS":
printer.updateConfig(event.data["USER_SETTINGS"]);
printer.updateConfig(event.data["PRINTER_SETTINGS"]);
break;
case "SLICE":
var gcode = slicer.getGCode(printer);
self.postMessage({
"cmd": "GCODE",
"gcode": gcode
});
break;
case "CLOSE":
self.close();
break;
}
});

View File

@ -1,74 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<script src="library/benchmark.js"></script>
<script src="library/three.js"></script>
<title>Doedel Drie Dee || Webworker Benchmark</title>
<style>
</style>
</head>
<body>
<script>
var worker = new Worker('webworker/benchmark.js');
var geometry = new THREE.BoxGeometry(10, 30, 10).clone();
//var geometry = new THREE.TorusKnotGeometry(10, 3, 200, 200).clone();
new Benchmark.Suite().add('Buffer Geometry', function () {
var bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry);
worker.postMessage(bufferGeometry);
//this happens in the worker
var workerGeometry = new THREE.Geometry().fromBufferGeometry(bufferGeometry);
workerGeometry.mergeVertices();
}).add('Buffer Geometry Transferrable Object', function () {
var bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry);
var buffers = [];
for (var i = 0; i < bufferGeometry.attributesKeys.length; i ++) {
var key = bufferGeometry.attributesKeys[i];
buffers.push(bufferGeometry.attributes[key].array.buffer);
}
worker.postMessage(bufferGeometry, buffers);
//this happens in the worker
//this is redundant...
//buffers are transferred to worker so the do not exist in this part of the script
//[TEST NOT VIABLE]
var workerGeometry = new THREE.Geometry().fromBufferGeometry(bufferGeometry);
workerGeometry.mergeVertices();
}).add('Geometry JSON', function () {
var json = geometry.toJSON().data;
worker.postMessage(json);
//worker.postMessage(geometry);
//this happens in the worker
var loader = new THREE.JSONLoader();
var workerGeometry = loader.parse(json).geometry;
workerGeometry.mergeVertices();
}).on('cycle', function (event) {
document.body.innerHTML += "<p>" + String(event.target) + "</p>";
}).on('complete', function () {
document.body.innerHTML += "<p>" + 'Fastest is "' + this.filter('fastest').pluck('name') + '"' + "</p>";
}).run({
'async': true
});
</script>
</body>
</html>

View File

@ -1,19 +0,0 @@
----------- RESULTATEN TORUS KNOT --------------
Buffer Geometry x 0.53 ops/sec ±134.70% (8 runs sampled)
Buffer Geometry Transferrable Object x 63.04 ops/sec ±2.19% (67 runs sampled)
Geometry JSON x 0.50 ops/sec ±6.55% (6 runs sampled)
Fastest is "Buffer Geometry Transferrable Object"
----------- RESULTATEN KUBUS --------------
Buffer Geometry x 5,360 ops/sec ±19.42% (85 runs sampled)
Buffer Geometry Transferrable Object x 1,535 ops/sec ±10.17% (35 runs sampled)
Geometry JSON x 3,831 ops/sec ±2.52% (82 runs sampled)
Fastest is "Buffer Geometry"

View File

@ -1,207 +0,0 @@
<!DOCTYPE HTML>
<html lang='en'>
<head>
<script src='library/jquery.js'></script>
<script src='library/three.js'></script>
<script src='library/stl_loader.js'></script>
<script src='src/utils.js'></script>
<script src='src/box.js'></script>
<script src='src/printer.js'></script>
<script src='src/slicerworker.js'></script>
<title>Doedel Drie Dee || Webworker Test</title>
<style>
canvas {border: 1px solid black;}
#progress {height: 20px; width: 200px; border: 1px solid black; overflow: hidden;}
#progress_bar {height: 20px; background-color: lightblue; width: 0%;}
.block {border: 1px solid black; width: 400px; height: 400px; display: inline-block;}
#start_print, #download {display: none;}
</style>
</head>
<body>
<canvas id='3d-preview' height='400' width='400'></canvas>
<div class='block'>
<p>State: <span id='state'></span></p>
<p>Bed Temp: <span id='bed_temp'></span></p>
<p>Bed Target Temp: <span id='bed_target_temp'></span></p>
<p>Nozzle Temp: <span id='nozzle_temp'></span></p>
<p>Nozzle Target Temp: <span id='nozzle_target_temp'></span></p>
<p>Current Line: <span id='current_line'></span></p>
<p>Buffered Lines: <span id='buffered_lines'></span></p>
<p>Total Lines: <span id='total_lines'></span></p>
<p>Batches To Send: <span id='print_batches'></span></p>
<div id='progress'><div id='progress_bar'></div></div>
<button id="stop_print">Stop Print</button>
<button id="start_print">Start Print</button>
<button id="download">Download Gcode</button>
</div>
<script>
var USER_SETTINGS, PRINTER_SETTINGS, doodleBox, gcode, slicerWorker, printer;
function init () {
'use strict';
var scene = createScene();
var localIp = location.hash.substring(1);
doodleBox = new D3D.Box(localIp);
doodleBox.onupdate = function (data) {
document.getElementById('state').innerHTML = data.state;
document.getElementById('bed_temp').innerHTML = data.bed;
document.getElementById('bed_target_temp').innerHTML = data.bed_target;
document.getElementById('nozzle_temp').innerHTML = data.hotend;
document.getElementById('nozzle_target_temp').innerHTML = data.hotend_target;
document.getElementById('current_line').innerHTML = data.current_line;
document.getElementById('buffered_lines').innerHTML = data.buffered_lines;
document.getElementById('total_lines').innerHTML = data.total_lines;
document.getElementById('print_batches').innerHTML = doodleBox.printBatches.length;
};
printer = new D3D.Printer().updateConfig(USER_SETTINGS).updateConfig(PRINTER_SETTINGS['ultimaker2go']);
document.getElementById('stop_print').onclick = function () {
doodleBox.stopPrint(printer);
};
var slicer = new D3D.SlicerWorker();
slicer.setSettings(USER_SETTINGS, PRINTER_SETTINGS['ultimaker2go']);
var progressBar = document.getElementById('progress_bar');
slicer.onprogress = function (progress) {
progressBar.style.width = progress.procent * 100 + '%';
};
slicer.onfinish = function (_gcode) {
gcode = _gcode;
var startPrintButton = document.getElementById('start_print');
var downloadButton = document.getElementById('download');
startPrintButton.style.display = 'initial';
startPrintButton.onclick = function () {
doodleBox.print(gcode);
};
downloadButton.style.display = 'initial';
downloadButton.onclick = function () {
downloadFile("gcode.gcode", gcode.join('\n'));
};
};
var loader = new THREE.STLLoader();
loader.load('models/robot.stl', function (geometry) {
//var geometry = new THREE.TorusGeometry(20, 10, 30, 30).clone();
var material = new THREE.MeshPhongMaterial({color: 0x00ff00, wireframe: false});
//var material = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -Math.PI/2;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 1;
mesh.position.y = -0.1;
mesh.position.x = 60;
mesh.position.z = 60;
scene.add(mesh);
slicer.setMesh(mesh);
slicer.slice();
slicer.close();
});
}
function createScene () {
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer({canvas: document.getElementById('3d-preview'), antialias: true});
renderer.setClearColor(0xffffff, 1);
var camera = new THREE.PerspectiveCamera(75, renderer.domElement.width/renderer.domElement.height, 1, 10000);
scene.add(camera);
var light = new THREE.AmbientLight(0x404040);
scene.add(light);
var directionalLight = new THREE.PointLight(0xffffff, 0.5);
camera.add(directionalLight);
applyMouseControls(renderer, camera, new THREE.Vector3(50, 0, 50), 1000);
function applyMouseControls (renderer, camera, center, maxDistance) {
var distance = 20;
var rotX = 0;
var rotY = 0;
var moveCamera = false;
function updateCamera () {
camera.position.set(
Math.cos(rotY)*Math.sin(rotX)*distance,
Math.sin(rotY)*distance,
Math.cos(rotY)*Math.cos(rotX)*distance
).add(center);
camera.lookAt(center);
}
$(renderer.domElement).on('mousedown', function (e) {
moveCamera = true;
}).on('wheel', function (e) {
var event = e.originalEvent;
event.preventDefault();
distance = THREE.Math.clamp(distance - event.wheelDelta, 1, maxDistance);
updateCamera();
});
$(window).on('mouseup', function (e) {
moveCamera = false;
}).on('mousemove', function (e) {
var event = e.originalEvent;
if (moveCamera === true) {
rotX = (rotX - event.webkitMovementX/100) % (2*Math.PI);
rotY = THREE.Math.clamp(rotY + event.webkitMovementY/100, -Math.PI/2, Math.PI/2);
updateCamera();
}
});
updateCamera();
}
(function animate () {
requestAnimationFrame(animate);
renderer.render(scene, camera);
})();
return scene;
}
(function () {
'use strict';
var loadedItems = 0;
function loaded () {
loadedItems ++;
if (loadedItems === 2) {
init();
}
}
loadSettings('settings/user_settings.json', function (data) {
USER_SETTINGS = data;
loaded();
});
loadSettings('settings/printer_settings.json', function (data) {
PRINTER_SETTINGS = data;
loaded();
});
})();
</script>
</body>
</html>