From 5094996a02267e855eb9581ecbe1aa97eb1f6e27 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Fri, 12 Mar 2021 16:17:31 +1100 Subject: [PATCH 1/5] Match camera fov between cameras, add axes related to #235 --- web/src/components/IdeViewer/IdeViewer.js | 30 +++++++++-------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/web/src/components/IdeViewer/IdeViewer.js b/web/src/components/IdeViewer/IdeViewer.js index 739eb22..e324c19 100644 --- a/web/src/components/IdeViewer/IdeViewer.js +++ b/web/src/components/IdeViewer/IdeViewer.js @@ -10,11 +10,14 @@ function Controls({ onCameraChange }) { 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) + console.log(camera) + 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' if (controls.current) { @@ -29,7 +32,7 @@ function Controls({ onCameraChange }) { } 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 scale = 10 const scadY = -negScadY return [scadX * scale, scadY * scale, scadZ * scale] } @@ -65,7 +68,7 @@ function Box(props) { return ( - + ) @@ -85,14 +88,6 @@ const IdeViewer = () => { 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. -
{image && (
{ /> - - - - + + +
-- 2.39.5 From d3e70126693a150255c51103a9bd760363bf7a5a Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Fri, 12 Mar 2021 18:54:17 +1100 Subject: [PATCH 2/5] Add debounce to image fetch, add loading spinner other polish related #235 --- web/src/components/IdeViewer/IdeViewer.js | 101 +++++++++++++--------- web/src/helpers/hooks/useIdeState.js | 9 ++ 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/web/src/components/IdeViewer/IdeViewer.js b/web/src/components/IdeViewer/IdeViewer.js index e324c19..8ef3950 100644 --- a/web/src/components/IdeViewer/IdeViewer.js +++ b/web/src/components/IdeViewer/IdeViewer.js @@ -1,10 +1,11 @@ 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 }) +let debounceTimeoutId function Controls({ onCameraChange }) { const controls = useRef() const { scene, camera, gl } = useThree() @@ -12,41 +13,48 @@ function Controls({ onCameraChange }) { // init camera position camera.position.x = 16 camera.position.y = 12 - console.log(camera) 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 - 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 = () => clearTimeout(debounceTimeoutId) + controls.current.addEventListener('end', dragCallback) + controls.current.addEventListener('start', dragStart) const oldCurrent = controls.current - return () => oldCurrent.removeEventListener('end', callback) + return () => { + oldCurrent.removeEventListener('end', dragCallback) + oldCurrent.removeEventListener('start', dragStart) + } } }, []) @@ -55,8 +63,6 @@ function Controls({ onCameraChange }) { ) @@ -77,32 +83,39 @@ 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 (
+ {state.isLoading && ( +
+
+
+ )} {image && (
)}
setIsDragging(true)} - onMouseUp={() => setIsDragging(false)} > { /> - - - + + +
diff --git a/web/src/helpers/hooks/useIdeState.js b/web/src/helpers/hooks/useIdeState.js index 9777dcc..a3e6994 100644 --- a/web/src/helpers/hooks/useIdeState.js +++ b/web/src/helpers/hooks/useIdeState.js @@ -23,6 +23,7 @@ export const useIdeState = () => { splitPercentage: 70, }, }, + isLoading: false, } const reducer = (state, { type, payload }) => { switch (type) { @@ -38,6 +39,7 @@ export const useIdeState = () => { consoleMessages: payload.message ? [...state.consoleMessages, payload.message] : payload.message, + isLoading: false, } case 'errorRender': return { @@ -45,6 +47,7 @@ export const useIdeState = () => { consoleMessages: payload.message ? [...state.consoleMessages, payload.message] : payload.message, + isLoading: false, } case 'setIdeType': return { @@ -56,6 +59,11 @@ export const useIdeState = () => { ...state, layout: payload.message, } + case 'setLoading': + return { + ...state, + isLoading: true, + } default: return state } @@ -83,6 +91,7 @@ export const useIdeState = () => { }) } }) + dispatch({ type: 'setLoading' }) break default: -- 2.39.5 From a1c3d7a300be92ffbcfb2f2be755a5af4d886205 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Fri, 12 Mar 2021 19:02:43 +1100 Subject: [PATCH 3/5] Load first render on init will probably have to change in future when the code is loaded async too ok for now. --- web/src/components/IdeViewer/IdeViewer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/src/components/IdeViewer/IdeViewer.js b/web/src/components/IdeViewer/IdeViewer.js index 8ef3950..efc42a7 100644 --- a/web/src/components/IdeViewer/IdeViewer.js +++ b/web/src/components/IdeViewer/IdeViewer.js @@ -51,6 +51,7 @@ function Controls({ onCameraChange }) { controls.current.addEventListener('end', dragCallback) controls.current.addEventListener('start', dragStart) const oldCurrent = controls.current + dragCallback() return () => { oldCurrent.removeEventListener('end', dragCallback) oldCurrent.removeEventListener('start', dragStart) -- 2.39.5 From 23e34a0a6471ce3a7844e23cf12966edff54466b Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Fri, 12 Mar 2021 19:48:33 +1100 Subject: [PATCH 4/5] Add loading spinner on scroll --- web/src/components/IdeViewer/IdeViewer.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/src/components/IdeViewer/IdeViewer.js b/web/src/components/IdeViewer/IdeViewer.js index efc42a7..828af15 100644 --- a/web/src/components/IdeViewer/IdeViewer.js +++ b/web/src/components/IdeViewer/IdeViewer.js @@ -6,7 +6,7 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' extend({ OrbitControls }) let debounceTimeoutId -function Controls({ onCameraChange }) { +function Controls({ onCameraChange, onDragStart }) { const controls = useRef() const { scene, camera, gl } = useThree() useEffect(() => { @@ -47,7 +47,10 @@ function Controls({ onCameraChange }) { }) }, 400) } - const dragStart = () => clearTimeout(debounceTimeoutId) + const dragStart = () => { + onDragStart() + clearTimeout(debounceTimeoutId) + } controls.current.addEventListener('end', dragCallback) controls.current.addEventListener('start', dragStart) const oldCurrent = controls.current @@ -120,6 +123,7 @@ const IdeViewer = () => { > setIsDragging(true)} onCameraChange={({ position, rotation }) => { dispatch({ type: 'render', -- 2.39.5 From e5149f2c9520d0eae0883906577b9c12acd3155c Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 13 Mar 2021 17:10:15 +1100 Subject: [PATCH 5/5] Tidy up --- api/src/docker/openscad/runScad.js | 2 +- web/src/components/IdeViewer/IdeViewer.js | 2 +- web/src/helpers/hooks/useIdeState.js | 13 ++++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) 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 828af15..b97d8e0 100644 --- a/web/src/components/IdeViewer/IdeViewer.js +++ b/web/src/components/IdeViewer/IdeViewer.js @@ -116,7 +116,7 @@ const IdeViewer = () => {
)}
setIsDragging(true)} diff --git a/web/src/helpers/hooks/useIdeState.js b/web/src/helpers/hooks/useIdeState.js index a3e6994..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', -- 2.39.5