#ifndef SURVEYGEOMETRY_H #define SURVEYGEOMETRY_H #include #include #include struct SurveyGeometry { double rtkOffsetX = 0.0; // RTK相对天线中心的设备x轴偏移(m),头文件无对应字段,保留给用户输入 double rtkOffsetY = 0.0; // RTK相对天线中心的设备y轴偏移(m),来自CH_Y_OFFSETS double ch1XRel = 0.0; // 第1通道相对天线中心的x坐标(m),由CH_X_OFFSETS首尾值推导 QVector channelXRel; // 各通道相对天线中心的x坐标(m),来自CH_X_OFFSETS归一到天线中心 int channelCount = 1; // 通道总数,来自NUMBER_OF_CH int cgcsZone = 0; // CGCS2000 3度带带号,0表示自动检测 double centralMeridianDeg = 0.0; // 中央经线(度),自动推导 bool operator==(const SurveyGeometry &other) const { return rtkOffsetX == other.rtkOffsetX && rtkOffsetY == other.rtkOffsetY && ch1XRel == other.ch1XRel && channelXRel == other.channelXRel && channelCount == other.channelCount && cgcsZone == other.cgcsZone && centralMeridianDeg == other.centralMeridianDeg; } void applyHeaderOffsets(int numberOfChannels, const QVector &chXOffsets, const QVector &chYOffsets) { const int offsetChannelCount = qMax(chXOffsets.size(), chYOffsets.size()); channelCount = qMax(1, numberOfChannels > 0 ? numberOfChannels : offsetChannelCount); rtkOffsetY = chYOffsets.isEmpty() ? 0.0 : static_cast(chYOffsets.first()); channelXRel.clear(); channelXRel.reserve(channelCount); if (chXOffsets.size() >= 2) { const double centerX = (static_cast(chXOffsets.first()) + chXOffsets.last()) / 2.0; for (int i = 0; i < chXOffsets.size() && i < channelCount; ++i) { channelXRel.append(static_cast(chXOffsets[i]) - centerX); } ch1XRel = channelXRel.isEmpty() ? 0.0 : channelXRel.first(); } else { ch1XRel = 0.0; } if (channelXRel.size() < channelCount) { const int existing = channelXRel.size(); channelXRel.resize(channelCount); if (existing == 0) { for (int c = 0; c < channelCount; ++c) { channelXRel[c] = 0.0; } } else if (channelCount > 1) { const double lastXRel = -ch1XRel; for (int c = existing; c < channelCount; ++c) { channelXRel[c] = ch1XRel + (lastXRel - ch1XRel) * c / (channelCount - 1.0); } } } } static SurveyGeometry fromHeaderOffsets(int numberOfChannels, const QVector &chXOffsets, const QVector &chYOffsets) { SurveyGeometry g; g.applyHeaderOffsets(numberOfChannels, chXOffsets, chYOffsets); return g; } QJsonObject toJson() const { QJsonObject obj; obj["rtkOffsetX"] = rtkOffsetX; obj["rtkOffsetY"] = rtkOffsetY; obj["ch1XRel"] = ch1XRel; QJsonArray channelXRelArray; for (double x : channelXRel) { channelXRelArray.append(x); } obj["channelXRel"] = channelXRelArray; obj["channelCount"] = channelCount; obj["cgcsZone"] = cgcsZone; obj["centralMeridianDeg"] = centralMeridianDeg; return obj; } static SurveyGeometry fromJson(const QJsonObject &obj) { SurveyGeometry g; g.rtkOffsetX = obj.value("rtkOffsetX").toDouble(0.0); g.rtkOffsetY = obj.value("rtkOffsetY").toDouble(0.0); g.ch1XRel = obj.value("ch1XRel").toDouble(0.0); g.channelCount = qMax(1, obj.value("channelCount").toInt(1)); g.cgcsZone = obj.value("cgcsZone").toInt(0); g.centralMeridianDeg = obj.value("centralMeridianDeg").toDouble(0.0); const QJsonArray channelXRelArray = obj.value("channelXRel").toArray(); for (const QJsonValue &value : channelXRelArray) { g.channelXRel.append(value.toDouble(0.0)); } if (g.channelXRel.isEmpty() && obj.contains("ch16XRel")) { const double legacyLastXRel = obj.value("ch16XRel").toDouble(-g.ch1XRel); g.channelXRel.resize(g.channelCount); for (int c = 0; c < g.channelCount; ++c) { g.channelXRel[c] = (g.channelCount > 1) ? g.ch1XRel + (legacyLastXRel - g.ch1XRel) * c / (g.channelCount - 1.0) : g.ch1XRel; } } else if (g.channelXRel.isEmpty()) { g.channelXRel.resize(g.channelCount); const double lastXRel = -g.ch1XRel; for (int c = 0; c < g.channelCount; ++c) { g.channelXRel[c] = (g.channelCount > 1) ? g.ch1XRel + (lastXRel - g.ch1XRel) * c / (g.channelCount - 1.0) : g.ch1XRel; } } else if (g.channelXRel.size() != g.channelCount) { g.channelCount = qMax(1, g.channelXRel.size()); } return g; } }; #endif // SURVEYGEOMETRY_H