import { Base } from './Base';
import {
defaultConfigScene,
initScene,
computeNearFarCamera,
} from '@ud-viz/utils_browser';
import { throttle } from '@ud-viz/utils_shared';
import * as itowns from 'itowns';
import * as THREE from 'three';
/**
* @typedef {object} PlanarOption
* @property {boolean} [hasItownsControls=false] - If true enable Itowns View Controls
* @property {boolean} [useItownsMainLoop=true] - Rendering is done in itowns.mainLoop
* @property {itowns.Coordinates} coordinates {@link http://www.itowns-project.org/itowns/docs/#api/Geographic/Coordinates Coordinates}
* @property {number} [heading=-50] - Camera heading placement
* @property {number} [range=3000] - Camera range placement
* @property {number} [tilt=10] - Camera tilt placement
* @property {number} [maxSubdivisionLevel=5] - Maximum subdivision level for PlanarLayer
* @property {number} [delayNotifyChange=2000] - delay in ms to notify itowns view change
* @property {import('@ud-viz/utils_browser').SceneConfig} sceneConfig - scene config
*/
/** @classdesc It's a class that extends the {@link Base} class and adds a PlanarView to it */
export class Planar extends Base {
/**
*
* @param {itowns.Extent} extent - Geographical bounding rectangle. {@link http://www.itowns-project.org/itowns/docs/#api/Geographic/Extent Extent}
* @param {PlanarOption} [options={}] - {@link PlanarOption}
*/
constructor(extent, options = {}) {
super(options, false); // do not init3D since itownsView will do it
const hasItownsControls = options.hasItownsControls || false;
const coordinates = extent.center(); // default coordinates are extent center
if (options.coordinates) {
if (options.coordinates.x)
coordinates.x = parseFloat(options.coordinates.x);
if (options.coordinates.y)
coordinates.y = parseFloat(options.coordinates.y);
}
const heading = options.heading || -50;
const range = options.range || 3000;
const tilt = options.tilt || 10;
const maxSubdivisionLevel = options.maxSubdivisionLevel || 5;
/**
* planar view
*
@type {itowns.PlanarView} */
this.itownsView = new itowns.PlanarView(this.domElementWebGL, extent, {
disableSkirt: false,
placement: {
coord: coordinates,
heading: heading,
range: range,
tilt: tilt,
},
maxSubdivisionLevel: maxSubdivisionLevel,
controls: {
handleCollision: false,
focusOnMouseOver: false,
focusOnMouseClick: false,
},
});
this.itownsView.controls.enabled = hasItownsControls;
// fill parent class attributes create by the itownsView
/** @type {THREE.Scene} */
this.scene = this.itownsView.scene;
/** @type {THREE.WebGLRenderer} */
this.renderer = this.itownsView.mainLoop.gfxEngine.renderer;
/** @type {THREE.PerspectiveCamera} */
this.camera = this.itownsView.camera.camera3D;
/** @type {import('../THREEUtil').SceneConfig} */
this.sceneConfig = options.sceneConfig || defaultConfigScene;
/** @type {THREE.DirectionalLight} */
this.directionalLight = initScene(
this.camera,
this.renderer,
this.scene,
this.sceneConfig
);
/** @type {Function} */
this.notifyChangeToItownsView = throttle(() => {
this.itownsView.notifyChange(this.camera);
}, options.delayNotifyChange || 2000); // => to load 3DTiles and trigger mainLoop event
let useItownsMainLoop = true;
if (options.useItownsMainLoop != undefined)
useItownsMainLoop = options.useItownsMainLoop;
if (useItownsMainLoop) {
// by default itownsView is rendering
// requester compute near far
this.itownsView.addFrameRequester(
itowns.MAIN_LOOP_EVENTS.AFTER_CAMERA_UPDATE,
() => {
const bb = new THREE.Box3().setFromObject(this.scene);
computeNearFarCamera(this.camera, bb.min, bb.max);
}
);
}
}
/**
* Disable/enable itowns rendering from itowns.mainLoop
*
* @param {boolean} value - true enable / false disable
*/
enableItownsViewRendering(value) {
if (value) {
this.itownsView.render = null;
} else {
this.itownsView.render = () => {};
}
}
/**
* Render scene3D + labels
*/
render() {
super.render();
this.notifyChangeToItownsView();
// render also label layers
if (this.isRendering && this.itownsView.tileLayer) {
this.itownsView.mainLoop.gfxEngine.label2dRenderer.render(
this.itownsView.tileLayer.object3d,
this.itownsView.camera.camera3D
);
}
}
/**
* Resize Frame3D
*/
onResize() {
super.onResize(false); // dont resize three variables since itownsResize is doing it
}
/**
* Dispose Frame3D
*/
dispose() {
super.dispose();
this.itownsView.dispose();
}
}