UNPKG

@webviz/subsurface-viewer

Version:

3D visualization component for subsurface reservoir data

310 lines 10.9 kB
import { Geometry, Model } from "@luma.gl/engine"; import { Layer, project, picking, UNIT } from "@deck.gl/core"; import { createPropertyData } from "../utils/layerTools"; import { utilities } from "../shader_modules"; import { precisionForTests } from "../shader_modules/test-precision/precisionForTests"; import fsShader from "./marker.fs.glsl"; import vsShader from "./marker.vs.glsl"; const normalizeColor = (color) => { if (!color) { return new Uint8Array([0, 0, 0, 255]); } if (color.length > 4) { return new Uint8Array(color.slice(0, 4)); } switch (color.length) { case 0: return new Uint8Array([0, 0, 0, 255]); case 1: return new Uint8Array([...color, 0, 0, 255]); case 2: return new Uint8Array([...color, 0, 255]); case 3: return new Uint8Array([...color, 255]); default: return color; } }; const defaultProps = { "@@type": "WellMarkersLayer", name: "Well Markers", id: "well-markers", shape: "circle", sizeUnits: "meters", visible: true, ZIncreasingDownwards: true, getPosition: { type: "accessor", value: (x) => { return x.position; }, }, getSize: { type: "accessor", value: (x) => { return x.size; }, }, getAzimuth: { type: "accessor", value: (x) => { return x.azimuth; }, }, getInclination: { type: "accessor", value: (x) => { return x.inclination; }, }, getColor: { type: "accessor", value: (x) => { return normalizeColor(x.color); }, }, getOutlineColor: { type: "accessor", value: (x) => { return normalizeColor(x.outlineColor); }, }, }; export default class WellMarkersLayer extends Layer { constructor(props) { super(props); this.shapes = new Map(); this.initShapes(); } initializeState() { this.getAttributeManager().addInstanced({ instancePositions: { size: 3, type: "float64", transition: true, accessor: "getPosition", }, instanceSizes: { size: 1, type: "float64", transition: true, accessor: "getSize", defaultValue: 1.0, }, instanceAzimuths: { size: 1, type: "float64", transition: true, accessor: "getAzimuth", defaultValue: 0, }, instanceInclinations: { size: 1, type: "float64", transition: true, accessor: "getInclination", defaultValue: 0, }, instanceColors: { size: 4, type: "uint8", transition: true, accessor: "getColor", defaultValue: [255, 0, 0, 255], }, instanceOutlineColors: { size: 4, type: "uint8", transition: true, accessor: "getOutlineColor", defaultValue: [255, 0, 255, 255], }, }); const models = this._createModels(); this.setState({ shapeModel: models[0], outlineModel: models[1] }); } updateState(params) { var _a, _b; super.updateState(params); if (params.changeFlags.extensionsChanged || params.changeFlags.propsChanged) { const oldShapeModel = (_a = this.state) === null || _a === void 0 ? void 0 : _a["shapeModel"]; oldShapeModel.destroy(); const oldOutlineModel = (_b = this.state) === null || _b === void 0 ? void 0 : _b["outlineModel"]; oldOutlineModel.destroy(); const models = this._createModels(); this.setState(Object.assign(Object.assign({}, this.state), { shapeModel: models[0], outlineModel: models[1] })); this.getAttributeManager().invalidateAll(); } } getModels() { if (this.state["shapeModel"] && this.state["outlineModel"]) { return [ this.state["shapeModel"], this.state["outlineModel"], ]; } return []; } // eslint-disable-next-line @typescript-eslint/no-explicit-any draw(args) { if (!this.state["shapeModel"]) { return; } const models = this.getModels(); if (models.length && models.length < 2) { return; } models[0].shaderInputs.setProps(Object.assign(Object.assign({}, args.uniforms), { wellMarkers: { useOutlineColor: false, sizeUnits: UNIT[this.props.sizeUnits], ZIncreasingDownwards: this.props.ZIncreasingDownwards, } })); models[0].draw(args.context.renderPass); models[1].shaderInputs.setProps(Object.assign(Object.assign({}, args.uniforms), { wellMarkers: { useOutlineColor: true, sizeUnits: UNIT[this.props.sizeUnits], ZIncreasingDownwards: this.props.ZIncreasingDownwards, } })); models[1].draw(args.context.renderPass); } getPickingInfo({ info }) { var _a; if (!info.color) { return info; } const layer_properties = []; const markerIndex = this.decodePickingColor(info.color); const markerData = this.props.data; if (markerIndex >= 0 && markerIndex < markerData.length) { layer_properties.push(createPropertyData("Azimuth", markerData[markerIndex].azimuth)); layer_properties.push(createPropertyData("Inclination", markerData[markerIndex].inclination)); } if (typeof ((_a = info.coordinate) === null || _a === void 0 ? void 0 : _a[2]) !== "undefined") { let depth = info.coordinate[2]; depth = this.props.ZIncreasingDownwards ? -depth : depth; layer_properties.push(createPropertyData("Depth", depth)); } return Object.assign(Object.assign({}, info), { properties: layer_properties }); } getShaders() { return super.getShaders({ vs: vsShader, fs: fsShader, modules: [ project, picking, utilities, wellMarkersUniforms, precisionForTests, ], }); } initShapes() { const triangle_positions = [ -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0, ]; const triangle_outline = [ -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0, -1.0, -1.0, 0.0, ]; const circle_positions = []; const circle_outline = []; const N = 32; const R = 1.0; for (let i = 0; i <= N; ++i) { const angle = ((2.0 * Math.PI) / N) * i; circle_positions.push(R * Math.cos(angle)); circle_positions.push(R * Math.sin(angle)); circle_positions.push(0.0); // push center again to represent a circle with a triangle strip circle_positions.push(0.0); circle_positions.push(0.0); circle_positions.push(0.0); circle_outline.push(R * Math.cos(angle)); circle_outline.push(R * Math.sin(angle)); circle_outline.push(0.0); } const square_positions = [ -1.0, 1.0, 0.0, 1.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, ]; const square_outline = [ -1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0, -1.0, 1.0, 0.0, ]; this.shapes.set("triangle", { drawMode: "triangle-list", positions: new Float32Array(triangle_positions), outline: new Float32Array(triangle_outline), }); this.shapes.set("circle", { drawMode: "triangle-strip", positions: new Float32Array(circle_positions), outline: new Float32Array(circle_outline), }); this.shapes.set("square", { drawMode: "triangle-strip", positions: new Float32Array(square_positions), outline: new Float32Array(square_outline), }); } _createModels() { const device = this.context.device; const shape = this.shapes.get(this.props.shape); if (!shape) { return this._createEmptyModels(); } const shaders = this.getShaders(); const shapeModel = new Model(device, Object.assign(Object.assign({ id: `${this.props.id}-mesh` }, shaders), { bufferLayout: this.getAttributeManager().getBufferLayouts(), geometry: new Geometry({ topology: shape.drawMode, attributes: { positions: { size: 3, value: shape.positions }, }, }), isInstanced: true, instanceCount: this.getNumInstances() })); const outlineModel = new Model(device, Object.assign(Object.assign({ id: `${this.props.id}-outline` }, shaders), { bufferLayout: this.getAttributeManager().getBufferLayouts(), geometry: new Geometry({ topology: "line-strip", attributes: { positions: { size: 3, value: shape.outline }, }, }), isInstanced: true, instanceCount: this.getNumInstances() })); return [shapeModel, outlineModel]; } _createEmptyModels() { return [ new Model(this.context.device, { id: `${this.props.id}-empty-mesh`, vs: vsShader, fs: fsShader, isInstanced: true, instanceCount: 0, }), new Model(this.context.device, { id: `${this.props.id}-empty-outline`, vs: vsShader, fs: fsShader, isInstanced: true, instanceCount: 0, }), ]; } } const wellMarkersUniformsBlock = /*glsl*/ `\ uniform wellMarkersUniforms { int sizeUnits; bool useOutlineColor; bool ZIncreasingDownwards; } wellMarkers; `; // NOTE: this must exactly the same name than in the uniform block const wellMarkersUniforms = { name: "wellMarkers", vs: wellMarkersUniformsBlock, fs: undefined, uniformTypes: { sizeUnits: "f32", useOutlineColor: "u32", ZIncreasingDownwards: "u32", }, }; WellMarkersLayer.layerName = "WellMarkersLayer"; WellMarkersLayer.defaultProps = defaultProps; //# sourceMappingURL=wellMarkersLayer.js.map