Doodle3D-Slicer/src/interface/utils.js

187 lines
5.5 KiB
JavaScript
Raw Normal View History

2017-11-11 20:23:45 +01:00
import * as THREE from 'three';
import 'three/examples/js/controls/EditorControls';
2017-12-04 15:08:29 +01:00
import printerSettings from '../settings/printer.yml';
import materialSettings from '../settings/material.yml';
import qualitySettings from '../settings/quality.yml';
import { sliceGeometry } from '../slicer.js';
2017-12-04 17:44:08 +01:00
import React from 'react';
import PropTypes from 'prop-types';
2017-11-11 20:23:45 +01:00
export function placeOnGround(mesh) {
2017-11-12 01:51:41 +01:00
const boundingBox = new THREE.Box3().setFromObject(mesh);
2017-11-11 20:23:45 +01:00
mesh.position.y -= boundingBox.min.y;
mesh.updateMatrix();
}
export function createScene(canvas, props, state) {
2017-11-13 12:42:35 +01:00
const { geometry, pixelRatio } = props;
2017-11-13 02:47:53 +01:00
const { controlMode, settings } = state;
2017-11-12 00:46:12 +01:00
// center geometry
2017-11-11 20:23:45 +01:00
geometry.computeBoundingBox();
2017-11-16 14:54:55 +01:00
const center = geometry.boundingBox.getCenter();
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(-center.x, -center.y, -center.z));
2017-11-11 20:23:45 +01:00
const scene = new THREE.Scene();
2017-11-13 11:15:00 +01:00
const camera = new THREE.PerspectiveCamera(50, 1, 1, 10000);
2017-11-11 20:23:45 +01:00
camera.position.set(0, 400, 300);
2017-12-05 11:10:31 +01:00
const directionalLightA = new THREE.DirectionalLight(0xa2a2a2);
directionalLightA.position.set(1, 1, 1);
scene.add(directionalLightA);
2017-11-11 20:23:45 +01:00
2017-12-05 11:10:31 +01:00
const directionalLightB = new THREE.DirectionalLight(0xa2a2a2);
directionalLightB.position.set(-1, 1, -1);
scene.add(directionalLightB);
const light = new THREE.AmbientLight(0x656565);
2017-11-11 20:23:45 +01:00
scene.add(light);
2017-12-05 11:10:31 +01:00
const material = new THREE.MeshPhongMaterial({ color: 0x2194ce, side: THREE.DoubleSide, specular: 0xaaaaaa, shininess: 10 });
const mesh = new THREE.Mesh(geometry, material);
2017-11-11 20:23:45 +01:00
placeOnGround(mesh);
scene.add(mesh);
2017-12-04 15:08:29 +01:00
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();
const render = () => renderer.render(scene, camera);
2017-11-11 20:23:45 +01:00
2017-12-04 15:08:29 +01:00
const setSize = (width, height, pixelRatio = 1) => {
renderer.setSize(width, height);
renderer.setPixelRatio(pixelRatio);
camera.aspect = width / height;
camera.updateProjectionMatrix();
render();
};
2017-11-11 20:23:45 +01:00
2017-12-04 17:44:08 +01:00
let editorControls;
2017-12-04 15:08:29 +01:00
let renderer;
const updateCanvas = (canvas) => {
2017-12-04 17:44:08 +01:00
if (!renderer || renderer.domElement !== canvas) {
if (renderer) renderer.dispose();
renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
renderer.setClearColor(0xffffff, 0);
}
if (!editorControls || editorControls.domElement !== canvas) {
if (editorControls) editorControls.dispose();
editorControls = new THREE.EditorControls(camera, canvas);
editorControls.focus(mesh);
editorControls.addEventListener('change', render);
}
2017-12-04 15:08:29 +01:00
render();
2017-11-11 20:23:45 +01:00
};
2017-12-04 15:08:29 +01:00
updateCanvas(canvas);
2017-11-11 20:23:45 +01:00
2017-12-04 15:08:29 +01:00
return { editorControls, scene, mesh, camera, renderer, render, box, setSize, updateCanvas };
}
2017-11-11 20:23:45 +01:00
2017-12-04 15:08:29 +01:00
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/';
2017-11-11 20:23:45 +01:00
2017-12-04 15:08:29 +01:00
export async function slice(mesh, settings, printers, quality, material, updateProgress) {
2017-11-13 02:47:53 +01:00
const { dimensions } = settings;
2017-12-04 15:08:29 +01:00
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
});
});
2017-11-11 20:23:45 +01:00
2017-12-04 15:08:29 +01:00
const popup = window.open(`${CONNECT_URL}?uuid=${id}`, '_blank');
if (!popup) throw new Error('popup was blocked by browser');
2017-11-11 20:23:45 +01:00
}
2017-12-04 17:44:08 +01:00
const styles = {
width: '100%',
position: 'relative',
textAlign: 'initial',
};
export const TabTemplate = ({children, selected, style}) => {
const templateStyle = Object.assign({}, styles, style);
if (!selected) {
templateStyle.height = 0;
templateStyle.width = 0;
templateStyle.overflow = 'hidden';
}
return (
<div style={templateStyle}>
{children}
</div>
);
};
TabTemplate.propTypes = {
children: PropTypes.node,
selected: PropTypes.bool,
style: PropTypes.object,
};