UNPKG

@webviz/subsurface-viewer

Version:

3D visualization component for subsurface reservoir data

309 lines (306 loc) 13.9 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { project32 } from "@deck.gl/core"; import { BitmapLayer } from "@deck.gl/layers"; import * as png from "@vivaxy/png"; import { getModelMatrix } from "../utils/layerTools"; import { getImageData, } from "../utils/colormapTools"; import { decodeRGB } from "../utils/propertyMapTools"; import fsColormap from "./colormap.fs.glsl"; import { precisionForTests } from "../shader_modules/test-precision/precisionForTests"; const defaultProps = { "@@type": "ColormapLayer", name: "Property map", id: "colormap-layer", pickable: true, visible: true, valueRange: { type: "array", value: [0, 1] }, colorMapRange: { type: "array" }, valueDecoder: { rgbScaler: [1, 1, 1], // By default, scale the [0, 256*256*256-1] decoded values to [0, 1] floatScaler: 1.0 / (256.0 * 256.0 * 256.0 - 1.0), offset: 0, step: 0, }, rotDeg: 0, colorMapName: "Rainbow", contours: false, hillshading: false, contourReferencePoint: 0, contourInterval: 50, // 50 meter by default heightMapUrl: "", }; export default class ColormapLayer extends BitmapLayer { initializeState() { super.initializeState(); const createPropertyTexture = () => __awaiter(this, void 0, void 0, function* () { const response = yield fetch(this.props.heightMapUrl); if (!response.ok) { console.error("Could not load ", this.props.heightMapUrl); } else { const blob = yield response.blob(); const contentType = response.headers.get("content-type"); const isPng = contentType === "image/png"; if (isPng) { const heightMapTexture = yield new Promise((resolve) => { const fileReader = new FileReader(); fileReader.readAsArrayBuffer(blob); fileReader.onload = () => { const arrayBuffer = fileReader.result; const imgData = png.decode(arrayBuffer); const w = imgData.width; const h = imgData.height; const data = imgData.data; // array of int's const n = data.length; const buffer = new ArrayBuffer(n); const view = new DataView(buffer); for (let i = 0; i < n; i++) { view.setUint8(i, data[i]); } const array = new Uint8Array(buffer); const propertyTexture = this.context.device.createTexture({ sampler: { addressModeU: "clamp-to-edge", addressModeV: "clamp-to-edge", minFilter: "linear", magFilter: "linear", }, width: w, height: h, format: "rgba8unorm", data: array, }); resolve(propertyTexture); }; }); this.setState(Object.assign(Object.assign({}, this.state), { heightMapTexture })); } } }); createPropertyTexture(); } setShaderModuleProps(...props) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; if (!this.isLoaded) { if (typeof this.props.reportBoundingBox !== "undefined") { const xMin = this.props.bounds[0]; const yMin = this.props.bounds[1]; const zMin = 1; const xMax = this.props.bounds[2]; const yMax = this.props.bounds[3]; const zMax = -1; this.props.reportBoundingBox({ layerBoundingBox: [xMin, yMin, zMin, xMax, yMax, zMax], }); } } // Set property for modelMatrix. const m = getModelMatrix(this.props.rotDeg, this.props.bounds[0], // Rotate around upper left corner of bounds this.props.bounds[3]); for (const model of this.getModels()) { const isDefined = ((_b = (_a = props[0]) === null || _a === void 0 ? void 0 : _a.project) === null || _b === void 0 ? void 0 : _b.modelMatrix) !== undefined; if (isDefined) { props[0]["project"].modelMatrix = m; } model.shaderInputs.setProps(...props); } // Properties for local shader module. const valueRangeMin = (_c = this.props.valueRange[0]) !== null && _c !== void 0 ? _c : 0.0; const valueRangeMax = (_d = this.props.valueRange[1]) !== null && _d !== void 0 ? _d : 1.0; // If specified, color map will extend from colormapRangeMin to colormapRangeMax. // Otherwise it will extend from valueRangeMin to valueRangeMax. const colormapRangeMin = (_f = (_e = this.props.colorMapRange) === null || _e === void 0 ? void 0 : _e[0]) !== null && _f !== void 0 ? _f : valueRangeMin; const colormapRangeMax = (_h = (_g = this.props.colorMapRange) === null || _g === void 0 ? void 0 : _g[1]) !== null && _h !== void 0 ? _h : valueRangeMax; const colormapTexture = this.context.device.createTexture({ width: 256, height: 1, format: "rgb8unorm-webgl", data: getImageData((_j = this.props.colorMapFunction) !== null && _j !== void 0 ? _j : { colormapName: this.props.colorMapName, colorTables: this.context.userData .colorTables, }), }); // eslint-disable-next-line // @ts-ignore let heightMapTexture = this.state.heightMapTexture; const isHeightMapTextureDefined = typeof heightMapTexture !== "undefined"; if (!isHeightMapTextureDefined) { // Create a dummy texture heightMapTexture = this.context.device.createTexture({ sampler: { addressModeU: "clamp-to-edge", addressModeV: "clamp-to-edge", minFilter: "linear", magFilter: "linear", }, width: 1, height: 1, format: "rgba8unorm", data: new Uint8Array([1, 1, 1, 1]), }); } const heightValueRangeMin = (_l = (_k = this.props.heightValueRange) === null || _k === void 0 ? void 0 : _k[0]) !== null && _l !== void 0 ? _l : valueRangeMin; const heightValueRangeMax = (_o = (_m = this.props.heightValueRange) === null || _m === void 0 ? void 0 : _m[1]) !== null && _o !== void 0 ? _o : valueRangeMax; (_p = this.state.model) === null || _p === void 0 ? void 0 : _p.setBindings({ colormapTexture, heightMapTexture }); const bitmapResolution = this.props.image ? [ this.props.image.width, this.props.image.height, ] : [1, 1]; const contours = this.props.contours; const hillshading = this.props.hillshading; const contourReferencePoint = this.props.contourReferencePoint; const contourInterval = this.props.contourInterval; const isClampColor = this.props.colorMapClampColor !== undefined && this.props.colorMapClampColor !== true && this.props.colorMapClampColor !== false; let colormapClampColor = isClampColor ? this.props.colorMapClampColor : [0, 0, 0]; colormapClampColor = colormapClampColor.map((x) => (x !== null && x !== void 0 ? x : 0) / 255); const isColormapClampColorTransparent = this.props.colorMapClampColor === false; super.setShaderModuleProps({ map: { valueRangeMin, valueRangeMax, colormapRangeMin, colormapRangeMax, contours, hillshading, bitmapResolution, contourReferencePoint, contourInterval, isClampColor, colormapClampColor, isColormapClampColorTransparent, isHeightMapTextureDefined, heightValueRangeMin, heightValueRangeMax, rgbScaler: this.props.valueDecoder.rgbScaler, floatScaler: this.props.valueDecoder.floatScaler, offset: this.props.valueDecoder.offset, step: this.props.valueDecoder.step, }, }); } getShaders() { const parentShaders = super.getShaders(); // use object.assign to make sure we don't overwrite existing fields like `vs`, `modules`... return Object.assign({}, parentShaders, { fs: fsColormap, modules: [ ...parentShaders.modules, project32, map2DUniforms, precisionForTests, ], }); } getPickingInfo({ info, }) { if (!info.color) { return info; } const mergedDecoder = Object.assign(Object.assign({}, defaultProps.valueDecoder), this.props.valueDecoder); // The picked color is the one in raw image, not the one after colormapping. // We just need to decode that RGB color into a property float value. const val = decodeRGB(info.color, mergedDecoder, this.props.valueRange); if (info.coordinate) { info.coordinate[2] = NaN; // disable z value in 2D map; } return Object.assign(Object.assign({}, info), { // Picking color doesn't represent object index in this layer. // For more details, see https://deck.gl/docs/developer-guide/custom-layers/picking index: 0, propertyValue: val }); } getLegendData() { var _a, _b, _c, _d, _e, _f; const valueRangeMin = (_a = this.props.valueRange[0]) !== null && _a !== void 0 ? _a : 0.0; const valueRangeMax = (_b = this.props.valueRange[1]) !== null && _b !== void 0 ? _b : 1.0; // If specified color map will extend from colormapRangeMin to colormapRangeMax. // Otherwise it will extend from valueRangeMin to valueRangeMax. const min = (_d = (_c = this.props.colorMapRange) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : valueRangeMin; const max = (_f = (_e = this.props.colorMapRange) === null || _e === void 0 ? void 0 : _e[1]) !== null && _f !== void 0 ? _f : valueRangeMax; return { discrete: false, valueRange: [min, max], colorName: this.props.colorMapName, title: "PropertyMapLayer", colorMapFunction: this.props.colorMapFunction, }; } } ColormapLayer.layerName = "ColormapLayer"; ColormapLayer.defaultProps = defaultProps; // local shader module for the uniforms const map2DUniformsBlock = /*glsl*/ `\ uniform mapUniforms { float valueRangeMin; float valueRangeMax; float colormapRangeMin; float colormapRangeMax; vec2 bitmapResolution; bool contours; bool hillshading; float contourReferencePoint; float contourInterval; bool isClampColor; vec3 colormapClampColor; bool isColormapClampColorTransparent; bool isHeightMapTextureDefined; float heightValueRangeMin; float heightValueRangeMax; vec3 rgbScaler; // r, g and b multipliers float floatScaler; // value multiplier float offset; // translation of the r, g, b sum float step; // discretize the value in a number of } map; float decode_rgb2float(vec3 rgb) { rgb *= map.rgbScaler * vec3(16711680.0, 65280.0, 255.0); //255*256*256, 255*256, 255 float value = (rgb.r + rgb.g + rgb.b + map.offset) * map.floatScaler; // Value must be in [0, 1] and step in (0, 1] if (map.step > 0.0) { value = floor(value / map.step + 0.5) * map.step; } return value; } `; // NOTE: this must exactly the same name as in the uniform block const map2DUniforms = { name: "map", vs: map2DUniformsBlock, fs: map2DUniformsBlock, uniformTypes: { valueRangeMin: "f32", valueRangeMax: "f32", colormapRangeMin: "f32", colormapRangeMax: "f32", bitmapResolution: "vec2<f32>", contours: "u32", hillshading: "u32", contourReferencePoint: "f32", contourInterval: "f32", isClampColor: "u32", colormapClampColor: "vec3<f32>", isColormapClampColorTransparent: "u32", isHeightMapTextureDefined: "u32", heightValueRangeMin: "f32", heightValueRangeMax: "f32", rgbScaler: "vec3<f32>", floatScaler: "f32", offset: "f32", step: "f32", }, }; //# sourceMappingURL=colormapLayer.js.map