From 7bdb291fb4b3904af81a36581f50ba9e1eb009d0 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Thu, 25 Jun 2026 13:43:55 +0800 Subject: [PATCH] =?UTF-8?q?fix(gpr):=20=E4=BF=AE=E4=B8=96=E7=95=8C?= =?UTF-8?q?=E7=BD=91=E6=A0=BC=E8=B7=AF=E5=BE=84=E7=9F=AD=E7=BA=BF=E5=BB=BA?= =?UTF-8?q?=E4=BD=93=E5=A4=B1=E8=B4=A5(007=20=E6=B7=B1=E5=BA=A60=20?= =?UTF-8?q?=E7=BD=91=E6=A0=BC=E6=97=A0=E6=95=88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:CGCS easting 含带号约 4.0e7 米,存入 QVector3D(float32)后该量级 ULP 约 4 米;近正北短线 007 的东向跨度仅 0.81 米被浮点量化抹平成同值, CScanGridder 内 maxX<=minX 判退,返回空网格触发「深度0 网格无效」。 桥接层修法(不碰 verbatim 算法):存入 float 轨迹前先平移到局部原点 (首点 floor 到整米),坐标降到约 10^2 米量级,float 亚毫米精度无损; CScanGridder/TrajectoryCalculator 全程仅用差分/距离/IDW,对常量平移不变, 输出与未平移一致;最后把平移量加回 built.origin 还原真实 CGCS2000 世界米。 007 建成 23x347x195(东x北x深,78.5% 填充);001 不回归(18x1451x199, world origin 与基线 sub-meter 一致);external/gpr3dviewer 算法文件零改动。 --- src/io/gpr/Gpr3dvSurveyVolumeBridge.cpp | 36 ++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/io/gpr/Gpr3dvSurveyVolumeBridge.cpp b/src/io/gpr/Gpr3dvSurveyVolumeBridge.cpp index 62d9d2b..03f7803 100644 --- a/src/io/gpr/Gpr3dvSurveyVolumeBridge.cpp +++ b/src/io/gpr/Gpr3dvSurveyVolumeBridge.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -110,15 +111,35 @@ geopro::core::BuiltI16 buildLineVolumeSurvey(const std::string& lineDir, geom.cgcsZone = zone; geom.centralMeridianDeg = centralMeridianDeg; - QVector gpsCgcs; - gpsCgcs.reserve(static_cast(track.pts.size())); + // 先把所有 GPS 点正算到 CGCS2000(double,含带号),求局部原点。 + // 根因(短线 007 失败):CGCS easting 含带号 ≈ 4.0e7 米,存入 QVector3D(float32)后 + // 该量级 ULP ≈ 4 米——0.81 m 的东向跨度(近正北短线)被浮点量化抹平成同一个值, + // CScanGridder 里 maxX<=minX 判退 → 空网格(「深度0 网格无效」)。 + // 桥接层修法(不碰 verbatim 算法):存入 float 轨迹前先平移到局部原点(floor 到整米), + // 令坐标降到 ~10² 米量级、float 亚毫米精度无损;CScanGridder/TrajectoryCalculator 全程 + // 只用差分/距离/IDW(对常量平移不变),输出与未平移逐位一致——只是网格 origin 也变成局部值, + // 故最后把平移量加回 built.origin 即还原真实 CGCS2000 世界米。 + struct CgcsPt { double north; double east; double elev; }; + std::vector cgcsPts; + cgcsPts.reserve(track.pts.size()); for (const auto& p : track.pts) { double cx = 0.0, cy = 0.0; // cx=北(northing), cy=东(easting,含带号) CoordinateTransform::wgs84ToCgcs2000(p.lat * kDeg2Rad, p.lon * kDeg2Rad, zone, cx, cy); + cgcsPts.push_back({cx, cy, p.elev}); + } + // 局部原点 = 首点 floor 到整米(north→x 轴, east→y 轴,与 gpsPositions 约定一致)。 + const double localOriginNorth = std::floor(cgcsPts.front().north); + const double localOriginEast = std::floor(cgcsPts.front().east); + + QVector gpsCgcs; + gpsCgcs.reserve(static_cast(cgcsPts.size())); + for (const auto& q : cgcsPts) { // SurveyLine.gpsPositions 约定 x=北, y=东, z=高(与 TrajectoryCalculator 一致)。 - gpsCgcs.append(QVector3D(static_cast(cx), static_cast(cy), - static_cast(p.elev))); + // 平移到局部原点后再转 float(保住亚米精度)。 + gpsCgcs.append(QVector3D(static_cast(q.north - localOriginNorth), + static_cast(q.east - localOriginEast), + static_cast(q.elev))); } SurveyLine line; @@ -171,8 +192,11 @@ geopro::core::BuiltI16 buildLineVolumeSurvey(const std::string& lineDir, const int ny = g0.height; // 北向 northing 格数 const int nz = nzOut; // 深度 const double cellSize = g0.cellSizeM; - const double originX = g0.originX; // CGCS easting(含带号) 米 - const double originY = g0.originY; // CGCS northing 米 + // g0.originX/Y 为局部坐标系下的网格左下角(因 gpsPositions 已平移到局部原点); + // 加回 localOriginEast/North 还原真实 CGCS2000 世界米。 + // (CScanGridder 网格 X=东=gpsPositions.y, Y=北=gpsPositions.x,故 originX 配 East、originY 配 North。) + const double originX = g0.originX + localOriginEast; // CGCS easting(含带号) 米 + const double originY = g0.originY + localOriginNorth; // CGCS northing 米 // 量化区间:先扫所有输出深度网格的有效值(命中 validMask)定 [vmin,vmax]。 // (CScanGridder values 为处理后幅值的 IDW 插值结果,连续浮点。)