diff --git a/api/src/docker/openscad/runScad.js b/api/src/docker/openscad/runScad.js index 6ff251b..c313277 100644 --- a/api/src/docker/openscad/runScad.js +++ b/api/src/docker/openscad/runScad.js @@ -17,7 +17,7 @@ module.exports.runScad = async ({ const { x: rx, y: ry, z: rz } = rotation const { x: px, y: py, z: pz } = position const cameraArg = `--camera=${px},${py},${pz},${rx},${ry},${rz},300` - const command = `xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" openscad -o /tmp/${tempFile}/output.png ${cameraArg} --imgsize=${x},${y} /tmp/${tempFile}/main.scad` + const command = `xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" openscad -o /tmp/${tempFile}/output.png ${cameraArg} --imgsize=${x},${y} --colorscheme DeepOcean /tmp/${tempFile}/main.scad` console.log('command', command) try { diff --git a/web/src/components/IdeViewer/IdeViewer.js b/web/src/components/IdeViewer/IdeViewer.js index 739eb22..b97d8e0 100644 --- a/web/src/components/IdeViewer/IdeViewer.js +++ b/web/src/components/IdeViewer/IdeViewer.js @@ -1,49 +1,64 @@ import { IdeContext } from 'src/components/IdeToolbarNew' -import { useRef, useState, useEffect, useContext, useMemo } from 'react' +import { useRef, useState, useEffect, useContext } from 'react' import { Canvas, extend, useFrame, useThree } from 'react-three-fiber' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' extend({ OrbitControls }) -function Controls({ onCameraChange }) { +let debounceTimeoutId +function Controls({ onCameraChange, onDragStart }) { const controls = useRef() const { scene, camera, gl } = useThree() useEffect(() => { // init camera position - camera.position.x = 12 + camera.position.x = 16 camera.position.y = 12 - // Euler rotation can be problematic since order matters - // We want it to rotate around the z or vertical axis first then the x axis - // in Three Y is the vertical axis (Z for openscad) + camera.fov = 22.5 // matches default openscad fov + + // Order matters with Euler rotations + // We want it to rotate around the z or vertical axis first then the x axis to match openscad + // in Three.js Y is the vertical axis (Z for openscad) camera.rotation._order = 'YXZ' + const getRotations = () => { + const { x, y, z } = camera.rotation + const rad2Deg = 180 / Math.PI + const scadX = (x + Math.PI / 2) * rad2Deg + const scadZ = y * rad2Deg + const scadY = z * rad2Deg + return [scadX, scadY, scadZ] + } + const getPositions = () => { + const { x: scadX, y: scadZ, z: negScadY } = camera.position + const scale = 10 + const scadY = -negScadY + return [scadX * scale, scadY * scale, scadZ * scale] + } if (controls.current) { - const callback = ({ target }) => { - const getRotations = () => { - const { x, y, z } = target.object.rotation - const rad2Deg = 180 / Math.PI - const scadX = (x + Math.PI / 2) * rad2Deg - const scadZ = y * rad2Deg - const scadY = z * rad2Deg - return [scadX, scadY, scadZ] - } - const getPositions = () => { - const { x: scadX, y: scadZ, z: negScadY } = target.object.position - const scale = 10 // I'm not sure why this is exactly 10 - const scadY = -negScadY - return [scadX * scale, scadY * scale, scadZ * scale] - } - const [rx, ry, rz] = getRotations() - const [x, y, z] = getPositions() + const dragCallback = () => { + clearTimeout(debounceTimeoutId) + debounceTimeoutId = setTimeout(() => { + const [rx, ry, rz] = getRotations() + const [x, y, z] = getPositions() - onCameraChange({ - position: { x, y, z }, - rotation: { x: rx, y: ry, z: rz }, - }) + onCameraChange({ + position: { x, y, z }, + rotation: { x: rx, y: ry, z: rz }, + }) + }, 400) } - controls.current.addEventListener('end', callback) + const dragStart = () => { + onDragStart() + clearTimeout(debounceTimeoutId) + } + controls.current.addEventListener('end', dragCallback) + controls.current.addEventListener('start', dragStart) const oldCurrent = controls.current - return () => oldCurrent.removeEventListener('end', callback) + dragCallback() + return () => { + oldCurrent.removeEventListener('end', dragCallback) + oldCurrent.removeEventListener('start', dragStart) + } } }, []) @@ -52,8 +67,6 @@ function Controls({ onCameraChange }) { ) @@ -65,7 +78,7 @@ function Box(props) { return ( - + ) @@ -74,43 +87,43 @@ let currentCode // I have no idea why this works and using state.code is the dis const IdeViewer = () => { const { state, dispatch } = useContext(IdeContext) const [isDragging, setIsDragging] = useState(false) + const [image, setImage] = useState() - const image = useMemo( - () => + useEffect(() => { + setImage( state.objectData?.type === 'png' && - state.objectData?.data && - window.URL.createObjectURL(state.objectData?.data), - [state.objectData] - ) + state.objectData?.data && + window.URL.createObjectURL(state.objectData?.data) + ) + setIsDragging(false) + }, [state.objectData]) currentCode = state.code return (
-
- Rotating the Three.js Cube should than update the openscad camera to - view the CAD object from the same angle. But having trouble translating - between the two coordinate systems. OpenScad's camera only changes X and - Z angles and Y is always 0. Where as rotation values from Three seem to - change all x, y and z. I probably need to learn a bit more about 3d - math. -
+ {state.isLoading && ( +
+
+
+ )} {image && (
)}
setIsDragging(true)} - onMouseUp={() => setIsDragging(false)} > setIsDragging(true)} onCameraChange={({ position, rotation }) => { dispatch({ type: 'render', @@ -126,10 +139,17 @@ const IdeViewer = () => { /> - - - - + + +
diff --git a/web/src/helpers/hooks/useIdeState.js b/web/src/helpers/hooks/useIdeState.js index 9777dcc..90c4464 100644 --- a/web/src/helpers/hooks/useIdeState.js +++ b/web/src/helpers/hooks/useIdeState.js @@ -4,11 +4,14 @@ import { cadPackages } from 'src/helpers/cadPackages' export const useIdeState = () => { const initialState = { ideType: 'openScad', - consoleMessages: [ - { type: 'error', message: 'line 15 is being very naughty' }, - { type: 'message', message: '5 bodies produced' }, - ], - code: 'cube(60);sphere(25);', + consoleMessages: [{ type: 'message', message: 'Initialising OpenSCAD' }], + code: `difference(){ + union(){ + cube(60); + sphere(25); + } + translate([30,30,30])cylinder(r=25,h=100); +}`, objectData: { type: 'stl', data: 'some binary', @@ -23,6 +26,7 @@ export const useIdeState = () => { splitPercentage: 70, }, }, + isLoading: false, } const reducer = (state, { type, payload }) => { switch (type) { @@ -38,6 +42,7 @@ export const useIdeState = () => { consoleMessages: payload.message ? [...state.consoleMessages, payload.message] : payload.message, + isLoading: false, } case 'errorRender': return { @@ -45,6 +50,7 @@ export const useIdeState = () => { consoleMessages: payload.message ? [...state.consoleMessages, payload.message] : payload.message, + isLoading: false, } case 'setIdeType': return { @@ -56,6 +62,11 @@ export const useIdeState = () => { ...state, layout: payload.message, } + case 'setLoading': + return { + ...state, + isLoading: true, + } default: return state } @@ -83,6 +94,7 @@ export const useIdeState = () => { }) } }) + dispatch({ type: 'setLoading' }) break default: