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