-
+
+ {
+
- {!sliced &&
-
-
this.setState({ controlMode: 'translate' })} label="translate" />
- this.setState({ controlMode: 'rotate' })} label="rotate" />
- this.setState({ controlMode: 'scale' })} label="scale" />
+ {!showFullScreen.active &&
+
+
}
+ {!isSlicing &&
+
+
+
+
+
+
}
-
- {sliced &&
-
}
- {!sliced &&
+
+ {!showFullScreen.active && }
-
-
}
- {sliced &&
-
- {onCompleteActions.map(({ title, callback }, i) => (
- callback({ gcode, settings, printers, quality, material })} primary label={title} />
- ))}
-
}
- {isSlicing &&
-
Slicing: {progress.percentage.toLocaleString(navigator.language, { style: 'percent' })}
-
- {progress.actions.map((action, i) => - {action}
)}
-
-
}
+
+ {error &&
{error}
}
+ {isSlicing &&
{progress.action}
}
+ {isSlicing &&
}
+
+
+
+
+
);
}
diff --git a/src/interface/utils.js b/src/interface/utils.js
index 4e0bfd5..bc91f35 100644
--- a/src/interface/utils.js
+++ b/src/interface/utils.js
@@ -1,6 +1,9 @@
import * as THREE from 'three';
import 'three/examples/js/controls/EditorControls';
-import 'three/examples/js/controls/TransformControls';
+import printerSettings from '../settings/printer.yml';
+import materialSettings from '../settings/material.yml';
+import qualitySettings from '../settings/quality.yml';
+import { sliceGeometry } from '../slicer.js';
export function placeOnGround(mesh) {
const boundingBox = new THREE.Box3().setFromObject(mesh);
@@ -18,22 +21,11 @@ export function createScene(canvas, props, state) {
const center = geometry.boundingBox.getCenter();
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-center.x, -center.y, -center.z));
- const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
- renderer.setClearColor(0xffffff, 0);
-
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(50, 1, 1, 10000);
camera.position.set(0, 400, 300);
- const setSize = (width, height, pixelRatio = 1) => {
- renderer.setSize(width, height);
- renderer.setPixelRatio(pixelRatio);
- camera.aspect = width / height;
- camera.updateProjectionMatrix();
- render();
- };
-
const directionalLight = new THREE.DirectionalLight(0xd5d5d5);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
@@ -45,36 +37,109 @@ export function createScene(canvas, props, state) {
placeOnGround(mesh);
scene.add(mesh);
- const editorControls = new THREE.EditorControls(camera, canvas);
- editorControls.focus(mesh);
-
- const control = new THREE.TransformControls(camera, canvas);
- control.setMode(controlMode);
- control.setRotationSnap(THREE.Math.degToRad(45));
- control.addEventListener('mouseDown', () => editorControls.enabled = false);
- control.addEventListener('mouseUp', () => {
- editorControls.enabled = true;
- placeOnGround(mesh);
- });
-
- control.attach(mesh);
- scene.add(control);
-
- const render = () => {
- control.update();
- renderer.render(scene, camera);
- };
-
- control.addEventListener('change', render);
- editorControls.addEventListener('change', render);
-
- const box = new THREE.BoxHelper();
- box.update(new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1).applyMatrix(new THREE.Matrix4().makeTranslation(0, 0.5, 0))));
- box.material.color.setHex(0x72bcd4);
+ const box = new THREE.BoxHelper(new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1).applyMatrix(new THREE.Matrix4().makeTranslation(0, 0.5, 0))), 0x72bcd4);
scene.add(box);
const { dimensions } = settings;
box.scale.set(dimensions.y, dimensions.z, dimensions.x);
+ box.updateMatrix();
- return { control, editorControls, scene, mesh, camera, renderer, render, box, setSize };
+ const editorControls = new THREE.EditorControls(camera, canvas);
+ editorControls.focus(mesh);
+
+ const render = () => renderer.render(scene, camera);
+ editorControls.addEventListener('change', render);
+
+ const setSize = (width, height, pixelRatio = 1) => {
+ renderer.setSize(width, height);
+ renderer.setPixelRatio(pixelRatio);
+ camera.aspect = width / height;
+ camera.updateProjectionMatrix();
+ render();
+ };
+
+ let renderer;
+ const updateCanvas = (canvas) => {
+ renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
+ renderer.setClearColor(0xffffff, 0);
+ render();
+ };
+ updateCanvas(canvas);
+
+ return { editorControls, scene, mesh, camera, renderer, render, box, setSize, updateCanvas };
+}
+
+export function fetchProgress(url, { method = 'get', headers = {}, body = {} } = {}, onProgress) {
+ return new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open(method, url);
+ if (headers) {
+ for (const key in headers) {
+ const header = headers[key];
+ xhr.setRequestHeader(key, header);
+ }
+ }
+ xhr.onload = event => resolve(event.target.responseText);
+ xhr.onerror = reject;
+ if (xhr.upload && onProgress) xhr.upload.onprogress = onProgress;
+ xhr.send(body);
+ });
+}
+
+const GCODE_SERVER_URL = 'https://gcodeserver.doodle3d.com';
+const CONNECT_URL = 'http://connect.doodle3d.com/';
+
+export async function slice(mesh, settings, printers, quality, material, updateProgress) {
+ const { dimensions } = settings;
+ const centerX = dimensions.x / 2;
+ const centerY = dimensions.y / 2;
+
+ const geometry = mesh.geometry.clone();
+ mesh.updateMatrix();
+
+ const matrix = new THREE.Matrix4().makeTranslation(centerY, 0, centerX).multiply(mesh.matrix);
+ const gcode = await sliceGeometry(settings, geometry, matrix, false, false, ({ progress }) => {
+ updateProgress({
+ action: progress.action,
+ slicing: progress.done / progress.total
+ });
+ });
+
+ // upload G-code file to AWS S3
+ const { data: { reservation, id } } = await fetch(`${GCODE_SERVER_URL}/upload`, { method: 'POST' })
+ .then(response => response.json());
+
+ const body = new FormData();
+ const { fields } = reservation;
+ for (const key in fields) {
+ body.append(key, fields[key]);
+ }
+
+ const file = ';' + JSON.stringify({
+ name: `${name}.gcode`,
+ ...settings,
+ printer: {
+ type: printers,
+ title: printerSettings[printers].title
+ },
+ material: {
+ type: material,
+ title: materialSettings[material].title
+ },
+ quality: {
+ type: quality,
+ title: qualitySettings[quality].title
+ }
+ }).trim() + '\n' + gcode;
+ body.append('file', file);
+
+ await fetchProgress(reservation.url, { method: 'POST', body }, (progess) => {
+ updateProgress({
+ action: 'Uploading',
+ uploading: progess.loaded / progess.total
+ });
+ });
+
+ const popup = window.open(`${CONNECT_URL}?uuid=${id}`, '_blank');
+ if (!popup) throw new Error('popup was blocked by browser');
}
diff --git a/src/sliceActions/slice.js b/src/sliceActions/slice.js
index 42b2226..a1cbaad 100644
--- a/src/sliceActions/slice.js
+++ b/src/sliceActions/slice.js
@@ -99,31 +99,25 @@ function gcodeToString(gcode) {
}
const MAX_SPEED = 100 * 60;
+const COLOR = new THREE.Color();
function createGcodeGeometry(gcode) {
const positions = [];
const colors = [];
- let lastPoint
+ let lastPoint = [0, 0, 0];
for (let i = 0; i < gcode.length; i ++) {
const { G, F, X, Y, Z } = gcode[i];
if (X || Y || Z) {
- let color;
- if (G === 0) {
- color = new THREE.Color(0x00ff00);
- } else if (G === 1) {
- color = new THREE.Color().setHSL(F / MAX_SPEED, 0.5, 0.5);
- }
-
if (G === 1) {
- if (lastPoint) positions.push(lastPoint[0], lastPoint[1], lastPoint[2]);
+ positions.push(lastPoint.Y, lastPoint.Z, lastPoint.X);
positions.push(Y, Z, X);
+ const color = (G === 0) ? COLOR.setHex(0x00ff00) : COLOR.setHSL(F / MAX_SPEED, 0.5, 0.5);
colors.push(color.r, color.g, color.b);
colors.push(color.r, color.g, color.b);
}
-
- lastPoint = [Y, Z, X];
+ lastPoint = { X, Y, Z };
}
}