@webviz/subsurface-viewer
Version:
3D visualization component for subsurface reservoir data
230 lines • 12.2 kB
JavaScript
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