Skip to content

Commit

Permalink
Allow changing camera settings (#204)
Browse files Browse the repository at this point in the history
* Allow changing camera settings

* Linter

* Update Playwright Snapshots

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
martinRenou and github-actions[bot] committed Jun 29, 2023
1 parent 28f8892 commit e461738
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ export class MainMenu extends MenuBar {
type: 'command',
command: CommandIDs.updateAxes
});
menu.addItem({
type: 'command',
command: CommandIDs.updateCameraSettings
});

const themeMenu = new RankedMenu({
commands: this._commands,
Expand Down
54 changes: 54 additions & 0 deletions packages/jupytercad-extension/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,36 @@ const EXPLODED_VIEW_FORM = {
}
};

const CAMERA_FORM = {
title: 'Camera Settings',
schema: {
type: 'object',
required: ['Type'],
additionalProperties: false,
properties: {
Type: {
title: 'Projection',
description: 'The projection type',
type: 'string',
enum: ['Perspective', 'Orthographic']
}
}
},
default: (panel: JupyterCadPanel) => {
return {
Type: panel.cameraSettings?.type ?? 'Perspective'
};
},
syncData: (panel: JupyterCadPanel) => {
return (props: IDict) => {
const { Type } = props;
panel.cameraSettings = {
type: Type
};
};
}
};

/**
* Add the FreeCAD commands to the application's command registry.
*/
Expand Down Expand Up @@ -551,6 +581,29 @@ export function addCommands(
await dialog.launch();
}
});

commands.addCommand(CommandIDs.updateCameraSettings, {
label: trans.__('Camera Settings'),
isEnabled: () => Boolean(tracker.currentWidget),
iconClass: 'fa fa-camera',
execute: async () => {
const current = tracker.currentWidget;

if (!current) {
return;
}

const dialog = new FormDialog({
context: current.context,
title: CAMERA_FORM.title,
schema: CAMERA_FORM.schema,
sourceData: CAMERA_FORM.default(current.content),
syncData: CAMERA_FORM.syncData(current.content),
cancelButton: true
});
await dialog.launch();
}
});
}

/**
Expand All @@ -575,6 +628,7 @@ export namespace CommandIDs {

export const updateAxes = 'jupytercad:updateAxes';
export const updateExplodedView = 'jupytercad:updateExplodedView';
export const updateCameraSettings = 'jupytercad:updateCameraSettings';
}

namespace Private {
Expand Down
63 changes: 56 additions & 7 deletions packages/jupytercad-extension/src/mainview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { v4 as uuid } from 'uuid';

import {
AxeHelper,
CameraSettings,
ExplodedView,
IAnnotation,
IDict,
Expand All @@ -32,7 +33,6 @@ import {
} from './types';
import { FloatingAnnotation } from './annotation/view';
import { getCSSVariableColor, throttle } from './tools';
import { Vector2 } from 'three';

// Apply the BVH extension
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
Expand Down Expand Up @@ -238,9 +238,9 @@ export class MainView extends React.Component<IProps, IStates> {

this._scene.add(new THREE.AmbientLight(0xffffff, 0.5)); // soft white light

const light = new THREE.PointLight(0xffffff, 1);
this._cameraLight = new THREE.PointLight(0xffffff, 1);

this._camera.add(light);
this._camera.add(this._cameraLight);

this._scene.add(this._camera);

Expand Down Expand Up @@ -367,8 +367,15 @@ export class MainView extends React.Component<IProps, IStates> {
this.divRef.current.clientHeight,
false
);
this._camera.aspect =
this.divRef.current.clientWidth / this.divRef.current.clientHeight;
if (this._camera.type === 'PerspectiveCamera') {
this._camera.aspect =
this.divRef.current.clientWidth / this.divRef.current.clientHeight;
} else {
this._camera.left = this.divRef.current.clientWidth / -2;
this._camera.right = this.divRef.current.clientWidth / 2;
this._camera.top = this.divRef.current.clientHeight / 2;
this._camera.bottom = this.divRef.current.clientHeight / -2;
}
this._camera.updateProjectionMatrix();
}
};
Expand Down Expand Up @@ -406,7 +413,7 @@ export class MainView extends React.Component<IProps, IStates> {

copy.project(this._camera);

return new Vector2(
return new THREE.Vector2(
(0.5 + copy.x / 2) * canvas.width,
(0.5 - copy.y / 2) * canvas.height
);
Expand Down Expand Up @@ -986,6 +993,16 @@ export class MainView extends React.Component<IProps, IStates> {
this._setupExplodedView();
}
}

if (change.key === 'cameraSettings') {
const cameraSettings = change.newValue as CameraSettings | undefined;

if (change.type !== 'remove' && cameraSettings) {
this._cameraSettings = cameraSettings;

this._updateCamera();
}
}
}

private _setupExplodedView() {
Expand Down Expand Up @@ -1028,6 +1045,36 @@ export class MainView extends React.Component<IProps, IStates> {
}
}

private _updateCamera() {
const position = new THREE.Vector3().copy(this._camera.position);
const up = new THREE.Vector3().copy(this._camera.up);

this._camera.remove(this._cameraLight);
this._scene.remove(this._camera);

if (this._cameraSettings.type === 'Perspective') {
this._camera = new THREE.PerspectiveCamera(90, 2, 0.1, 1000);
} else {
const width = this.divRef.current?.clientWidth || 0;
const height = this.divRef.current?.clientHeight || 0;

this._camera = new THREE.OrthographicCamera(
width / -2,
width / 2,
height / 2,
height / -2
);
}

this._camera.add(this._cameraLight);

this._scene.add(this._camera);
this._controls.object = this._camera;

this._camera.position.copy(position);
this._camera.up.copy(up);
}

private _computeExplodedState(mesh: BasicMesh) {
const center = new THREE.Vector3();
this._boundingGroup.getCenter(center);
Expand Down Expand Up @@ -1179,9 +1226,11 @@ export class MainView extends React.Component<IProps, IStates> {
// TODO Make this a shared property
private _explodedView: ExplodedView = { enabled: false, factor: 0 };
private _explodedViewLinesHelperGroup: THREE.Group | null = null; // The list of line helpers for the exploded view
private _cameraSettings: CameraSettings = { type: 'Perspective' };

private _scene: THREE.Scene; // Threejs scene
private _camera: THREE.PerspectiveCamera; // Threejs camera
private _camera: THREE.PerspectiveCamera | THREE.OrthographicCamera; // Threejs camera
private _cameraLight: THREE.PointLight;
private _raycaster = new THREE.Raycaster();
private _renderer: THREE.WebGLRenderer; // Threejs render
private _requestID: any = null; // ID of window.requestAnimationFrame
Expand Down
8 changes: 8 additions & 0 deletions packages/jupytercad-extension/src/toolbar/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ export class ToolbarWidget extends Toolbar {
commands: options.commands
})
);
this.addItem(
'Camera Settings',
new CommandToolbarButton({
id: CommandIDs.updateCameraSettings,
label: '',
commands: options.commands
})
);

this.addItem('spacer', Toolbar.createSpacerItem());

Expand Down
7 changes: 7 additions & 0 deletions packages/jupytercad-extension/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ export type ExplodedView = {
factor: number;
};

/**
* The state of the camera
*/
export type CameraSettings = {
type: 'Perspective' | 'Orthographic';
};

export interface IJcadObjectDocChange {
objectChange?: Array<{
name: string;
Expand Down
9 changes: 9 additions & 0 deletions packages/jupytercad-extension/src/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { MainView } from './mainview';
import {
AxeHelper,
ExplodedView,
CameraSettings,
IJupyterCadModel,
IJupyterCadWidget
} from './types';
Expand Down Expand Up @@ -84,6 +85,14 @@ export class JupyterCadPanel extends ReactWidget {
this._view.set('explodedView', value || null);
}

get cameraSettings(): CameraSettings | undefined {
return this._view.get('cameraSettings') as CameraSettings | undefined;
}

set cameraSettings(value: CameraSettings | undefined) {
this._view.set('cameraSettings', value || null);
}

deleteAxes(): void {
this._view.delete('axes');
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit e461738

Please sign in to comment.