UNPKG

@giro3d/giro3d

Version:

A JS/WebGL framework for 3D geospatial data visualization

111 lines (110 loc) 3.53 kB
/* * Copyright (c) 2015-2018, IGN France. * Copyright (c) 2018-2026, Giro3D team. * SPDX-License-Identifier: MIT */ import { Mesh, MeshBasicMaterial, Sphere, SphereGeometry } from 'three'; import { isEntity3D } from '../entities/Entity3D'; import { isShape } from '../entities/Shape'; import DrawTool from '../interactions/DrawTool'; import SunExposure from '../interactions/SunExposure'; import Panel from './Panel'; export default class SunExposurePanel extends Panel { radius = 100; resolution = 10; temporalResolution = 10; helpers = false; date = '2025-06-21'; timeRange = '8-18'; _drawTool = null; _center = null; _sphere = null; _helper = null; _entity = null; _sunExposure = null; updateBoundingSphere() { if (this._center == null) { return; } this._sphere = new Sphere(this._center, this.radius); if (this._helper == null) { const helper = new Mesh(new SphereGeometry(), new MeshBasicMaterial({ color: 'cyan', wireframe: true, opacity: 0.3 })); this._helper = helper; this.instance.add(helper); } const r = this.radius; this._helper.position.copy(this._center); this._helper.scale.set(r, r, r); this._helper.updateMatrixWorld(true); this.instance.notifyChange(); } constructor(parentGui, instance) { super(parentGui, instance, 'SunExposure'); const updateSphere = this.updateBoundingSphere.bind(this); this.addController(this, 'radius').min(1).max(10000).onChange(updateSphere); this.addController(this, 'setCenter'); this.addController(this, 'resolution').min(0.1).max(1000); this.addController(this, 'helpers').name('Show helpers'); this.addController(this, 'date'); this.addController(this, 'timeRange').name('Start/End hours (UTC)'); this.addController(this, 'temporalResolution').name('Temporal resolution (minutes)').min(10).max(120); this.addController(this, 'compute'); this.addController(this, 'cleanup'); } async compute() { if (this._sphere == null) { console.error('No sphere set for computation'); return; } this.cleanup(); const [startTime, endTime] = this.timeRange.split('-').map(x => Number.parseInt(x)); const date = new Date(this.date); const yyyy = date.getUTCFullYear(); const mm = date.getUTCMonth(); const dd = date.getUTCDay(); const start = new Date(Date.UTC(yyyy, mm, dd, startTime)); const end = new Date(Date.UTC(yyyy, mm, dd, endTime)); const objects = this.instance.getEntities(e => { return isEntity3D(e) && !isShape(e); }); const tool = new SunExposure({ instance: this.instance, objects, start, end, temporalResolution: this.temporalResolution * 60, limits: this._sphere, showHelpers: this.helpers, spatialResolution: this.resolution }); this._sunExposure = tool; const results = await tool.compute(); this._entity = results.entity; } cleanup() { if (this._entity != null) { this.instance.remove(this._entity); this._entity = null; } if (this._sunExposure != null) { this._sunExposure.dispose(); this._sunExposure = null; } } async setCenter() { if (this._drawTool == null) { this._drawTool = new DrawTool({ instance: this.instance }); } const shape = await this._drawTool.createPoint(); if (shape != null) { this._center = shape.points[0]; } this.updateBoundingSphere(); } }