#include "dto/DatasetChartDto.hpp" #include #include #include 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& 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 parseDatasetAnomalies(const QJsonArray& arr) { std::vector 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(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