115 lines
6.0 KiB
C++
115 lines
6.0 KiB
C++
#include "dto/DatasetChartDto.hpp"
|
||
#include <cmath>
|
||
#include <QString>
|
||
#include <QtGlobal>
|
||
namespace geopro::data::dto {
|
||
using namespace geopro::core;
|
||
|
||
static double num(const QJsonValue& v, double def = 0.0) {
|
||
if (v.isDouble()) return v.toDouble();
|
||
if (v.isString()) { bool ok = false; double d = v.toString().toDouble(&ok); return ok ? d : def; }
|
||
return def;
|
||
}
|
||
|
||
Grid parseInversionGrid(const QJsonObject& data) {
|
||
const QJsonArray x = data.value("x").toArray();
|
||
const QJsonArray y = data.value("y").toArray();
|
||
const QJsonArray v = data.value("v").toArray(); // [ny][nx]
|
||
const int nx = x.size(), ny = y.size();
|
||
Grid g(nx < 1 ? 1 : nx, ny < 1 ? 1 : ny);
|
||
g.x.clear(); for (auto e : x) g.x.push_back(num(e));
|
||
g.y.clear(); for (auto e : y) g.y.push_back(num(e));
|
||
// 经纬度(每列 [nx]):供 CurtainActor 经 GeoLocalFrame 把每列摆到真实测线位置——
|
||
// 弯曲测线 → 曲面帘面(不解析则 lat/lon 空、退化成 y=0 平面)。API 字段 lat/lon。
|
||
g.lat.clear(); for (auto e : data.value("lat").toArray()) g.lat.push_back(num(e));
|
||
g.lon.clear(); for (auto e : data.value("lon").toArray()) g.lon.push_back(num(e));
|
||
if (v.size() != ny) // 服务端 v 行数与 y 不符:下方越界处填 NaN,记录便于排查(非静默)。
|
||
qWarning("parseInversionGrid: v rows=%d != ny=%d (缺失行将填 NaN)", v.size(), ny);
|
||
for (int j = 0; j < ny; ++j) {
|
||
const QJsonArray row = v.at(j).toArray();
|
||
for (int i = 0; i < nx; ++i) {
|
||
const QJsonValue cell = row.at(i);
|
||
g.valueAt(i, j) = (cell.isNull() || cell.isUndefined()) ? std::nan("") : num(cell, std::nan(""));
|
||
}
|
||
}
|
||
g.vmin = num(data.value("vmin")); g.vmax = num(data.value("vmax"));
|
||
return g;
|
||
}
|
||
|
||
ScatterField parseScatterGraph(const QJsonObject& data) {
|
||
ScatterField s;
|
||
auto fill = [&](const char* key, std::vector<double>& dst) {
|
||
for (auto e : data.value(key).toArray()) dst.push_back(num(e)); };
|
||
fill("xlist", s.x); fill("ylist", s.y); fill("hlist", s.z); fill("vlist", s.v);
|
||
fill("projectXList", s.projX); fill("projectYList", s.projY);
|
||
return s;
|
||
}
|
||
|
||
ColorScale parseColorBar(const QJsonObject& data) {
|
||
ColorScale cs;
|
||
const QJsonObject props = data.value("properties").toObject();
|
||
// 整体透明度(两级第二级):properties.opacity,缺省 1(不透明)。
|
||
if (props.contains("opacity")) cs.setGlobalOpacity(props.value("opacity").toDouble(1.0));
|
||
const QJsonArray bar = props.value("colorBar").toArray();
|
||
for (auto e : bar) {
|
||
const QJsonArray pair = e.toArray();
|
||
if (pair.size() < 2) continue;
|
||
const double val = num(pair.at(0));
|
||
const std::string rgba = pair.at(1).toString().toStdString();
|
||
// API colorBar 颜色为混合格式:hex(#RRGGBB) 与 CSS rgba(r,g,b,a),其中 a 是 0–1 浮点
|
||
// (实测 "rgba(0, 0, 170, 1)")。须用 Unit 标度(a*255),否则 a=1 被当字节 → alpha≈1 近透明。
|
||
cs.addStop(val, parseColor(rgba, AlphaScale::Unit));
|
||
}
|
||
return cs;
|
||
}
|
||
|
||
std::vector<Anomaly> parseDatasetAnomalies(const QJsonArray& arr) {
|
||
std::vector<Anomaly> out;
|
||
for (auto e : arr) {
|
||
const QJsonObject o = e.toObject();
|
||
Anomaly a;
|
||
a.id = o.value("id").toString().toStdString(); // 删除/更新/定位需要持久化 id
|
||
a.name = o.value("exceptionName").toString().toStdString();
|
||
a.typeName = o.value("exceptionTypeName").toString().toStdString();
|
||
a.exceptionTypeId = o.value("exceptionTypeId").toString().toStdString();
|
||
a.remark = o.value("remark").toString().toStdString();
|
||
a.createTime = o.value("createTime").toString().toStdString();
|
||
const int mt = o.value("exceptionMarkType").toInt(2); // 1=点 2=线 3=面 4=文字
|
||
a.markType = (mt >= 1 && mt <= 4) ? static_cast<AnomalyMarkType>(mt)
|
||
: AnomalyMarkType::Polyline; // 越界值兜底为线
|
||
const QJsonObject lg = o.value("legend").toObject();
|
||
a.lineColor = lg.value("polylineColor").toString("#000000").toStdString();
|
||
a.lineWidth = lg.value("polylineWidth").toDouble(1.0);
|
||
a.dashed = lg.value("polylineShape").toString() == "dash";
|
||
// 文字标注 customLegend(详情只读展示用):content/color/size/opacity。
|
||
const QJsonObject cl = o.value("customLegend").toObject();
|
||
if (!cl.isEmpty()) {
|
||
QString content = cl.value("content").toString();
|
||
if (content.isEmpty()) content = cl.value("text").toString();
|
||
a.textContent = content.toStdString();
|
||
a.textColor = cl.value("color").toString("#000000").toStdString();
|
||
a.textSize = cl.value("size").toInt(12);
|
||
a.textOpacity = cl.value("opacity").toDouble(1.0);
|
||
}
|
||
for (auto c : o.value("location").toObject().value("coordinate").toArray()) {
|
||
const QJsonObject p = c.toObject();
|
||
a.localPts.push_back(Vec2{p.value("x").toDouble(), p.value("y").toDouble()});
|
||
}
|
||
// 经纬度坐标(对照原版:latitudeLongitude.latLon[].{longitude,latitude})。
|
||
// 纯展示,不换算;空/缺失 → 详情坐标系下拉只给「图形坐标」(与原版 latLon.length===0 一致)。
|
||
for (auto c : o.value("latitudeLongitude").toObject().value("latLon").toArray()) {
|
||
const QJsonObject p = c.toObject();
|
||
a.lonLatPts.push_back(Vec2{p.value("longitude").toDouble(), p.value("latitude").toDouble()});
|
||
}
|
||
// 投影坐标(对照原版:geographicalCoordinates.coordinates[].{northCoord,eastCoord},
|
||
// 原版映射 x=northCoord、y=eastCoord)。
|
||
for (auto c : o.value("geographicalCoordinates").toObject().value("coordinates").toArray()) {
|
||
const QJsonObject p = c.toObject();
|
||
a.eastNorthPts.push_back(Vec2{p.value("northCoord").toDouble(), p.value("eastCoord").toDouble()});
|
||
}
|
||
out.push_back(std::move(a));
|
||
}
|
||
return out;
|
||
}
|
||
} // namespace geopro::data::dto
|