|
|
|
|
@ -20,6 +20,7 @@
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <thread>
|
|
|
|
|
#include <vector>
|
|
|
|
|
@ -808,33 +809,60 @@ int cmdBuildGeo(int argc, char** argv) {
|
|
|
|
|
// volumeData[通道][道][样本],再桥接(Gpr3dvVolumeBridge)成 geopro int16 量化体
|
|
|
|
|
// (轴 X=道/Y=通道/Z=样本),落 ChunkedVolumeStore + buildPyramid。原样渲(14 格 Y
|
|
|
|
|
// 薄体),不做横向插值加密。
|
|
|
|
|
int cmdBuildLine(int argc, char** argv) {
|
|
|
|
|
const Args a = parseArgs(argc, argv, 2);
|
|
|
|
|
if (a.positional.size() < 2) {
|
|
|
|
|
std::cerr << "用法: gpr_poc build-line <lineDir> <linePrefix> "
|
|
|
|
|
"--out <storeDir> [--levels 3]\n"
|
|
|
|
|
"例: gpr_poc build-line \"D:/Downloads/明星路\" 明星路_001 "
|
|
|
|
|
"--out tmp/line001_proc --levels 3\n";
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
const std::string lineDir = a.positional[0];
|
|
|
|
|
const std::string linePrefix = a.positional[1];
|
|
|
|
|
const int levels = std::stoi(a.get("levels", "3"));
|
|
|
|
|
const std::string out =
|
|
|
|
|
a.get("out", (fs::temp_directory_path() / "gpr_store_line").string());
|
|
|
|
|
// 磁盘剩余空间(GB):查 path 所在卷可用字节。失败(路径不存在等)→ -1(视为未知)。
|
|
|
|
|
double freeSpaceGB(const std::string& path) {
|
|
|
|
|
std::error_code ec;
|
|
|
|
|
// 用已存在的父目录查(out 目录可能还没建)。
|
|
|
|
|
fs::path p = fs::absolute(path, ec);
|
|
|
|
|
while (!p.empty() && !fs::exists(p, ec)) p = p.parent_path();
|
|
|
|
|
if (p.empty()) p = fs::current_path(ec);
|
|
|
|
|
const fs::space_info si = fs::space(p, ec);
|
|
|
|
|
if (ec) return -1.0;
|
|
|
|
|
return static_cast<double>(si.available) / (1024.0 * 1024.0 * 1024.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 单线建体结果(供 build-all 汇总,不编造)。ok=false 时 reason 给清晰原因。
|
|
|
|
|
struct LineBuildResult {
|
|
|
|
|
std::string prefix;
|
|
|
|
|
bool ok = false;
|
|
|
|
|
std::string reason; // 失败/跳过原因
|
|
|
|
|
std::int64_t nx = 0, ny = 0, nz = 0;
|
|
|
|
|
std::int64_t dataBytes = 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 单线建体核心:gpr3dv 处理链 → 桥接量化体(可 coarse 下采样) → 落盘 + 金字塔。
|
|
|
|
|
// 异常(加载失败/立方体空/短桩线维度退化)由调用方捕获,不在此中断批量。
|
|
|
|
|
LineBuildResult buildOneLine(const std::string& lineDir,
|
|
|
|
|
const std::string& linePrefix,
|
|
|
|
|
const std::string& out, int levels, int coarse) {
|
|
|
|
|
LineBuildResult r;
|
|
|
|
|
r.prefix = linePrefix;
|
|
|
|
|
|
|
|
|
|
std::cout << "[build-line] lineDir=" << lineDir << " linePrefix=" << linePrefix
|
|
|
|
|
<< " levels=" << levels << " out=" << out << "\n";
|
|
|
|
|
<< " levels=" << levels << " coarse=" << coarse << " out=" << out
|
|
|
|
|
<< "\n";
|
|
|
|
|
|
|
|
|
|
// 1) gpr3dv 处理链 → 处理后立方体 → 桥接量化体。
|
|
|
|
|
// 1) gpr3dv 处理链 → 处理后立方体 → 桥接量化体(coarse 沿测线下采样)。
|
|
|
|
|
Stopwatch swBridge;
|
|
|
|
|
geopro::io::gpr::BridgeMetrics bm;
|
|
|
|
|
geopro::core::BuiltI16 built =
|
|
|
|
|
geopro::io::gpr::buildLineVolumeFromGpr3dv(lineDir, linePrefix, &bm);
|
|
|
|
|
geopro::core::BuiltI16 built = geopro::io::gpr::buildLineVolumeFromGpr3dv(
|
|
|
|
|
lineDir, linePrefix, &bm, coarse);
|
|
|
|
|
const double bridgeMs = swBridge.elapsedMs();
|
|
|
|
|
|
|
|
|
|
const std::int64_t nx = built.vol.nx(), ny = built.vol.ny(),
|
|
|
|
|
nz = built.vol.nz();
|
|
|
|
|
r.nx = nx;
|
|
|
|
|
r.ny = ny;
|
|
|
|
|
r.nz = nz;
|
|
|
|
|
// 短桩线/退化体守护:维度过小无法建有意义的金字塔/体绘制 → 报因跳过(不落盘)。
|
|
|
|
|
if (nx < 2 || ny < 1 || nz < 2) {
|
|
|
|
|
r.ok = false;
|
|
|
|
|
r.reason = "体维度退化(道×通道×样本=" + std::to_string(nx) + "x" +
|
|
|
|
|
std::to_string(ny) + "x" + std::to_string(nz) +
|
|
|
|
|
"),无法建可看体,跳过";
|
|
|
|
|
std::cerr << "[build-line] " << linePrefix << " " << r.reason << "\n";
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
const std::int64_t voxels = nx * ny * nz;
|
|
|
|
|
const std::int64_t rawBytes = voxels * 2; // int16
|
|
|
|
|
|
|
|
|
|
@ -848,7 +876,7 @@ int cmdBuildLine(int argc, char** argv) {
|
|
|
|
|
std::cout << "[build-line] 世界 spacing dx=" << bm.dx << " dy=" << bm.dy
|
|
|
|
|
<< " dz=" << bm.dz << " (m)\n";
|
|
|
|
|
|
|
|
|
|
// 2) 落盘 + 金字塔(道很长 45305>16384 → 需 levels≥2 使最粗层≤16384)。
|
|
|
|
|
// 2) 落盘 + 金字塔(道很长 → 需 levels≥2 使最粗层≤16384)。
|
|
|
|
|
fs::create_directories(out);
|
|
|
|
|
Stopwatch swWrite;
|
|
|
|
|
geopro::data::ChunkedVolumeStore::write(out, built);
|
|
|
|
|
@ -862,6 +890,7 @@ int cmdBuildLine(int argc, char** argv) {
|
|
|
|
|
const double pyrMs = swPyr.elapsedMs();
|
|
|
|
|
|
|
|
|
|
const std::int64_t dataBytes = storeDataBytes(out);
|
|
|
|
|
r.dataBytes = dataBytes;
|
|
|
|
|
const double ratio =
|
|
|
|
|
dataBytes > 0 ? static_cast<double>(rawBytes) / dataBytes : 0.0;
|
|
|
|
|
const double peak = Probe::peakMemMB();
|
|
|
|
|
@ -887,9 +916,9 @@ int cmdBuildLine(int argc, char** argv) {
|
|
|
|
|
std::cout << "峰值内存(MB) : " << peak << "\n";
|
|
|
|
|
|
|
|
|
|
writeMetricLine(
|
|
|
|
|
"build-line,prefix=" + linePrefix + ",nx=" + std::to_string(nx) +
|
|
|
|
|
",ny=" + std::to_string(ny) + ",nz=" + std::to_string(nz) +
|
|
|
|
|
",voxels=" + std::to_string(voxels) +
|
|
|
|
|
"build-line,prefix=" + linePrefix + ",coarse=" + std::to_string(coarse) +
|
|
|
|
|
",nx=" + std::to_string(nx) + ",ny=" + std::to_string(ny) +
|
|
|
|
|
",nz=" + std::to_string(nz) + ",voxels=" + std::to_string(voxels) +
|
|
|
|
|
",vmin=" + std::to_string(bm.vminPhys) +
|
|
|
|
|
",vmax=" + std::to_string(bm.vmaxPhys) +
|
|
|
|
|
",dx=" + std::to_string(bm.dx) + ",dy=" + std::to_string(bm.dy) +
|
|
|
|
|
@ -899,6 +928,133 @@ int cmdBuildLine(int argc, char** argv) {
|
|
|
|
|
",bridgeMs=" + std::to_string(bridgeMs) +
|
|
|
|
|
",writeMs=" + std::to_string(writeMs) +
|
|
|
|
|
",pyrMs=" + std::to_string(pyrMs) + ",peakMB=" + std::to_string(peak));
|
|
|
|
|
|
|
|
|
|
r.ok = true;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cmdBuildLine(int argc, char** argv) {
|
|
|
|
|
const Args a = parseArgs(argc, argv, 2);
|
|
|
|
|
if (a.positional.size() < 2) {
|
|
|
|
|
std::cerr << "用法: gpr_poc build-line <lineDir> <linePrefix> "
|
|
|
|
|
"--out <storeDir> [--levels 3] [--coarse F]\n"
|
|
|
|
|
"例: gpr_poc build-line \"D:/Downloads/明星路\" 明星路_001 "
|
|
|
|
|
"--out tmp/line001_proc --levels 3 --coarse 4\n";
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
const std::string lineDir = a.positional[0];
|
|
|
|
|
const std::string linePrefix = a.positional[1];
|
|
|
|
|
const int levels = std::stoi(a.get("levels", "3"));
|
|
|
|
|
const int coarse = std::stoi(a.get("coarse", "1"));
|
|
|
|
|
const std::string out =
|
|
|
|
|
a.get("out", (fs::temp_directory_path() / "gpr_store_line").string());
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const LineBuildResult r =
|
|
|
|
|
buildOneLine(lineDir, linePrefix, out, levels, coarse);
|
|
|
|
|
if (!r.ok) {
|
|
|
|
|
std::cerr << "[build-line] 跳过: " << r.reason << "\n";
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
std::cerr << "[build-line] 失败(" << linePrefix << "): " << e.what() << "\n";
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build-all:发现目录下所有测线(_Axx 分组),逐条 build-line 到 baseDir/<lineName>/。
|
|
|
|
|
// 磁盘守护:每条建前查可用空间,低于阈值(默认 3GB)即停并报已建哪些。
|
|
|
|
|
// 短桩线/异常单条捕获并跳过(报因),不中断其余。
|
|
|
|
|
int cmdBuildAll(int argc, char** argv) {
|
|
|
|
|
const Args a = parseArgs(argc, argv, 2);
|
|
|
|
|
if (a.positional.empty() || !a.kv.count("outBase")) {
|
|
|
|
|
std::cerr << "用法: gpr_poc build-all <lineDir> --outBase <baseDir> "
|
|
|
|
|
"[--levels 3] [--coarse F] [--minFreeGB 3]\n"
|
|
|
|
|
"例: gpr_poc build-all \"D:/Downloads/明星路\" "
|
|
|
|
|
"--outBase tmp/lines_all --levels 3 --coarse 4\n";
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
const std::string lineDir = a.positional[0];
|
|
|
|
|
const std::string outBase = a.get("outBase", "");
|
|
|
|
|
const int levels = std::stoi(a.get("levels", "3"));
|
|
|
|
|
const int coarse = std::stoi(a.get("coarse", "1"));
|
|
|
|
|
const double minFreeGB = std::stod(a.get("minFreeGB", "3"));
|
|
|
|
|
|
|
|
|
|
// 1) 发现所有测线前缀:扫 *_<line>_A<NN>.iprh,取 "<...>_<line>" 部分(去 _A<NN>)。
|
|
|
|
|
std::set<std::string> prefixSet;
|
|
|
|
|
std::error_code ec;
|
|
|
|
|
for (const auto& e : fs::directory_iterator(lineDir, ec)) {
|
|
|
|
|
if (!e.is_regular_file()) continue;
|
|
|
|
|
const std::string name = e.path().filename().string();
|
|
|
|
|
if (e.path().extension().string() != ".iprh") continue;
|
|
|
|
|
// 找 "_A<NN>" 通道后缀,截断得测线前缀。
|
|
|
|
|
const std::size_t pos = name.rfind("_A");
|
|
|
|
|
if (pos == std::string::npos) continue;
|
|
|
|
|
std::size_t d = pos + 2;
|
|
|
|
|
while (d < name.size() && std::isdigit(static_cast<unsigned char>(name[d])))
|
|
|
|
|
++d;
|
|
|
|
|
if (d == pos + 2) continue; // _A 后无数字 → 非通道文件
|
|
|
|
|
prefixSet.insert(name.substr(0, pos));
|
|
|
|
|
}
|
|
|
|
|
if (prefixSet.empty()) {
|
|
|
|
|
std::cerr << "[build-all] 未在 " << lineDir << " 发现任何测线(*_A<NN>.iprh)\n";
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
std::vector<std::string> prefixes(prefixSet.begin(), prefixSet.end());
|
|
|
|
|
std::cout << "[build-all] 发现 " << prefixes.size() << " 条测线,outBase="
|
|
|
|
|
<< outBase << " levels=" << levels << " coarse=" << coarse
|
|
|
|
|
<< " minFreeGB=" << minFreeGB << "\n";
|
|
|
|
|
|
|
|
|
|
fs::create_directories(outBase, ec);
|
|
|
|
|
|
|
|
|
|
// 2) 逐条建:磁盘守护 → buildOneLine(单条 try/catch)。
|
|
|
|
|
std::vector<LineBuildResult> results;
|
|
|
|
|
bool stoppedByDisk = false;
|
|
|
|
|
for (const std::string& prefix : prefixes) {
|
|
|
|
|
const double freeGB = freeSpaceGB(outBase);
|
|
|
|
|
std::cout << "\n[build-all] --- " << prefix << " --- 剩余磁盘 "
|
|
|
|
|
<< freeGB << " GB\n";
|
|
|
|
|
if (freeGB >= 0.0 && freeGB < minFreeGB) {
|
|
|
|
|
std::cerr << "[build-all] 磁盘守护触发: 剩余 " << freeGB << " GB < "
|
|
|
|
|
<< minFreeGB << " GB,停止,未建 " << prefix << " 及其后。\n";
|
|
|
|
|
stoppedByDisk = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
const std::string out = (fs::path(outBase) / prefix).string();
|
|
|
|
|
LineBuildResult r;
|
|
|
|
|
r.prefix = prefix;
|
|
|
|
|
try {
|
|
|
|
|
r = buildOneLine(lineDir, prefix, out, levels, coarse);
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
r.ok = false;
|
|
|
|
|
r.reason = std::string("异常: ") + e.what();
|
|
|
|
|
std::cerr << "[build-all] " << prefix << " 失败: " << e.what()
|
|
|
|
|
<< "(跳过,继续)\n";
|
|
|
|
|
}
|
|
|
|
|
results.push_back(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3) 汇总。
|
|
|
|
|
std::cout << "\n=== build-all 汇总 ===\n";
|
|
|
|
|
int okCount = 0;
|
|
|
|
|
std::int64_t totalBytes = 0;
|
|
|
|
|
for (const auto& r : results) {
|
|
|
|
|
if (r.ok) {
|
|
|
|
|
++okCount;
|
|
|
|
|
totalBytes += r.dataBytes;
|
|
|
|
|
std::cout << " [OK] " << r.prefix << " 维度=" << r.nx << "x" << r.ny
|
|
|
|
|
<< "x" << r.nz << " data="
|
|
|
|
|
<< r.dataBytes / (1024.0 * 1024.0) << " MB\n";
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << " [跳过] " << r.prefix << " 原因=" << r.reason << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::cout << "成功 " << okCount << "/" << prefixes.size()
|
|
|
|
|
<< " 条,合计 data=" << totalBytes / (1024.0 * 1024.0 * 1024.0)
|
|
|
|
|
<< " GB,剩余磁盘 " << freeSpaceGB(outBase) << " GB\n";
|
|
|
|
|
if (stoppedByDisk)
|
|
|
|
|
std::cout << "注意: 因磁盘守护提前停止,部分测线未建。\n";
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -4388,7 +4544,9 @@ void usage() {
|
|
|
|
|
" gpr_poc build-geo <dir> [--cellXY 0.5] [--cellZ 0.1] "
|
|
|
|
|
"[--out <storeDir>] [--levels 4] [--maxLines N] [--curvilinear]\n"
|
|
|
|
|
" gpr_poc build-line <lineDir> <linePrefix> --out <storeDir> "
|
|
|
|
|
"[--levels 3]\n"
|
|
|
|
|
"[--levels 3] [--coarse F]\n"
|
|
|
|
|
" gpr_poc build-all <lineDir> --outBase <baseDir> "
|
|
|
|
|
"[--levels 3] [--coarse F] [--minFreeGB 3]\n"
|
|
|
|
|
" gpr_poc load <storeDir>\n"
|
|
|
|
|
" gpr_poc selftest\n"
|
|
|
|
|
" gpr_poc offscreen-smoke\n"
|
|
|
|
|
@ -4424,6 +4582,7 @@ int main(int argc, char** argv) {
|
|
|
|
|
if (cmd == "build-stream") return cmdBuildStream(argc, argv);
|
|
|
|
|
if (cmd == "build-geo") return cmdBuildGeo(argc, argv);
|
|
|
|
|
if (cmd == "build-line") return cmdBuildLine(argc, argv);
|
|
|
|
|
if (cmd == "build-all") return cmdBuildAll(argc, argv);
|
|
|
|
|
if (cmd == "load") return cmdLoad(argc, argv);
|
|
|
|
|
if (cmd == "selftest") return cmdSelftest();
|
|
|
|
|
if (cmd == "offscreen-smoke") return cmdOffscreenSmoke();
|
|
|
|
|
|