UNPKG

@webviz/subsurface-viewer

Version:

3D visualization component for subsurface reservoir data

764 lines 32.6 kB
import { COORDINATE_SYSTEM, Layer, OrthographicViewport, project32, } from "@deck.gl/core"; import { load } from "@loaders.gl/core"; import { ImageLoader } from "@loaders.gl/images"; import { Geometry, Model } from "@luma.gl/engine"; import { vec4 } from "gl-matrix"; import fontAtlasPng from "./font-atlas.png"; import { precisionForTests } from "../shader_modules/test-precision/precisionForTests"; import labelFragmentShader from "./label.fs.glsl"; import labelVertexShader from "./label.vs.glsl"; import lineFragmentShader from "./line.fs.glsl"; import lineVertexShader from "./line.vs.glsl"; var TEXT_ANCHOR; (function (TEXT_ANCHOR) { TEXT_ANCHOR[TEXT_ANCHOR["start"] = 0] = "start"; TEXT_ANCHOR[TEXT_ANCHOR["middle"] = 1] = "middle"; TEXT_ANCHOR[TEXT_ANCHOR["end"] = 2] = "end"; })(TEXT_ANCHOR || (TEXT_ANCHOR = {})); var ALIGNMENT_BASELINE; (function (ALIGNMENT_BASELINE) { ALIGNMENT_BASELINE[ALIGNMENT_BASELINE["top"] = 1] = "top"; ALIGNMENT_BASELINE[ALIGNMENT_BASELINE["center"] = 0] = "center"; ALIGNMENT_BASELINE[ALIGNMENT_BASELINE["bottom"] = -1] = "bottom"; })(ALIGNMENT_BASELINE || (ALIGNMENT_BASELINE = {})); var ViewSide; (function (ViewSide) { ViewSide[ViewSide["Left"] = 0] = "Left"; ViewSide[ViewSide["Right"] = 1] = "Right"; ViewSide[ViewSide["Bottom"] = 2] = "Bottom"; ViewSide[ViewSide["Top"] = 3] = "Top"; })(ViewSide || (ViewSide = {})); const zDepthAxes = 0; const tickLineLength = 10; const defaultProps = { "@@type": "Axes2DLayer", name: "Axes2D", id: "axes2d-layer", visible: true, coordinateSystem: COORDINATE_SYSTEM.CARTESIAN, minimalMarginH: 80, minimalMarginV: 30, marginH: 80, marginV: 30, isLeftRuler: true, isRightRuler: false, isBottomRuler: true, isTopRuler: false, labelFontSizePt: 9, }; // FONT ATLAS const font_width = 86; const yh = 97; const fontInfo = { letterHeight: 92, spaceWidth: 0, spacing: -1, textureWidth: 1714, textureHeight: 200, glyphInfos: { A: { x: 0, y: 0, width: font_width }, B: { x: font_width, y: 0, width: font_width }, C: { x: 2 * font_width, y: 0, width: font_width }, D: { x: 3 * font_width, y: 0, width: font_width }, E: { x: 4 * font_width, y: 0, width: font_width }, F: { x: 5 * font_width, y: 0, width: font_width }, G: { x: 6 * font_width, y: 0, width: font_width }, H: { x: 7 * font_width, y: 0, width: font_width }, I: { x: 8 * font_width, y: 0, width: font_width }, J: { x: 9 * font_width, y: 0, width: font_width }, K: { x: 10 * font_width, y: 0, width: font_width }, L: { x: 11 * font_width, y: 0, width: font_width }, M: { x: 12 * font_width, y: 0, width: font_width }, N: { x: 13 * font_width, y: 0, width: font_width }, O: { x: 14 * font_width, y: 0, width: font_width }, P: { x: 15 * font_width, y: 0, width: font_width }, Q: { x: 16 * font_width, y: 0, width: font_width }, R: { x: 17 * font_width, y: 0, width: font_width }, S: { x: 18 * font_width, y: 0, width: font_width }, T: { x: 19 * font_width, y: 0, width: font_width }, U: { x: 0, y: yh, width: font_width }, V: { x: font_width, y: yh, width: font_width }, W: { x: 2 * font_width, y: yh, width: font_width }, X: { x: 3 * font_width, y: yh, width: font_width }, Y: { x: 4 * font_width, y: yh, width: font_width }, Z: { x: 5 * font_width, y: yh, width: font_width }, 0: { x: 6 * font_width, y: yh, width: font_width }, 1: { x: 7 * font_width, y: yh, width: font_width }, 2: { x: 8 * font_width, y: yh, width: font_width }, 3: { x: 9 * font_width, y: yh, width: font_width }, 4: { x: 10 * font_width, y: yh, width: font_width }, 5: { x: 11 * font_width, y: yh, width: font_width }, 6: { x: 12 * font_width, y: yh, width: font_width }, 7: { x: 13 * font_width, y: yh, width: font_width }, 8: { x: 14 * font_width, y: yh, width: font_width }, 9: { x: 15 * font_width, y: yh, width: font_width }, "+": { x: 16 * font_width, y: yh, width: font_width }, "-": { x: 17 * font_width, y: yh, width: font_width }, ".": { x: 18 * font_width, y: yh, width: font_width }, ",": { x: 19 * font_width, y: yh, width: font_width }, }, }; export default class Axes2DLayer extends Layer { shouldUpdateState({ props, oldProps, context, changeFlags, }) { return (super.shouldUpdateState({ props, oldProps, context, changeFlags, }) || changeFlags.viewportChanged); } updateState() { // Calculating margins. var _a, _b, _c; // Note due to vertical scaling pixel2world mapping may differ in X and Y direction. const m = 100; // Length in pixels let worldFrom = this.context.viewport.unproject([0, 0, 0]); let worldTo = this.context.viewport.unproject([m, 0, 0]); let v = [ worldFrom[0] - worldTo[0], worldFrom[1] - worldTo[1], worldFrom[2] - worldTo[2], ]; const pixel2worldHor = Math.sqrt(v[0] * v[0] + v[1] * v[1]) / m; worldFrom = this.context.viewport.unproject([0, 0, 0]); worldTo = this.context.viewport.unproject([0, m, 0]); v = [ worldFrom[0] - worldTo[0], worldFrom[1] - worldTo[1], worldFrom[2] - worldTo[2], ]; const pixel2worldVer = Math.sqrt(v[0] * v[0] + v[1] * v[1]) / m; const marginV = (_a = this.props.minimalMarginV) !== null && _a !== void 0 ? _a : this.props.marginV; const marginH = (_b = this.props.minimalMarginH) !== null && _b !== void 0 ? _b : this.props.marginH; let worldMarginV = marginV * pixel2worldVer; let worldMarginH = marginH * pixel2worldHor; // If specified horisontal margin (mh) is to small for the label, increase it. const fontSizePixels = GetPixelsScale((_c = this.props.labelFontSizePt) !== null && _c !== void 0 ? _c : defaultProps.labelFontSizePt); const viewportBoundsW = this.context.viewport.getBounds(); //bounds in world coordinates. const yBoundsMin = viewportBoundsW[1]; const yBoundsMax = viewportBoundsW[3]; const isB = this.props.isBottomRuler; const isT = this.props.isTopRuler; const ymin = isB ? yBoundsMin + worldMarginV : yBoundsMin; const ymax = isT ? yBoundsMax - worldMarginV : yBoundsMax; const numLettersV = 1; const numPixelsV = fontSizePixels * numLettersV; const minimalPixelMarginV = numPixelsV + 2 * tickLineLength; if (marginV < minimalPixelMarginV) { worldMarginV = minimalPixelMarginV * pixel2worldVer; } const numLettersH = Math.max(this.makeLabel(ymin, 0).length, this.makeLabel(ymax, 0).length); const numPixelsH = fontSizePixels * numLettersH; const minimalPixelMarginH = numPixelsH + 2 * tickLineLength; if (marginH < minimalPixelMarginH) { worldMarginH = minimalPixelMarginH * pixel2worldHor; } this.setState(Object.assign(Object.assign({}, this.state), { worldMarginV, worldMarginH, pixel2worldVer, pixel2worldHor })); const fontTexture = this.state["fontTexture"]; const { labelModels, lineModel: lineModel, backgroundModel: backgroundModel, } = this._getModels(fontTexture); this.setState(Object.assign(Object.assign({}, this.state), { mv: worldMarginV, mh: worldMarginH })); this.setState(Object.assign(Object.assign({}, this.state), { models: [...labelModels, lineModel, backgroundModel] })); } initializeState() { const promise = load(fontAtlasPng, ImageLoader, { image: { type: "data" }, // Will load as ImageData. }); promise.then((data) => { const fontTexture = this.context.device.createTexture({ width: data.width, height: data.height, format: "rgb8unorm-webgl", data: data, sampler: { addressModeU: "clamp-to-edge", addressModeV: "clamp-to-edge", minFilter: "linear", magFilter: "linear", }, }); const { labelModels, lineModel, backgroundModel } = this._getModels(fontTexture); this.setState({ fontTexture, models: [...labelModels, lineModel, backgroundModel], }); }); } makeLabel(n, ndecimals) { let label = n.toFixed(ndecimals); if (this.props.formatLabelFunc) { label = this.props.formatLabelFunc(n); label = label.replace("e", "E"); // this font atlas does not have "e" label = label.replace("\u2212", "-"); // use standard minus sign } return label; } GetTickLinesAndLabels(min, max, viewSide) { const ndecimals = 0; const n_minor_ticks = 3; const lines = []; const tick_labels = []; const worldMarginV = this.state["worldMarginV"]; const worldMarginH = this.state["worldMarginH"]; const pixel2worldVer = this.state["pixel2worldVer"]; const pixel2worldHor = this.state["pixel2worldHor"]; const vpBounds = this.context.viewport.getBounds(); let start; let y_tick = 0; let x_tick = 0; if (viewSide === ViewSide.Top) { start = vpBounds[3] - worldMarginV; y_tick = start; } else if (viewSide === ViewSide.Bottom) { start = vpBounds[1] + worldMarginV; y_tick = start; } else if (viewSide === ViewSide.Left) { start = vpBounds[0] + worldMarginH; x_tick = start; } else if (viewSide === ViewSide.Right) { start = vpBounds[2] - worldMarginH; x_tick = start; } const isTopOrBottomRuler = viewSide === ViewSide.Top || viewSide === ViewSide.Bottom; const m = tickLineLength; // Length in pixels const delta = isTopOrBottomRuler ? m * pixel2worldVer : m * pixel2worldHor; const L = isTopOrBottomRuler ? LineLengthInPixels([min, 0, 0], [max, 0, 0], this.context.viewport) : LineLengthInPixels([0, min, 0], [0, max, 0], this.context.viewport); const ticks = GetTicks(min, max, L); // Note: this may be replaced by NiceTicks npm package. const tick_length = viewSide === ViewSide.Left || viewSide === ViewSide.Bottom ? -delta : delta; for (let i = 0; i < ticks.length; i++) { const tick = ticks[i]; const label = this.makeLabel(tick, ndecimals); tick_labels.push(label); // tick line start if (isTopOrBottomRuler) { lines.push(tick, y_tick, zDepthAxes); // tick line start lines.push(tick, y_tick + tick_length, zDepthAxes); // tick line end. } else { lines.push(x_tick, tick, zDepthAxes); lines.push(x_tick + tick_length, tick, zDepthAxes); } } // Add minor X ticks. if (ticks.length > 1) { const tick1 = ticks[0]; const tick2 = ticks[1]; const d = (tick2 - tick1) / (n_minor_ticks + 1); const tick_start = tick1; // up let i = 0; while (tick_start + (i + 1) * d < max) { const tick = tick_start + (i + 1) * d; tick_labels.push(""); i++; if (isTopOrBottomRuler) { lines.push(tick, y_tick, zDepthAxes); // tick line start lines.push(tick, y_tick + 0.5 * tick_length, zDepthAxes); // tick line end. } else { lines.push(x_tick, tick, zDepthAxes); lines.push(x_tick + 0.5 * tick_length, tick, zDepthAxes); } } // down i = 0; while (tick_start - (i + 1) * d > min) { const tick = tick_start - (i + 1) * d; tick_labels.push(""); i++; if (isTopOrBottomRuler) { lines.push(tick, y_tick, zDepthAxes); lines.push(tick, y_tick + 0.5 * tick_length, zDepthAxes); } else { lines.push(x_tick, tick, zDepthAxes); lines.push(x_tick + 0.5 * tick_length, tick, zDepthAxes); } } } const labels = this.makeLabelsData(lines, tick_labels); return [lines, labels]; } GetBackgroundTriangleLinesHorizontal(x_min_w, x_max_w, isTop) { const worldMarginV = this.state["worldMarginV"]; const vp_bounds = this.context.viewport.getBounds(); // [xmin, ymin, xmax, ymax] const y_max = isTop ? vp_bounds[3] : vp_bounds[1] + worldMarginV; const y_min = isTop ? vp_bounds[3] - worldMarginV : vp_bounds[1]; const p1 = [x_min_w, y_max, zDepthAxes]; const p2 = [x_max_w, y_max, zDepthAxes]; const p3 = [x_max_w, y_min, zDepthAxes]; const p4 = [x_min_w, y_min, zDepthAxes]; /*eslint-disable */ const background_lines = [ ...p1, ...p2, ...p4, // triangle 1 ...p2, ...p4, ...p3, // triangle 2 ]; /*eslint-enable */ return background_lines; } GetBackgroundTriangleLinesVertical(y_min_w, y_max_w, isLeft // left or right ruler. ) { const worldMarginH = this.state["worldMarginH"]; const vp_bounds = this.context.viewport.getBounds(); // [xmin, ymin, xmax, ymax] const x_max = isLeft ? vp_bounds[0] + worldMarginH : vp_bounds[2]; const x_min = isLeft ? vp_bounds[0] : vp_bounds[2] - worldMarginH; const p1 = [x_max, y_min_w, zDepthAxes]; const p2 = [x_max, y_max_w, zDepthAxes]; const p3 = [x_min, y_max_w, zDepthAxes]; const p4 = [x_min, y_min_w, zDepthAxes]; /*eslint-disable */ const background_lines = [ ...p1, ...p2, ...p4, // triangle 1 ...p2, ...p4, ...p3, // triangle 2 ]; /*eslint-enable */ return background_lines; } makeLabelsData(tick_lines, tick_labels) { const labels = []; for (let i = 0; i < tick_lines.length / 6; i++) { const from = [ tick_lines[6 * i + 0], tick_lines[6 * i + 1], tick_lines[6 * i + 2], ]; const to = [ tick_lines[6 * i + 3], tick_lines[6 * i + 4], tick_lines[6 * i + 5], ]; const label = tick_labels[i]; const tick_vec = [ to[0] - from[0], to[1] - from[1], to[2] - from[2], ]; const s = 0.5; const pos = [ to[0] + s * tick_vec[0], to[1] + s * tick_vec[1], to[2] + s * tick_vec[2], ]; let anchor = TEXT_ANCHOR.end; let alignment = ALIGNMENT_BASELINE.center; const is_xaxis = from[1] !== to[1]; if (is_xaxis) { anchor = TEXT_ANCHOR.middle; alignment = ALIGNMENT_BASELINE.top; } else { const screen_from = this.context.viewport.project(from); const screen_to = this.context.viewport.project(to); if (screen_from[0] < screen_to[0]) { anchor = TEXT_ANCHOR.start; } } labels.push({ label, pos, anchor, alignment }); } return labels; } draw(opts) { const is_orthographic = this.context.viewport.constructor === OrthographicViewport; if (typeof this.state["fontTexture"] === "undefined" || !is_orthographic) { return; } const models = this.getModels(); const n = models.length; if (n < 2) { // Should ever happen. return; } // background models[n - 1].draw(opts.context.renderPass); // lines models[n - 2].draw(opts.context.renderPass); // labels for (let i = 0; i < n - 2; i++) { models[i].draw(opts.context.renderPass); } return; } // Make models for background, lines (tick marks and axis) and labels. _getModels(fontTexture) { var _a, _b, _c; const device = this.context.device; // Margins. const worldMarginV = this.state["worldMarginV"]; const worldMarginH = this.state["worldMarginH"]; const pixel2worldVer = this.state["pixel2worldVer"]; const pixel2worldHor = this.state["pixel2worldHor"]; const viewport_bounds_w = this.context.viewport.getBounds(); //bounds in world coordinates. const xBoundsMin = viewport_bounds_w[0]; const xBoundsMax = viewport_bounds_w[2]; const yBoundsMin = viewport_bounds_w[1]; const yBoundsMax = viewport_bounds_w[3]; let tick_and_axes_lines = []; let background_lines = []; let labelData = []; const isB = this.props.isBottomRuler; const isT = this.props.isTopRuler; const isL = this.props.isLeftRuler; const isR = this.props.isRightRuler; const xmin = xBoundsMin + (isL ? worldMarginH : 0); const xmax = xBoundsMax - (isR ? worldMarginH : 0); const ymin = isB ? yBoundsMin + worldMarginV : yBoundsMin; const ymax = isT ? yBoundsMax - worldMarginV : yBoundsMax; //- BOTTOM RULER ---------------------------------------- if (isB) { const axes = [xmin, ymin, zDepthAxes, xmax, ymin, zDepthAxes]; const [ticks, labels] = this.GetTickLinesAndLabels(xmin, xmax, ViewSide.Bottom); const back_lines = this.GetBackgroundTriangleLinesHorizontal(xBoundsMin, xBoundsMax, false); tick_and_axes_lines = [...tick_and_axes_lines, ...axes, ...ticks]; background_lines = [...background_lines, ...back_lines]; labelData = [...labelData, ...labels]; } //- TOP RULER ---------------------------------------- if (isT) { const axes = [xmin, ymax, zDepthAxes, xmax, ymax, zDepthAxes]; const [ticks, labels] = this.GetTickLinesAndLabels(xmin, xmax, ViewSide.Top); const back_lines = this.GetBackgroundTriangleLinesHorizontal(xBoundsMin, xBoundsMax, true // isTop ); tick_and_axes_lines = [...tick_and_axes_lines, ...axes, ...ticks]; background_lines = [...background_lines, ...back_lines]; labelData = [...labelData, ...labels]; } //- LEFT RULER ---------------------------------------- if (isL) { const axes = [xmin, ymin, zDepthAxes, xmin, ymax, zDepthAxes]; const [ticks, labels] = this.GetTickLinesAndLabels(ymin, ymax, ViewSide.Left); const back_lines = this.GetBackgroundTriangleLinesVertical(ymin, ymax, true); tick_and_axes_lines = [...tick_and_axes_lines, ...axes, ...ticks]; background_lines = [...background_lines, ...back_lines]; labelData = [...labelData, ...labels]; } //- RIGHT RULER ---------------------------------------- if (isR) { const axes = [xmax, ymin, zDepthAxes, xmax, ymax, zDepthAxes]; const [ticks, labels] = this.GetTickLinesAndLabels(ymin, ymax, ViewSide.Right); const back_lines = this.GetBackgroundTriangleLinesVertical(ymin, ymax, false); tick_and_axes_lines = [...tick_and_axes_lines, ...axes, ...ticks]; background_lines = [...background_lines, ...back_lines]; labelData = [...labelData, ...labels]; } // Line models. (axis line and tick lines) // Color on axes and text. let lineColor = [0.0, 0.0, 0.0, 1.0]; if (typeof this.props.axisColor !== "undefined") { lineColor = this.props.axisColor; if (lineColor.length === 3) { lineColor.push(255); } lineColor = lineColor.map((x) => (x !== null && x !== void 0 ? x : 0) / 255); } const lineModel = new Model(device, Object.assign(Object.assign({ id: `${this.props.id}-lines` }, super.getShaders({ vs: lineVertexShader, fs: lineFragmentShader, modules: [project32, linesUniforms, precisionForTests], })), { geometry: new Geometry({ topology: "line-list", attributes: { positions: new Float32Array(tick_and_axes_lines), }, vertexCount: tick_and_axes_lines.length / 3, }), isInstanced: false })); lineModel.shaderInputs.setProps({ lines: { uColor: lineColor, uClipZ: -1, }, }); //-- Background model -- // Color on axes background. let bColor = [0.5, 0.5, 0.5, 1]; if (typeof this.props.backgroundColor !== "undefined") { bColor = this.props.backgroundColor; if (bColor.length === 3) { bColor.push(255); } bColor = bColor.map((x) => (x !== null && x !== void 0 ? x : 0) / 255); } const backgroundModel = new Model(device, Object.assign(Object.assign({ id: `${this.props.id}-background` }, super.getShaders({ vs: lineVertexShader, fs: lineFragmentShader, modules: [project32, linesUniforms, precisionForTests], })), { geometry: new Geometry({ topology: "triangle-list", attributes: { positions: new Float32Array(background_lines), }, vertexCount: background_lines.length / 3, }), isInstanced: false })); backgroundModel.shaderInputs.setProps({ lines: { uColor: bColor, uClipZ: -0.9, }, }); //-- Labels model-- const labelModels = []; const pixelScale = GetPixelsScale((_a = this.props.labelFontSizePt) !== null && _a !== void 0 ? _a : defaultProps.labelFontSizePt); for (const item of labelData) { const x = item.pos[0]; const y = item.pos[1]; const z = item.pos[2]; const label = item.label; const anchor = (_b = item.anchor) !== null && _b !== void 0 ? _b : TEXT_ANCHOR.start; const alignment_baseline = (_c = item.alignment) !== null && _c !== void 0 ? _c : ALIGNMENT_BASELINE.center; if (label === "") { continue; } const pos_w = vec4.fromValues(x, y, z, 1); // pos world const len = label.length; const numVertices = len * 6; const positions = new Float32Array(numVertices * 3); const texcoords = new Float32Array(numVertices * 2); const maxX = fontInfo.textureWidth; const maxY = fontInfo.textureHeight; let offset = 0; let offsetTexture = 0; let x1 = 0; if (anchor === TEXT_ANCHOR.end) { x1 = -len; } else if (anchor === TEXT_ANCHOR.middle) { x1 = -len / 2; } let y_alignment_offset = 0; if (alignment_baseline === ALIGNMENT_BASELINE.center) { y_alignment_offset = 0.5 * pixelScale; } else if (alignment_baseline === ALIGNMENT_BASELINE.top) { y_alignment_offset = 1 * pixelScale; } for (let ii = 0; ii < len; ++ii) { const letter = label[ii]; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const glyphInfo = fontInfo.glyphInfos[letter]; if (glyphInfo) { // Unit square. const x2 = x1 + 1; const u1 = glyphInfo.x / maxX; const v1 = (glyphInfo.y + fontInfo.letterHeight - 1) / maxY; const u2 = (glyphInfo.x + glyphInfo.width - 1) / maxX; const v2 = glyphInfo.y / maxY; const h = 1; // 6 vertices per letter // t1 /*eslint-disable */ positions[offset + 0] = pos_w[0] + x1 * pixelScale * pixel2worldHor; // Add a distance in view coords and convert to world positions[offset + 1] = pos_w[1] + (0 * pixelScale - y_alignment_offset) * pixel2worldVer; positions[offset + 2] = pos_w[2]; texcoords[offsetTexture + 0] = u1; texcoords[offsetTexture + 1] = v1; positions[offset + 3] = pos_w[0] + x2 * pixelScale * pixel2worldHor; positions[offset + 4] = pos_w[1] + (0 * pixelScale - y_alignment_offset) * pixel2worldVer; positions[offset + 5] = pos_w[2]; texcoords[offsetTexture + 2] = u2; texcoords[offsetTexture + 3] = v1; positions[offset + 6] = pos_w[0] + x1 * pixelScale * pixel2worldHor; positions[offset + 7] = pos_w[1] + (h * pixelScale - y_alignment_offset) * pixel2worldVer; positions[offset + 8] = pos_w[2]; texcoords[offsetTexture + 4] = u1; texcoords[offsetTexture + 5] = v2; // t2 positions[offset + 9] = pos_w[0] + x1 * pixelScale * pixel2worldHor; positions[offset + 10] = pos_w[1] + (h * pixelScale - y_alignment_offset) * pixel2worldVer; positions[offset + 11] = pos_w[2]; texcoords[offsetTexture + 6] = u1; texcoords[offsetTexture + 7] = v2; positions[offset + 12] = pos_w[0] + x2 * pixelScale * pixel2worldHor; positions[offset + 13] = pos_w[1] + (0 * pixelScale - y_alignment_offset) * pixel2worldVer; positions[offset + 14] = pos_w[2]; texcoords[offsetTexture + 8] = u2; texcoords[offsetTexture + 9] = v1; positions[offset + 15] = pos_w[0] + x2 * pixelScale * pixel2worldHor; positions[offset + 16] = pos_w[1] + (h * pixelScale - y_alignment_offset) * pixel2worldVer; positions[offset + 17] = pos_w[2]; texcoords[offsetTexture + 10] = u2; texcoords[offsetTexture + 11] = v2; /*eslint-ensable */ x1 += 1; offset += 18; offsetTexture += 12; } else { // we don't have this character so just advance x1 += 1; } } const model = new Model(device, Object.assign(Object.assign({ id: `${this.props.id}-${label}` }, super.getShaders({ vs: labelVertexShader, fs: labelFragmentShader, modules: [project32, axesUniforms, precisionForTests], })), { bindings: { // @ts-ignore fontTexture, }, geometry: new Geometry({ topology: "triangle-list", attributes: { positions, vTexCoord: { value: texcoords, size: 2, }, }, vertexCount: positions.length / 3, }), bufferLayout: this.getAttributeManager().getBufferLayouts(), isInstanced: false })); model.shaderInputs.setProps({ axes: { uAxisColor: lineColor, uBackGroundColor: bColor, }, }); labelModels.push(model); } return { labelModels: labelModels, lineModel: lineModel, backgroundModel: backgroundModel, }; } } Axes2DLayer.layerName = "Axes2DLayer"; Axes2DLayer.defaultProps = defaultProps; //-- Local help functions. ------------------------------------------------- // KEEP for now. // USAGE: // const pos_w = vec4.fromValues(x, y, z, 1); // pos world // const pos_v = multMatVec(viewMatrix, pos_w); // pos view // function multMatVec( // viewMatrix: number[], // pos_w: vec4 // ): [number, number, number] { // const pos_v = vec4.transformMat4( // vec4.create(), // pos_w, // mat4.fromValues( // ...(viewMatrix.slice(0, mat4.fromValues.length) as Parameters< // typeof mat4.fromValues // >) // ) // ); // return pos_v.slice(0, 3) as [number, number, number]; // } function LineLengthInPixels(p0, p1, viewport) { const screen_from = viewport.project(p0); const screen_to = viewport.project(p1); const v = [ screen_from[0] - screen_to[0], screen_from[1] - screen_to[1], screen_from[2] - screen_to[2], ]; const L = Math.sqrt(v[0] * v[0] + v[1] * v[1]); // Length of axis on screen in pixles. return L; } function GetTicks(min, max, axis_pixel_length) { let step = Math.min(Math.round(axis_pixel_length / 100) + 1, 20); const range = max - min; const delta = Math.abs(range) / step; let decade = 1; if (delta >= 10) { const logde = Math.log10(delta); const pot = Math.floor(logde); decade = Math.pow(10.0, pot); } let scaled_delta = Math.round(delta / decade); if (scaled_delta == 3) scaled_delta = 2; else if (scaled_delta == 4 || scaled_delta == 6 || scaled_delta == 7) scaled_delta = 5; else if (scaled_delta > 7) scaled_delta = 10; else if (scaled_delta < 1) scaled_delta = 1; const incr = scaled_delta * decade; const start = Math.ceil(min / incr) * incr; const stop = Math.floor(max / incr) * incr; const calc_step = Math.floor(Math.abs(stop - start) / incr); step = calc_step > 0 ? calc_step : 0; const ticks = []; //ticks.push(min); for (let i = 0; i <= step; i++) { const x = start + i * incr; ticks.push(x); } return ticks; } function GetPixelsScale(labelFontSizePt) { // Estimated number of pixels from baseline to top of font. // Linear interpolation based on this table: https://reeddesign.co.uk/test/points-pixels.html const px = Math.max(0, (8 / 9) * labelFontSizePt); return px; } const linesUniformsBlock = /*glsl*/ `\ uniform linesUniforms { vec4 uColor; float uClipZ; } lines; `; // NOTE: this must exactly the same name than in the uniform block const linesUniforms = { name: "lines", vs: linesUniformsBlock, fs: linesUniformsBlock, uniformTypes: { uColor: "vec4<f32>", uClipZ: "f32", }, }; const axesUniformsBlock = /*glsl*/ `\ uniform axesUniforms { vec4 uAxisColor; vec4 uBackGroundColor; } axes; `; // NOTE: this must exactly the same name than in the uniform block const axesUniforms = { name: "axes", vs: axesUniformsBlock, fs: axesUniformsBlock, uniformTypes: { uAxisColor: "vec4<f32>", uBackGroundColor: "vec4<f32>", }, }; //# sourceMappingURL=axes2DLayer.js.map