Add axes w/ rotation sync w/ main model viewer
This commit is contained in:
parent
a01a7df0a0
commit
7a9e3f927f
3 changed files with 109 additions and 22 deletions
46
axes.scad
Normal file
46
axes.scad
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
module arrow(length=30, shaft_radius=1, head_radius=2, head_length=5) {
|
||||
cylinder(h=length-head_length, r=shaft_radius, center=false);
|
||||
|
||||
translate([0, 0, length-head_length])
|
||||
cylinder(h=head_length, r1=head_radius, r2=0, center=false);
|
||||
}
|
||||
|
||||
color("red")
|
||||
rotate([0, 90, 0])
|
||||
arrow();
|
||||
|
||||
color("green")
|
||||
rotate([-90, 0, 0])
|
||||
arrow();
|
||||
|
||||
color("blue")
|
||||
rotate([0, 0, 90])
|
||||
arrow();
|
||||
|
||||
module letter(text)
|
||||
linear_extrude(1) text(text, halign="center", valign="center");
|
||||
|
||||
letter_dist = 38;
|
||||
union() {
|
||||
color("red")
|
||||
translate([letter_dist, 0, 0])
|
||||
rotate([45, 0, 45])
|
||||
letter("X");
|
||||
color("green")
|
||||
rotate([0, 0, 90])
|
||||
translate([letter_dist, 0, 0])
|
||||
rotate([45, 0, -45])
|
||||
letter("Y");
|
||||
color("blue")
|
||||
rotate([0, -90, 0])
|
||||
translate([letter_dist, 0, 0])
|
||||
rotate([90+45, 0, 0])
|
||||
rotate([0, 0, -90])
|
||||
letter("Z");
|
||||
}
|
||||
|
||||
color("grey")
|
||||
cube(10, center=true);
|
||||
|
||||
color([0, 0, 0, $preview ? 0.05 : 0])
|
||||
sphere(r=43);
|
||||
BIN
public/axes.glb
Normal file
BIN
public/axes.glb
Normal file
Binary file not shown.
|
|
@ -1,10 +1,7 @@
|
|||
// Portions of this file are Copyright 2021 Google LLC, and licensed under GPL2+. See COPYING.
|
||||
|
||||
import { CSSProperties, useContext, useRef } from 'react';
|
||||
import { CSSProperties, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { ModelContext } from './contexts';
|
||||
import { StlViewer} from "react-stl-viewer";
|
||||
import { ColorPicker } from 'primereact/colorpicker';
|
||||
import { defaultModelColor } from '../state/initial-state';
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
|
|
@ -19,34 +16,78 @@ export default function ViewerPanel({className, style}: {className?: string, sty
|
|||
if (!model) throw new Error('No model');
|
||||
|
||||
const state = model.state;
|
||||
const modelRef = useRef();
|
||||
const modelViewerRef = useRef<any>();
|
||||
const axesViewerRef = useRef<any>();
|
||||
|
||||
for (const ref of [modelViewerRef, axesViewerRef]) {
|
||||
const otherRef = ref === modelViewerRef ? axesViewerRef : modelViewerRef;
|
||||
useEffect(() => {
|
||||
function handleCameraChange(e: any) {
|
||||
if (e.detail.source === 'user-interaction') {
|
||||
const cameraOrbit = ref.current.getCameraOrbit();
|
||||
cameraOrbit.radius = otherRef.current.getCameraOrbit().radius;
|
||||
|
||||
otherRef.current.cameraOrbit = cameraOrbit.toString();
|
||||
}
|
||||
}
|
||||
ref.current.addEventListener('camera-change', handleCameraChange);
|
||||
return () => ref.current.removeEventListener('camera-change', handleCameraChange);
|
||||
}, [ref.current, otherRef.current]);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
...(style ?? {})
|
||||
}}>
|
||||
{(state.output?.displayFileURL || state.output?.outFile && state.output.outFile.name.endsWith('.glb') && state.output?.outFileURL) && (
|
||||
<model-viewer
|
||||
orientation="0deg -90deg 0deg"
|
||||
src={state.output?.displayFileURL ?? state.output?.outFileURL ?? ''}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
environment-image="./skybox-lights.jpg"
|
||||
max-camera-orbit="auto 180deg auto"
|
||||
min-camera-orbit="auto 0deg auto"
|
||||
camera-controls
|
||||
ar
|
||||
ref={(ref: any) => {
|
||||
modelRef.current = ref;
|
||||
}}
|
||||
/>
|
||||
<model-viewer
|
||||
orientation="0deg -90deg 0deg"
|
||||
src={state.output?.displayFileURL ?? state.output?.outFileURL ?? ''}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
environment-image="./skybox-lights.jpg"
|
||||
max-camera-orbit="auto 180deg auto"
|
||||
min-camera-orbit="auto 0deg auto"
|
||||
camera-controls
|
||||
ar
|
||||
ref={modelViewerRef}
|
||||
>
|
||||
<span slot="progress-bar"></span>
|
||||
</model-viewer>
|
||||
{state.view.showAxes && (
|
||||
<model-viewer
|
||||
orientation="0deg -90deg 0deg"
|
||||
src="./axes.glb"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
zIndex: 10,
|
||||
height: '200px',
|
||||
width: '200px',
|
||||
}}
|
||||
loading="eager"
|
||||
interpolation-decay="0"
|
||||
environment-image="./skybox-lights.jpg"
|
||||
max-camera-orbit="auto 180deg auto"
|
||||
min-camera-orbit="auto 0deg auto"
|
||||
orbit-sensitivity="5"
|
||||
interaction-prompt="none"
|
||||
disable-zoom
|
||||
camera-controls="false"
|
||||
disable-tap
|
||||
disable-pan
|
||||
ref={axesViewerRef}
|
||||
>
|
||||
<span slot="progress-bar"></span>
|
||||
</model-viewer>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue