UNPKG

@webviz/subsurface-viewer

Version:

3D visualization component for subsurface reservoir data

230 lines 12.2 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 { isEqual } from "lodash"; import { CompositeLayer } from "@deck.gl/core"; import { getModelMatrix } from "../utils/layerTools"; import config from "../../SubsurfaceConfig.json"; import { findConfig } from "../../utils/configTools"; import { loadDataArray } from "../../utils/serialize"; import PrivateMapLayer from "./privateMapLayer"; import { rotate } from "./utils"; import { makeFullMesh } from "./webworker"; import workerpool from "workerpool"; // init workerpool const workerPoolConfig = findConfig(config, "config/workerpool", "config/layer/MapLayer/workerpool"); const pool = workerpool.pool(Object.assign({ maxWorkers: 10, workerType: "web", }, workerPoolConfig)); function onTerminateWorker() { const stats = pool.stats(); if (stats.busyWorkers === 0 && stats.pendingTasks === 0) { pool.terminate(); } } /** * Will load data for the mesh and the properties. Both of which may be given as arrays (javascript or typed) * or as a URL to the data in binary format. * Return value: A promise with the data given as typed arrays. */ function loadMeshAndProperties(meshData, propertiesData) { return __awaiter(this, void 0, void 0, function* () { // Keep //const t0 = performance.now(); const mesh = yield loadDataArray(meshData, Float32Array); const properties = yield loadDataArray(propertiesData, Float32Array); // if (!isMesh && !isProperties) { // console.error("Error. One or both of texture and mesh must be given!"); // } // Keep this. // const t1 = performance.now(); // console.debug(`Task loading took ${(t1 - t0) * 0.001} seconds.`); return Promise.all([mesh, properties]); }); } const defaultProps = { "@@type": "MapLayer", name: "Map", id: "map3d-layer-float32", pickable: true, visible: true, bounds: { type: "object", value: null, false: true, compare: true }, colorMapRange: { type: "array" }, contours: [-1.0, -1.0], // If contour lines should follow depth or properties. isContoursDepth: true, gridLines: false, smoothShading: true, material: true, depthTest: true, ZIncreasingDownwards: true, }; export default class MapLayer extends CompositeLayer { get isLoaded() { var _a, _b; const subLayers = this.getSubLayers(); const isLoaded = super.isLoaded && subLayers.length > 0 && // Note super version differs only in this. It returns true on empty array. subLayers.every((layer) => layer.isLoaded); const isFinished = (_b = (_a = this.state) === null || _a === void 0 ? void 0 : _a["isFinishedLoading"]) !== null && _b !== void 0 ? _b : false; return isLoaded && isFinished; } rebuildData(reportBoundingBox) { var _a, _b; if (typeof this.props.meshUrl !== "undefined") { console.warn('"meshUrl" is deprecated. Use "meshData"'); } if (typeof this.props.propertiesUrl !== "undefined") { console.warn('"propertiesUrl" is deprecated. Use "propertiesData"'); } const meshData = (_a = this.props.meshData) !== null && _a !== void 0 ? _a : this.props.meshUrl; const propertiesData = (_b = this.props.propertiesData) !== null && _b !== void 0 ? _b : this.props.propertiesUrl; const p = loadMeshAndProperties(meshData, propertiesData); p.then(([meshData, propertiesData]) => { // Using inline web worker for calculating the triangle mesh from // loaded input data so not to halt the GUI thread. const webworkerParams = this.getWebworkerParams(meshData, propertiesData); pool.exec(makeFullMesh, [{ data: webworkerParams.params }]).then((e) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v; const [positions, normals, triangleIndices, vertexProperties, lineIndices, meshZValueRange, propertyValueRange,] = e; this.setState(Object.assign(Object.assign({}, this.state), { positions, normals, triangleIndices, vertexProperties, lineIndices, propertyValueRange, isFinishedLoading: true })); if (typeof this.props.reportBoundingBox !== "undefined" && reportBoundingBox) { const xinc = (_c = (_b = (_a = this.props.frame) === null || _a === void 0 ? void 0 : _a.increment) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : 0; const yinc = (_f = (_e = (_d = this.props.frame) === null || _d === void 0 ? void 0 : _d.increment) === null || _e === void 0 ? void 0 : _e[1]) !== null && _f !== void 0 ? _f : 0; const nnodes_x = (_j = (_h = (_g = this.props.frame) === null || _g === void 0 ? void 0 : _g.count) === null || _h === void 0 ? void 0 : _h[0]) !== null && _j !== void 0 ? _j : 2; // number of nodes in x direction const nnodes_y = (_m = (_l = (_k = this.props.frame) === null || _k === void 0 ? void 0 : _k.count) === null || _l === void 0 ? void 0 : _l[1]) !== null && _m !== void 0 ? _m : 2; const xMin = (_q = (_p = (_o = this.props.frame) === null || _o === void 0 ? void 0 : _o.origin) === null || _p === void 0 ? void 0 : _p[0]) !== null && _q !== void 0 ? _q : 0; const yMin = (_t = (_s = (_r = this.props.frame) === null || _r === void 0 ? void 0 : _r.origin) === null || _s === void 0 ? void 0 : _s[1]) !== null && _t !== void 0 ? _t : 0; const zMin = -meshZValueRange[0]; const xMax = xMin + xinc * (nnodes_x - 1); const yMax = yMin + yinc * (nnodes_y - 1); const zMax = -meshZValueRange[1]; // If map is rotated the bounding box must reflect that. const center = (_u = this.props.frame.rotPoint) !== null && _u !== void 0 ? _u : this.props.frame.origin; const rotDeg = (_v = this.props.frame.rotDeg) !== null && _v !== void 0 ? _v : 0; const rotRad = (rotDeg * (2.0 * Math.PI)) / 360.0; // Rotate x,y around "center" "rad" radians const [x0, y0] = rotate(xMin, yMin, center[0], center[1], rotRad); // eslint-disable-line const [x1, y1] = rotate(xMax, yMin, center[0], center[1], rotRad); // eslint-disable-line const [x2, y2] = rotate(xMax, yMax, center[0], center[1], rotRad); // eslint-disable-line const [x3, y3] = rotate(xMin, yMax, center[0], center[1], rotRad); // eslint-disable-line // Rotated bounds in x/y plane. const x_min = Math.min(x0, x1, x2, x3); const x_max = Math.max(x0, x1, x2, x3); const y_min = Math.min(y0, y1, y2, y3); const y_max = Math.max(y0, y1, y2, y3); this.props.reportBoundingBox({ layerBoundingBox: [ x_min, y_min, zMin, x_max, y_max, zMax, ], }); } onTerminateWorker(); }); }); } initializeState() { this.setState(Object.assign(Object.assign({}, this.state), { isFinishedLoading: false })); const reportBoundingBox = true; this.rebuildData(reportBoundingBox); } updateState({ props, oldProps, }) { const needs_reload = !isEqual(props.meshUrl, oldProps.meshUrl) || !isEqual(props.propertiesUrl, oldProps.propertiesUrl) || !isEqual(props.meshData, oldProps.meshData) || !isEqual(props.propertiesData, oldProps.propertiesData) || !isEqual(props.frame, oldProps.frame) || !isEqual(props.ZIncreasingDownwards, oldProps.ZIncreasingDownwards) || !isEqual(props.gridLines, oldProps.gridLines); if (needs_reload) { this.setState(Object.assign(Object.assign({}, this.state), { isFinishedLoading: false })); const reportBoundingBox = false; this.rebuildData(reportBoundingBox); } } renderLayers() { var _a, _b; if (Object.keys(this.state).length === 1) { // isFinishedLoading only in state return []; } const [minX, minY] = this.props.frame.origin; const center = (_a = this.props.frame.rotPoint) !== null && _a !== void 0 ? _a : [minX, minY]; const rotatingModelMatrix = getModelMatrix((_b = this.props.frame.rotDeg) !== null && _b !== void 0 ? _b : 0, center[0], center[1]); const isMesh = (typeof this.props.meshUrl !== "undefined" && this.props.meshUrl !== "") || (typeof this.props.meshData !== "undefined" && this.props.meshData !== ""); const isModelMatrix = typeof this.props.modelMatrix !== "undefined" && this.props.modelMatrix !== null; if (isModelMatrix) { rotatingModelMatrix.multiplyRight(this.props.modelMatrix); } const enableLighting = this.props.material !== false; const layer = new PrivateMapLayer(this.getSubLayerProps({ positions: this.state["positions"], normals: this.state["normals"], triangleIndices: this.state["triangleIndices"], vertexProperties: this.state["vertexProperties"], lineIndices: this.state["lineIndices"], pickable: this.props.pickable, modelMatrix: rotatingModelMatrix, contours: this.props.contours, gridLines: this.props.gridLines, isContoursDepth: !isMesh ? false : this.props.isContoursDepth, colormapName: this.props.colorMapName, colormapRange: this.props.colorMapRange, colormapClampColor: this.props.colorMapClampColor, colormapFunction: this.props.colorMapFunction, propertyValueRange: this.state["propertyValueRange"], material: this.props.material, smoothShading: this.props.smoothShading, depthTest: this.props.depthTest, ZIncreasingDownwards: this.props.ZIncreasingDownwards, enableLighting, })); return [layer]; } getWebworkerParams(meshData, propertiesData) { if (!meshData && !propertiesData) { throw new Error("Either mesh or properties or the both must be defined"); } const params = [ meshData, propertiesData, !!meshData, this.props.frame, this.props.smoothShading, this.props.gridLines, ]; const transferrables = [ meshData === null || meshData === void 0 ? void 0 : meshData.buffer, propertiesData === null || propertiesData === void 0 ? void 0 : propertiesData.buffer, ].filter((item) => !!item); if (transferrables.length > 0) { return { params, transferrables }; } return { params }; } } MapLayer.layerName = "MapLayer"; MapLayer.defaultProps = defaultProps; //# sourceMappingURL=mapLayer.js.map