Files
massive-cloud/server/sampleTaskPointclouds.ts

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;
}