Files
water-management-system/frontend/node_modules/ktx-parse/src/util.ts
T
bot_dev1 85df71fc28 feat: 实现供水运营专题大屏BI可视化
- 新增OperationDashboard.vue全屏大屏组件
- 添加6个核心KPI指标卡片: 进水总量/出水总量/产销差率/营收额/平均水质/报警次数
- 实现6个ECharts图表: 供水趋势/水质分布/报警统计/管网空间/设备状态/营收分析
- 创建静态HTML版本operation-dashboard.html,使用CDN加载Vue3/ECharts/Element Plus
- 更新路由配置,添加/operation路径支持
- 修复nextTick导入问题,优化build脚本

🚧 开发者: bot_dev1
📝 任务: #38 [BI] 运营仪表盘 + 供水专题大屏
2026-06-15 09:06:11 +08:00

218 lines
6.9 KiB
TypeScript

import type { vec3 } from './constants-internal.js';
import {
type VKFormat,
VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
VK_FORMAT_BC1_RGB_UNORM_BLOCK,
VK_FORMAT_BC7_SRGB_BLOCK,
VK_FORMAT_EAC_R11G11_SNORM_BLOCK,
VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,
VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,
VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,
VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,
VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,
VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,
VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,
VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,
VK_FORMAT_UNDEFINED,
} from './constants.js';
import type { KTX2Container } from './container.js';
/** Encodes text to an ArrayBuffer. */
export function encodeText(text: string): Uint8Array {
return new TextEncoder().encode(text);
}
/** Decodes an ArrayBuffer to text. */
export function decodeText(buffer: Uint8Array): string {
return new TextDecoder().decode(buffer);
}
/** Concatenates N ArrayBuffers. */
export function concat(buffers: (ArrayBuffer | Uint8Array)[]): Uint8Array {
let totalByteLength = 0;
for (const buffer of buffers) {
totalByteLength += buffer.byteLength;
}
const result = new Uint8Array(totalByteLength);
let byteOffset = 0;
for (const buffer of buffers) {
result.set(new Uint8Array(buffer), byteOffset);
byteOffset += buffer.byteLength;
}
return result;
}
/** Returns the least common multiple (LCM) for two positive integers. */
export function leastCommonMultiple(a: number, b: number): number {
const max = Math.max(a, b);
const min = Math.min(a, b);
let lcm = max;
while (lcm % min !== 0) {
lcm += max;
}
return lcm;
}
/**
* Returns amount of padding, in bytes, required to pad a value V to N-byte
* boundaries. Both V and N must be positive integers.
*/
export function getPadding(v: number, n = 4): number {
return Math.ceil(v / n) * n - v;
}
/** Returns byte length per texel block. */
export function getBlockByteLength(container: KTX2Container): number {
return container.levels[0].levelData.byteLength / getBlockCount(container, 0);
}
/**
* Returns total number of blocks for given level. For VK_FORMAT_UNDEFINED, DFD is required.
*
* References:
* - https://github.khronos.org/KTX-Specification/ktxspec.v2.html#levelImages
*/
export function getBlockCount(container: KTX2Container, levelIndex: number): number {
let blockCount = 1;
const pixelDimensions = [container.pixelWidth, container.pixelHeight, container.pixelDepth];
const blockDimensions = getBlockDimensions(container);
for (let i = 0; i < 3; i++) {
if (pixelDimensions[i] > 0) {
const dimBlockCount = Math.ceil(Math.floor(pixelDimensions[i] * 2 ** -levelIndex) / blockDimensions[i]);
blockCount *= Math.max(1, dimBlockCount);
}
}
if (container.layerCount > 0) {
blockCount *= container.layerCount;
}
if (container.faceCount > 0) {
blockCount *= container.faceCount;
}
return blockCount;
}
/**
* Given a KTX2 container, returns block dimensions as [width, height, depth]. Requires valid DFD.
*/
export function getBlockDimensions(container: KTX2Container): vec3 {
const [x, y, z] = container.dataFormatDescriptor[0].texelBlockDimension;
return [x + 1, y + 1, z + 1];
}
/**
* Given `vkFormat`, returns block dimensions as [width, height, depth]. Does not support
* VK_FORMAT_UNDEFINED.
*
* References:
* - https://github.khronos.org/KTX-Specification/ktxspec.v2.html#_mippadding
* - https://registry.khronos.org/vulkan/specs/1.2-extensions/html/vkspec.html#formats-compatibility
*/
export function getBlockDimensionsByVKFormat(vkFormat: VKFormat): vec3 {
if (vkFormat === VK_FORMAT_UNDEFINED) {
throw new Error('Unknown block dimensions for VK_FORMAT_UNDEFINED.');
}
if (vkFormat >= VK_FORMAT_BC1_RGB_UNORM_BLOCK && vkFormat <= VK_FORMAT_BC7_SRGB_BLOCK) {
return [4, 4, 1];
}
if (vkFormat >= VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK && vkFormat <= VK_FORMAT_EAC_R11G11_SNORM_BLOCK) {
return [4, 4, 1];
}
if (vkFormat === VK_FORMAT_ASTC_4x4_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_4x4_SRGB_BLOCK) {
return [4, 4, 1];
}
if (vkFormat === VK_FORMAT_ASTC_5x4_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_5x4_SRGB_BLOCK) {
return [5, 4, 1];
}
if (vkFormat === VK_FORMAT_ASTC_5x5_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_5x5_SRGB_BLOCK) {
return [5, 5, 1];
}
if (vkFormat === VK_FORMAT_ASTC_6x5_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_6x5_SRGB_BLOCK) {
return [6, 5, 1];
}
if (vkFormat === VK_FORMAT_ASTC_6x6_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_6x6_SRGB_BLOCK) {
return [6, 6, 1];
}
if (vkFormat === VK_FORMAT_ASTC_8x5_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_8x5_SRGB_BLOCK) {
return [8, 5, 1];
}
if (vkFormat === VK_FORMAT_ASTC_8x6_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_8x6_SRGB_BLOCK) {
return [8, 6, 1];
}
if (vkFormat === VK_FORMAT_ASTC_8x8_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_8x8_SRGB_BLOCK) {
return [8, 8, 1];
}
if (vkFormat === VK_FORMAT_ASTC_10x5_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_10x5_SRGB_BLOCK) {
return [10, 5, 1];
}
if (vkFormat === VK_FORMAT_ASTC_10x6_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_10x6_SRGB_BLOCK) {
return [10, 6, 1];
}
if (vkFormat === VK_FORMAT_ASTC_10x8_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_10x8_SRGB_BLOCK) {
return [10, 8, 1];
}
if (vkFormat === VK_FORMAT_ASTC_10x10_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_10x10_SRGB_BLOCK) {
return [10, 10, 1];
}
if (vkFormat === VK_FORMAT_ASTC_12x10_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_12x10_SRGB_BLOCK) {
return [12, 10, 1];
}
if (vkFormat === VK_FORMAT_ASTC_12x12_UNORM_BLOCK || vkFormat === VK_FORMAT_ASTC_12x12_SRGB_BLOCK) {
return [12, 12, 1];
}
if (
vkFormat === VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG ||
vkFormat === VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG ||
vkFormat === VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG ||
vkFormat === VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG
) {
return [8, 4, 1];
}
if (
vkFormat === VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG ||
vkFormat === VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG ||
vkFormat === VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG ||
vkFormat === VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG
) {
return [4, 4, 1];
}
return [1, 1, 1];
}