global coordinate system widget

This commit is contained in:
Val Erastov 2018-10-01 23:30:36 -07:00
parent 88ce8f3890
commit fe9d7c1a81
12 changed files with 409 additions and 25 deletions

View file

@ -0,0 +1,67 @@
import {AmbientLight, PerspectiveCamera, Scene, SpotLight, WebGLRenderer} from 'three';
import DPR from '../dpr';
import {MeshArrow} from './objects/auxiliary';
import * as SceneGraph from './sceneGraph';
import {AXIS} from '../../web/app/math/l3space';
export default function(container) {
function createBasisArrow(axis, color) {
return new MeshArrow(axis, color, 1, 0.3, 0.15, 0.02);
}
let xAxis = createBasisArrow(AXIS.X, 0xFF0000);
let yAxis = createBasisArrow(AXIS.Y, 0x00FF00);
let zAxis = createBasisArrow(AXIS.Z, 0x0000FF);
let root = SceneGraph.createGroup();
let csys = SceneGraph.createGroup();
let scene = new Scene();
csys.add(xAxis);
csys.add(yAxis);
csys.add(zAxis);
root.add(csys);
scene.add(root);
let ambientLight = new AmbientLight(0x0f0f0f);
scene.add(ambientLight);
let spotLight = new SpotLight(0xffffff);
spotLight.position.set(0, 0, 5);
spotLight.castShadow = true;
scene.add(spotLight);
let camera = new PerspectiveCamera( 25, 1, 0.1, 2000 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 5;
let renderer = new WebGLRenderer({ alpha: true });
renderer.setPixelRatio(DPR);
// renderer.setClearColor(0x000000, 1);
// renderer.setClearAlpha(0);
renderer.setSize( container.clientWidth, container.clientHeight );
container.appendChild( renderer.domElement );
function renderScene() {
renderer.render(scene, camera);
}
function render(cameraToSync) {
root.quaternion.setFromRotationMatrix( cameraToSync.matrixWorldInverse );
renderScene();
}
function dispose() {
xAxis.dispose();
yAxis.dispose();
zAxis.dispose();
renderer.dispose();
}
return {
render, dispose
}
}

View file

@ -1,10 +1,11 @@
import DPR from 'dpr';
import {ArrowHelper, Vector3} from 'three';
import {ArrowHelper, CylinderBufferGeometry, Mesh, MeshBasicMaterial, Object3D, Vector3} from 'three';
import {createMeshLineGeometry} from './meshLine';
export function createArrow(length, arrowLength, arrowHead, axis, color, opacity, materialMixins) {
let arrow = new ArrowHelper(new Vector3().copy(axis), new Vector3(0, 0, 0), length, color, arrowLength, arrowHead);
arrow.updateMatrix();
arrow.line.material.linewidth = 1/DPR;
arrow.line.material.linewidth = 1 / DPR;
if (opacity !== undefined) {
arrow.line.material.opacity = opacity;
arrow.line.material.transparent = true;
@ -17,3 +18,63 @@ export function createArrow(length, arrowLength, arrowHead, axis, color, opacity
}
return arrow;
}
let tipGeometry = null;
let lineGeometry = null;
export class MeshArrow extends Object3D {
constructor(dir, color, length, headLength, headWidth, lineWidth) {
super();
if (color === undefined) color = 0xffff00;
if (length === undefined) length = 1;
if (headLength === undefined) headLength = 0.2 * length;
if (headWidth === undefined) headWidth = 0.2 * headLength;
if (lineWidth === undefined) lineWidth = 0.2 * headWidth;
if (!tipGeometry) {
tipGeometry = new CylinderBufferGeometry(0, 0.5, 1, 5, 1);
tipGeometry.translate(0, -0.5, 0);
lineGeometry = createMeshLineGeometry([[0, 0, 0], [0, 1, 0]], 1);
}
// dir is assumed to be normalized
let cone = new Mesh(tipGeometry, new MeshBasicMaterial({color}));
let line = new Mesh(lineGeometry, new MeshBasicMaterial({color}));
line.matrixAutoUpdate = false;
cone.matrixAutoUpdate = false;
this.add(line);
this.add(cone);
if (dir.y > 0.99999) {
this.quaternion.set(0, 0, 0, 1);
} else if (dir.y < -0.99999) {
this.quaternion.set(1, 0, 0, 0);
} else {
let axis = new Vector3();
let radians;
axis.set(dir.z, 0, -dir.x).normalize();
radians = Math.acos(dir.y);
this.quaternion.setFromAxisAngle(axis, radians);
}
line.scale.set(lineWidth, Math.max(0, length - headLength), lineWidth);
line.updateMatrix();
cone.scale.set(headWidth, headLength, headWidth);
cone.position.y = length;
cone.updateMatrix();
this.cone = cone;
this.line = line;
}
dispose() {
this.cone.material.dispose();
this.line.material.dispose();
}
}

View file

@ -0,0 +1,145 @@
import {Face3, Geometry, Vector3} from 'three';
export default function facetedCube(size, w) {
let d = size * 0.5;
let l = d - w;
const v = (x,y,z) => new Vector3(x,y,z);
let geom = new Geometry();
//front
geom.vertices.push(v(-l, -l, d));
geom.vertices.push(v(l, -l, d));
geom.vertices.push(v(l, l, d));
geom.vertices.push(v(-l, l, d));
//top
geom.vertices.push(v(-l, d, l));
geom.vertices.push(v(l, d, l));
geom.vertices.push(v(l, d, -l));
geom.vertices.push(v(-l, d, -l));
//back
geom.vertices.push(v(-l, -l, -d));
geom.vertices.push(v(l, -l, -d));
geom.vertices.push(v(l, l, -d));
geom.vertices.push(v(-l, l, -d));
//bottom
geom.vertices.push(v(-l, -d, l));
geom.vertices.push(v(l, -d, l));
geom.vertices.push(v(l, -d, -l));
geom.vertices.push(v(-l, -d, -l));
//left
geom.vertices.push(v(-d, -l, -l));
geom.vertices.push(v(-d, -l, l));
geom.vertices.push(v(-d, l, l));
geom.vertices.push(v(-d, l, -l));
//right
geom.vertices.push(v(d, -l, -l));
geom.vertices.push(v(d, -l, l));
geom.vertices.push(v(d, l, l));
geom.vertices.push(v(d, l, -l));
//front
geom.faces.push( new Face3( 0, 1, 2 ) );
geom.faces.push( new Face3( 2, 3, 0 ) );
//top
geom.faces.push( new Face3( 4, 5, 6 ) );
geom.faces.push( new Face3( 6, 7, 4 ) );
//back
geom.faces.push( new Face3( 10, 9, 8) );
geom.faces.push( new Face3( 8, 11, 10 ) );
//bottom
geom.faces.push( new Face3( 14, 13, 12) );
geom.faces.push( new Face3( 12, 15, 14 ) );
//left
geom.faces.push( new Face3( 16, 17, 18 ) );
geom.faces.push( new Face3( 18, 19, 16 ) );
// right
geom.faces.push( new Face3( 22, 21, 20 ) );
geom.faces.push( new Face3( 20, 23, 22 ) );
//front-top
geom.faces.push( new Face3( 4, 3, 2) );
geom.faces.push( new Face3( 2, 5, 4 ) );
//top-back
geom.faces.push( new Face3( 7, 6, 10) );
geom.faces.push( new Face3( 10, 11, 7 ) );
// back-bottom
geom.faces.push( new Face3( 8, 9, 14) );
geom.faces.push( new Face3( 14, 15, 8 ) );
//bottom-left
geom.faces.push( new Face3( 15, 12, 17) );
geom.faces.push( new Face3( 17, 16, 15 ) );
//bottom-right
geom.faces.push( new Face3( 20, 21, 13) );
geom.faces.push( new Face3( 13, 14, 20 ) );
//top-right
geom.faces.push( new Face3( 6, 5, 22) );
geom.faces.push( new Face3( 22, 23, 6 ) );
//top-left
geom.faces.push( new Face3( 19, 18, 4) );
geom.faces.push( new Face3( 4, 7, 19 ) );
//front-left
geom.faces.push( new Face3( 18, 17, 0) );
geom.faces.push( new Face3( 0, 3, 18 ) );
//front-bottom
geom.faces.push( new Face3( 12, 13, 1) );
geom.faces.push( new Face3( 1, 0, 12 ) );
//right-back
geom.faces.push( new Face3( 9, 10, 23) );
geom.faces.push( new Face3( 23, 20, 9 ) );
//front-right
geom.faces.push( new Face3( 21, 22, 2) );
geom.faces.push( new Face3( 2, 1, 21 ) );
//back-left
geom.faces.push( new Face3( 16, 19, 11) );
geom.faces.push( new Face3( 11, 8, 16 ) );
//front-top-left
geom.faces.push( new Face3( 4, 18, 3 ) );
//front-top-right
geom.faces.push( new Face3( 2, 22, 5 ) );
//top-right-back
geom.faces.push( new Face3( 23, 10, 6 ) );
// top-left-back
geom.faces.push( new Face3( 7, 11, 19 ) );
// front-left-bottom
geom.faces.push( new Face3( 17, 12, 0 ) );
// front-right-bottom
geom.faces.push( new Face3( 1, 13, 21 ) );
// back-right-bottom
geom.faces.push( new Face3( 20, 14, 9 ) );
// back-left-bottom
geom.faces.push( new Face3( 8, 15, 16 ) );
geom.computeFaceNormals();
return geom;
}

View file

@ -0,0 +1,45 @@
import * as vec from '../../../web/app/math/vec';
import {perpendicularVector} from '../../../web/app/math/math';
import {Face3, Geometry, Vector3} from 'three';
export function createMeshLineGeometry(points, width) {
const vThree = arr => new Vector3().fromArray(arr);
const geometry = new Geometry();
let base = null;
for (let i = 1; i < points.length; i++) {
let a = points[i - 1];
let b = points[i];
let ab = vec._normalize(vec.sub(b, a));
let dirs = [];
dirs[0] = perpendicularVector(ab);
dirs[1] = vec.cross(ab, dirs[0]);
dirs[2] = vec.negate(dirs[0]);
dirs[3] = vec.negate(dirs[1]);
dirs.forEach(d => vec._mul(d, width));
if (base === null) {
base = dirs.map(d => vec.add(a, d));
}
let lid = dirs.map(d => vec.add(b, d));
let off = geometry.vertices.length;
base.forEach(p => geometry.vertices.push(vThree(p)));
lid.forEach(p => geometry.vertices.push(vThree(p)));
base = lid;
[
[0, 4, 3],
[3, 4, 7],
[2, 3, 7],
[7, 6, 2],
[0, 1, 5],
[5, 4, 0],
[1, 2, 6],
[6, 5, 1],
].forEach(([a, b, c]) => geometry.faces.push(new Face3(a + off, b + off, c + off)));
}
geometry.computeFaceNormals();
return geometry;
}

View file

@ -4,12 +4,13 @@ import './utils/vectorThreeEnhancement';
export default class SceneSetUp {
constructor(container) {
constructor(container, onRendered) {
this.container = container;
this.scene = new THREE.Scene();
this.rootGroup = this.scene;
this.onRendered = onRendered;
this.setUpCamerasAndLights();
this.setUpControls();
@ -195,6 +196,7 @@ export default class SceneSetUp {
render() {
this.light.position.set(this.camera.position.x, this.camera.position.y, this.camera.position.z);
this.renderer.render(this.scene, this.camera);
this.onRendered();
};
domElement() {

View file

@ -0,0 +1,34 @@
import React from 'react';
import ReactDOM from 'react-dom';
import ls from './CameraControl.less';
import mapContext from 'ui/mapContext';
import cameraControlRenderer from 'scene/cameraControlRenderer';
@mapContext(({services, streams}) => ({
getCamera: () => services.viewer && services.viewer.sceneSetup.camera,
sceneRendered$: streams.cadScene.sceneRendered
}))
export default class CameraControl extends React.Component {
render () {
return <div className={ls.cameraControl} />
}
componentDidMount() {
let container = ReactDOM.findDOMNode(this);
this.renderer = cameraControlRenderer(container);
this.detacher = this.props.sceneRendered$.attach(() => {
let camera = this.props.getCamera();
if (camera) {
this.renderer.render(camera)
}
});
}
componentWillUnmount() {
this.detacher();
this.renderer.dispose();
}
}

View file

@ -0,0 +1,10 @@
@size: 80px;
.cameraControl {
top: -@size;
right: 0;
position: absolute;
width: @size;
height: @size;
pointer-events: none;
}

View file

@ -8,9 +8,9 @@ import WizardManager from '../../craft/wizard/components/WizardManager';
import FloatView from './FloatView';
import HistoryTimeline from '../../craft/ui/HistoryTimeline';
import SelectedModificationInfo from '../../craft/ui/SelectedModificationInfo';
import Explorer from './Explorer';
import BottomStack from './BottomStack';
import SketcherToolbars from './SketcherToolbars';
import CameraControl from './CameraControl';
export default class View3d extends React.Component {
@ -33,6 +33,7 @@ export default class View3d extends React.Component {
</Abs>
</Abs>
<BottomStack>
<CameraControl />
<HistoryTimeline />
<PlugableControlBar/>
</BottomStack>

View file

@ -57,7 +57,11 @@ export default function startApplication(callback) {
...applicationPlugins,
ViewSyncPlugin
];
let allPlugins = [...preUIPlugins, ...plugins];
defineStreams(allPlugins, context);
activatePlugins(preUIPlugins, context);
startReact(context, () => {
@ -68,6 +72,14 @@ export default function startApplication(callback) {
});
}
export function defineStreams(plugins, context) {
for (let plugin of plugins) {
if (plugin.defineStreams) {
plugin.defineStreams(context);
}
}
}
export function activatePlugins(plugins, context) {
for (let plugin of plugins) {
plugin.activate(context);

View file

@ -1,19 +1,24 @@
import Viewer, {CAMERA_MODE} from './viewer';
import CadScene from "./cadScene";
import {externalState} from '../../../../modules/lstream';
import {InPlaceSketcher} from '../sketch/inPlaceSketcher';
import Viewer from './viewer';
import CadScene from './cadScene';
import {externalState, stream} from 'lstream';
export function defineStreams({streams, services}) {
streams.cadScene = {
sceneRendered: stream(),
cameraMode: externalState(() => services.viewer.getCameraMode(), mode => viewer.setCameraMode(mode))
};
}
export function activate({streams, services}) {
let {dom} = services;
let viewer = new Viewer(dom.viewerContainer);
const onRendered = () => streams.cadScene.sceneRendered.next();
let viewer = new Viewer(dom.viewerContainer, onRendered);
services.viewer = viewer;
services.cadScene = new CadScene(viewer.sceneSetup.rootGroup);
streams.cadScene = {
cameraMode: externalState(() => viewer.getCameraMode(), mode => viewer.setCameraMode(mode))
};
// let sketcher3D = new Sketcher3D(dom.viewerContainer);
// services.viewer.setCameraMode(CAMERA_MODE.ORTHOGRAPHIC);

View file

@ -2,8 +2,8 @@ import SceneSetup from 'scene/sceneSetup';
export default class Viewer {
constructor(container) {
this.sceneSetup = new SceneSetup(container);
constructor(container, onRendered) {
this.sceneSetup = new SceneSetup(container, onRendered);
this.renderRequested = false;
}

View file

@ -1,20 +1,22 @@
import Vector from 'math/vector';
var ORIGIN = new Vector(0, 0, 0);
const freeze = Object.freeze;
var AXIS = {
X : new Vector(1, 0, 0),
Y : new Vector(0, 1, 0),
Z : new Vector(0, 0, 1)
};
const ORIGIN = freeze(new Vector(0, 0, 0));
var IDENTITY_BASIS = [AXIS.X, AXIS.Y, AXIS.Z];
const AXIS = freeze({
X : freeze(new Vector(1, 0, 0)),
Y : freeze(new Vector(0, 1, 0)),
Z : freeze(new Vector(0, 0, 1))
});
export const STANDARD_BASES = {
const IDENTITY_BASIS = Object.freeze([AXIS.X, AXIS.Y, AXIS.Z]);
export const STANDARD_BASES = freeze({
'XY': IDENTITY_BASIS,
'XZ': [AXIS.X, AXIS.Z, AXIS.Y],
'ZY': [AXIS.Z, AXIS.Y, AXIS.X]
};
});
/** @constructor */