48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as db from './db.js';
|
|
import { samplePointcloudFile, type SampledPoint } from './pointcloudSample.js';
|
|
|
|
/** 与批量采样接口一致的配额 seek 采样(供热力分析作业复用) */
|
|
export async function sampleTaskPointclouds(taskId: number, budget: number): Promise<SampledPoint[]> {
|
|
const pcRecords = await db.listTaskPointcloudFiles(taskId);
|
|
const paths = pcRecords.map((r) => r.filePath);
|
|
if (paths.length === 0) return [];
|
|
|
|
const budgetClamped = Math.min(Math.max(50_000, budget), 20_000_000);
|
|
const supportedExts = ['.ply', '.txt', '.xyz', '.pts'];
|
|
|
|
const fileInfos = paths.map((fp) => ({
|
|
filePath: fp,
|
|
name: path.basename(fp),
|
|
ext: path.extname(fp).toLowerCase(),
|
|
size: fs.existsSync(fp) ? fs.statSync(fp).size : 0,
|
|
}));
|
|
const supportedFiles = fileInfos.filter((f) => supportedExts.includes(f.ext) && f.size > 0);
|
|
const totalBytes = supportedFiles.reduce((s, f) => s + f.size, 0);
|
|
if (supportedFiles.length === 0) return [];
|
|
|
|
const quotaMap = new Map<string, number>();
|
|
for (const f of supportedFiles) {
|
|
const quota =
|
|
totalBytes > 0
|
|
? Math.max(100, Math.round((f.size / totalBytes) * budgetClamped))
|
|
: Math.floor(budgetClamped / supportedFiles.length);
|
|
quotaMap.set(f.filePath, quota);
|
|
}
|
|
|
|
const sampledPerFile = await Promise.all(
|
|
fileInfos.map((f) => {
|
|
if (!supportedExts.includes(f.ext) || f.size === 0) {
|
|
return Promise.resolve([] as SampledPoint[]);
|
|
}
|
|
return samplePointcloudFile(f.filePath, f.size, quotaMap.get(f.filePath) ?? 0);
|
|
}),
|
|
);
|
|
const allPoints: SampledPoint[] = [];
|
|
for (const pts of sampledPerFile) {
|
|
allPoints.push(...pts);
|
|
}
|
|
return allPoints;
|
|
}
|