void ContourWidget::drawContour()
{
XYChart *poXYChart = new XYChart(this->width(), this->height(), 0xffffff, 0x888888);
poXYChart->addTitle(title.toUtf8(), "Arial Bold Italic", 16);
poXYChart->setPlotArea((this->width()-this->height())/2, 40, this->height(), this->height()-100);
poXYChart->xAxis()->setTitle("经度(°)", "Arial Bold Italic", 12);
poXYChart->yAxis()->setTitle("纬度(°)", "Arial Bold Italic", 12);
poXYChart->xAxis()->setLinearScale(minX, maxX);
poXYChart->yAxis()->setLinearScale(minY, maxY);
poXYChart->xAxis()->setLabelStyle("Arial Bold");
poXYChart->yAxis()->setLabelStyle("Arial Bold");
poXYChart->yAxis()->setTickDensity(40);
poXYChart->xAxis()->setTickDensity(40);
ContourLayer* layer = poXYChart->addContourLayer(DoubleArray(adX, size),
DoubleArray(adY, size),
DoubleArray(adZ, size));
poXYChart->getPlotArea()->moveGridBefore(layer);
ColorAxis* cAxis = layer->setColorAxis(this->width() - 300, this->height()*0.1545, Chart::TopLeft, this->height()*0.618, Chart::Right);
cAxis->setLinearScale(minZ, maxZ, (maxZ-minZ)/20);
cAxis->setTitle("总场(mV)", "Arial Bold Italic", 12);
cAxis->setLabelStyle("Arial Bold");
int colorGradient[] = {0x9999FF, 0x0000CC, 0x00CC00, 0xFFFF00, 0xEE0000, 0xFF0000};
const int colorGradient_size = (int)(sizeof(colorGradient)/sizeof(*colorGradient));
cAxis->setColorGradient(false, IntArray(colorGradient, colorGradient_size));
ui->chartViewer->setChart(poXYChart);
ui->chartViewer->setImageMap(poXYChart->getHTMLImageMap("", "", "title='<*cdml*><*font=bold*>经度(°): {x|8}<*br*>纬度(°): {y|8}<*br*>总场(mV): {z|6}''"));
}
下面这段就是抄了官网的example。纯属hello world 阶段学习。
#include <math.h>
#include <QLabel>
#include <QCheckBox>
#include <QMouseEvent>
#include "threedchartrotation.h"
#include "chartdir.h"
#include <QVBoxLayout>
#include <iostream>
#include <cmath>
#include <QButtonGroup>
ThreeDChartRotation::ThreeDChartRotation(QString title,
double *adX, double *adY, double *adZ, double *adW,
double minX, double maxX,
double minY, double maxY,
double minZ, double maxZ,
double minW, double maxW,
int size, QWidget *parent) :
QDialog(parent)
{
// Set up the GUI
this->setWindowTitle("三维曲面等高线图");
this->setWindowIcon(QIcon(":/new/prefix1/image/3D.png"));
this->setMinimumSize(800, 800);
this->setWindowFlags(Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
m_DrawFrameOnRotate = new QCheckBox("旋转时绘制网格框架");
m_DrawFrameOnRotate->setStyleSheet("font-size:12px Arial;");
m_DrawFrameOnRotate->setChecked(true);
QButtonGroup *poButtonGroup = new QButtonGroup;
poButtonGroup->setExclusive(true);
QCheckBox *poCheckBoxTotal = new QCheckBox("Z轴展示总场");
poCheckBoxTotal->setChecked(true);
QCheckBox *poCheckBoxDepth = new QCheckBox("Z轴展示深度");
poCheckBoxDepth->setChecked(false);
eZValue = Z_TOTAL;
poButtonGroup->addButton(poCheckBoxTotal, Z_TOTAL);
poButtonGroup->addButton(poCheckBoxDepth, Z_DEPTH);
connect(poButtonGroup, &QButtonGroup::buttonClicked, this, [=](QAbstractButton *button){
eZValue = static_cast<Z_VALUE>(poButtonGroup->buttons().indexOf(button));
if (m_ChartViewer->needUpdateChart())
drawChart(m_ChartViewer);
});
QVBoxLayout *poVBoxLayout = new QVBoxLayout;
poVBoxLayout->addStretch();
poVBoxLayout->addWidget(m_DrawFrameOnRotate, 0, Qt::AlignLeft);
poVBoxLayout->addWidget(poCheckBoxTotal, 0, Qt::AlignLeft);
poVBoxLayout->addWidget(poCheckBoxDepth, 0, Qt::AlignLeft);
poVBoxLayout->addStretch();
// Chart Viewer
m_ChartViewer = new QChartViewer(this);
connect(m_ChartViewer, SIGNAL(viewPortChanged()),SLOT(onViewPortChanged()));
connect(m_ChartViewer, SIGNAL(mouseMove(QMouseEvent *)), SLOT(onMouseMoveChart(QMouseEvent *)));
connect(m_ChartViewer, SIGNAL(clicked(QMouseEvent *)), SLOT(onMouseUpChart(QMouseEvent *)));
// Set initial zoom/scroll direction
m_ChartViewer->setScrollDirection(Chart::DirectionHorizontalVertical);
m_ChartViewer->setZoomDirection(Chart::KeepAspectRatio);
// Enable mouse wheel zooming by setting the zoom ratio to 1.1 per wheel event
m_ChartViewer->setMouseWheelZoomRatio(1.1);
QHBoxLayout *poHBoxLayout = new QHBoxLayout;
poHBoxLayout->addLayout(poVBoxLayout, 0);
poHBoxLayout->addWidget(m_ChartViewer, 1, Qt::AlignCenter);
this->setLayout(poHBoxLayout);
// 3D view angles
m_elevationAngle = 30;
m_rotationAngle = 45;
// Keep track of mouse drag
m_isDragging = false;
m_lastMouseX = -1;
m_lastMouseY = -1;
// Update the viewport to display the chart
m_ChartViewer->updateViewPort(true, false);
this->title = title;
this->adX = adX;
this->adY = adY;
this->adZ = adZ;
this->adW = adW;
this->minX = minX;
this->maxX = maxX;
this->minY = minY;
this->maxY = maxY;
this->minZ = minZ;
this->maxZ = maxZ;
this->minW = minW;
this->maxW = maxW;
this->size = size;
}
ThreeDChartRotation::~ThreeDChartRotation()
{
delete m_ChartViewer->getChart();
}
//
// View port changed event
//
void ThreeDChartRotation::onViewPortChanged()
{
// Update the chart if necessary
if (m_ChartViewer->needUpdateChart())
drawChart(m_ChartViewer);
}
//
// Draw chart
//
void ThreeDChartRotation::drawChart(QChartViewer *poChartViewer)
{
SurfaceChart* poSurfaceChart = new SurfaceChart(this->width(), this->height(), 0xffffff, 0x888888);
poSurfaceChart->setPerspective(20);
poSurfaceChart->addTitle(title.toUtf8(), "Arial Bold Italic", 16);
poSurfaceChart->setPlotRegion(this->width()/2, this->height()/2, this->height()/qSqrt(2), this->height()/qSqrt(2), this->height()/qSqrt(2)*0.618);
QString oStrLabel, oStrZAxisTitle;
switch (eZValue) {
case Z_TOTAL:
poSurfaceChart->setData(DoubleArray(adX, size), DoubleArray(adY, size), DoubleArray(adW, size));
oStrZAxisTitle = "总场(mV)";
oStrLabel = "title='<*cdml*>经度(°): {x|10}<*br*>纬度(°): {y|10}<*br*>总场(mV): {z|6}'";
break;
case Z_DEPTH:
poSurfaceChart->setData(DoubleArray(adX, size), DoubleArray(adY, size), DoubleArray(adZ, size), DoubleArray(adW, size));
oStrZAxisTitle = "深度(m)";
oStrLabel = "title='<*cdml*>经度(°): {x|10}<*br*>纬度(°): {y|10}<*br*>深度(m): {z|2}'";
break;
default:
break;
}
poSurfaceChart->setInterpolation(80, 80);
int majorGridColor = 0xc0000000;
int minorGridColor = poSurfaceChart->dashLineColor(majorGridColor, Chart::DotLine);
poSurfaceChart->setSurfaceAxisGrid(majorGridColor, majorGridColor, minorGridColor, minorGridColor);
// Add XY projection
poSurfaceChart->addXYProjection();
// Set contour lines to semi-transparent white (0x7fffffff)
poSurfaceChart->setContourColor(0x7fffffff);
poSurfaceChart->setViewAngle(m_elevationAngle, m_rotationAngle);
if (m_isDragging && m_DrawFrameOnRotate->isChecked()){
poSurfaceChart->setShadingMode(Chart::RectangularFrame);
}
ColorAxis* poColorAxis = poSurfaceChart->setColorAxis(this->width() - 300, this->height()*0.1545, Chart::TopLeft, this->height()*0.618, Chart::Right);
poColorAxis->setLabelStyle("Arial", 10);
poColorAxis->setAxisBorder(Chart::Transparent, 0);
poColorAxis->setTitle("总场(mV)", "Arial Bold", 15);
poColorAxis->setLinearScale(minW, maxW, (maxW-minW)/20);
int colorGradient[] = {0x9999FF, 0x0000CC, 0x00CC00, 0xFFFF00, 0xEE0000, 0xFF0000};
const int colorGradient_size = (int)(sizeof(colorGradient)/sizeof(*colorGradient));
poColorAxis->setColorGradient(false, IntArray(colorGradient, colorGradient_size));
poSurfaceChart->xAxis()->setTitle("经度(°)", "Arial Bold Italic", 12);
poSurfaceChart->yAxis()->setTitle("纬度(°)", "Arial Bold Italic", 12);
poSurfaceChart->zAxis()->setTitle(oStrZAxisTitle.toUtf8(), "Arial Bold Italic", 12);
delete poChartViewer->getChart();
poChartViewer->setChart(poSurfaceChart);
poChartViewer->setImageMap(poSurfaceChart->getHTMLImageMap("", "", oStrLabel.toUtf8()));
}
void ThreeDChartRotation::resizeEvent(QResizeEvent *event)
{
m_ChartViewer->getChart()->setSize(event->size().width(), event->size().height());
}
void ThreeDChartRotation::onMouseMoveChart(QMouseEvent *event)
{
int mouseX = m_ChartViewer->getChartMouseX();
int mouseY = m_ChartViewer->getChartMouseY();
// Drag occurs if mouse is moving and mouse button is down
if (event->buttons() & Qt::LeftButton)
{
if (m_isDragging)
{
// The chart is configured to rotate by 90 degrees when the mouse moves from
// left to right, which is the plot region width (360 pixels). Similarly, the
// elevation changes by 90 degrees when the mouse moves from top to buttom,
// which is the plot region height (270 pixels).
m_rotationAngle += (m_lastMouseX - mouseX) * 90.0 / 360;
m_elevationAngle += (mouseY - m_lastMouseY) * 90.0 / 270;
m_ChartViewer->updateViewPort(true, false);
}
// Keep track of the last mouse position
m_lastMouseX = mouseX;
m_lastMouseY = mouseY;
m_isDragging = true;
}
}
void ThreeDChartRotation::onMouseUpChart(QMouseEvent *event)
{
if (m_isDragging && (event->button() == Qt::LeftButton))
{
// mouse up means not dragging
m_isDragging = false;
m_ChartViewer->updateViewPort(true, false);
}
}
仅仅是学习。
这里面有个数据网格化。使用反距离加权法插值。
//xyPosition:输入点坐标(X,Y)
//inScatterData:输入的散点(X,Y,Z)集合
//返回输入点插值所得到的Z
有数学大佬,可以给出更完美的克里金插值法,这样距离Golden Software的Surfer就又近了一步。
#include "GridWorker.h"
GridWorker::GridWorker(QSqlDatabase db, double dStep, double dCM, QObject *parent)
: QObject{parent}
{
this->db = db;
this->dStep = dStep;
this->dCM = dCM;
}
void GridWorker::run()
{
QSqlQuery query(db);
db.transaction();
//检索极值,确定平面范围
double maxLon = 0.0, minLon = 0.0, maxLat = 0.0, minLat = 0.0;
query.clear();
query.exec("select min(longitude), max(longitude), min(latitude), max(latitude) from merge");
if(query.first()){
minLon = query.value(0).toDouble();
maxLon = query.value(1).toDouble();
minLat = query.value(2).toDouble();
maxLat = query.value(3).toDouble();
}
qDebugV0()<<QString::number(minLon, 'f', 8)
<<QString::number(maxLon, 'f', 8)
<<QString::number(minLat, 'f', 8)
<<QString::number(maxLat, 'f', 8);
qDebugV0()<<QString::number((maxLon - minLon), 'f', 8)<<QString::number((maxLat - minLat), 'f', 8);
//Vector 3D,选取 需要出图的关键数据
QScatterDataArray *poArrayDepth = new QScatterDataArray;
QScatterDataArray *poArrayTotal = new QScatterDataArray;
query.clear();
query.exec("select longitude, latitude, depth, total from merge");
while(query.next()){
poArrayDepth->append(QVector3D(query.value("longitude").toDouble(),
query.value("latitude").toDouble(),
query.value("depth").toDouble()));
poArrayTotal->append(QVector3D(query.value("longitude").toDouble(),
query.value("latitude").toDouble(),
query.value("total").toDouble()));
}
//contour 存到数据库 表里面
query.clear();
query.exec("delete from contour");
query.prepare(QString("insert into contour values(?, ?, ?, ?)"));
QVariantList arLongitude, arLatitude, arDepth, arTotal;
QPair<double, double> stepLonLat = this->getStep(maxLon, minLon, maxLat, minLat, dStep);
double dStepLon = stepLonLat.first;
double dStepLat = stepLonLat.second;
qDebugV0()<<"距离, 纬度 经度 rate: "<<(maxLat-minLat)/dStepLat<<(maxLon-minLon)/dStepLon;
double dCnt = (maxLat-minLat)/dStepLat * (maxLon-minLon)/dStepLon;
quint32 uiPercentage = PROGRESS_STEP;
for(double lon = minLon; lon < maxLon; lon += dStepLon){
//emit sigProgress(100*(lon - minLon)/(maxLon-minLon) , QString("lon, (%1/%2)").arg((lon - minLon)/dStepLon).arg((maxLon-minLon)/dStepLon));
for(double lat = minLat; lat < maxLat; lat += dStepLat){
//根据给定的 x y ,计算出 网格化的结果 总场值,
QVector3D vDepth = this->calIDW(poArrayDepth, QVector2D(lon, lat));
QVector3D vTotal = this->calIDW(poArrayTotal, QVector2D(lon, lat));
arLongitude.append(vTotal.x());
arLatitude.append(vTotal.y());
arDepth.append(-1*vDepth.z());
arTotal.append(vTotal.z());
float fProgress = (lon - minLon)/(maxLon-minLon) * (lat - minLat)/(maxLat-minLat) * 100;
if(fProgress >= uiPercentage)
{
emit sigProgress(fProgress , "数据网格化~");
uiPercentage = uiPercentage + PROGRESS_STEP;
}
}
}
query.addBindValue(arLongitude);
query.addBindValue(arLatitude);
query.addBindValue(arDepth);
query.addBindValue(arTotal);
query.execBatch(); //进行批处理操作
db.commit();
emit sigProgress(100, QString("网格化完毕!"));
}
//反距离加权法插值
//xyPosition:输入点坐标(X,Y)
//inScatterData:输入的散点(X,Y,Z)集合
//返回输入点插值所得到的Z
QVector3D GridWorker::calIDW(QScatterDataArray *poArray, QVector2D vector2D)
{
double result = 0;
int inNum = poArray->count();
QVector<double> di;
di.resize(inNum);
double sum_di = 0;
for(int i = 0; i < inNum; i++)
{
double dis = sqrt(pow(vector2D.x() - poArray->at(i).x(), 2) + pow(vector2D.y() - poArray->at(i).y(), 2));
if(dis == 0){
return QVector3D(vector2D.x(), vector2D.y(), poArray->at(i).z());
}
di[i] = 1.0/pow(dis, 2);
sum_di += (di[i]);
}
for(int i = 0; i < inNum; i++){
result += ((di[i]/sum_di) * poArray->at(i).z());
}
QVector<double>().swap(di);
//qDebugV0()<< QString::number(vector2D.x(), 'f', 10)<<","<< QString::number(vector2D.y(), 'f', 10)<<","<< QString::number(result, 'f', 10) ;
return QVector3D(vector2D.x(), vector2D.y(), result);
}
QPair<double, double> GridWorker::getStep(double maxLon,double minLon, double maxLat, double minLat, double dStep)
{
XYZ oXYZLB = BLToGauss((minLon), (minLat));//左下角
XYZ oXYZRB = BLToGauss((maxLon), (minLat));//右下角
XYZ oXYZLT = BLToGauss((minLon), (maxLat));//左上角
double dLengthLon = oXYZRB.y - oXYZLB.y;//东西方向的 距离
double dLengthLat = oXYZLT.x - oXYZLB.x;//南北方向的 距离
qDebugV0()<<"距离, 南北 东西 : "<<dLengthLat<<dLengthLon;
qDebugV0()<<"距离, 纬度 经度 rate: "<<dLengthLat/dStep<<dLengthLon/dStep;
// qDebugV0()<<"距离, 纬度 经度 mi: "<<dLengthLat<<dLengthLon;
// qDebugV0()<<"距离, 纬度 经度 du: "<<(maxLat-minLat)<<(maxLon-minLon);
QPair<double, double> stepLonLat;
stepLonLat.first = dStep/dLengthLon*(maxLon-minLon);//东西方向的 经度 步长 单位是度 度
stepLonLat.second = dStep/dLengthLat*(maxLat-minLat);//南北方向的 纬度 步长 单位是度 度
return stepLonLat;
}
/**
* 由经纬度反算成高斯投影坐标(高斯正算)
*
* @param longitude
* @param latitude
*/
XYZ GridWorker::BLToGauss(double longitude, double latitude)
{
int ProjNo = 0;
// 带宽
int ZoneWide = 3;
double longitude1, latitude1, longitude0, X0, Y0, xval, yval;
double a, f, e2, ee, NN, T, C, A, M, iPI;
// 3.1415926535898/180.0;
iPI = M_PI/180.0;
// 84年北京坐标系参数
a = 6378137;
f = 1.0 / 298.2572236;
//CGCS2000坐标系参数
// a = 6378137;
// f = 1.0 / 298.2572221;
ProjNo = 0;
longitude0 = ProjNo * ZoneWide ;
longitude0 = dCM * iPI;
// 经度转换为弧度
longitude1 = longitude * iPI;
// 纬度转换为弧度
latitude1 = latitude * iPI;
e2 = 2 * f - f * f;
ee = e2 * (1.0 - e2);
NN = a / sqrt(1.0 - e2 * sin(latitude1) * sin(latitude1));
T = tan(latitude1) * tan(latitude1);
C = ee * cos(latitude1) * cos(latitude1);
A = (longitude1 - longitude0) * cos(latitude1);
M = a * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256) * latitude1 - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2 / 1024) * sin(2 * latitude1) + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024) * sin(4 * latitude1) - (35 * e2 * e2 * e2 / 3072) * sin(6 * latitude1));
xval = NN * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * ee) * A * A * A * A * A / 120);
yval = M + NN * tan(latitude1) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * ee) * A * A * A * A * A * A / 720);
X0 = 1000000 * (ProjNo ) + 500000;
Y0 = 0;
xval = xval + X0;
yval = yval + Y0;
XYZ oXYZ;
oXYZ.x = yval;
oXYZ.y = xval;
qDebugV0()<<"x: "<<QString::number(oXYZ.x, 10, 3)<<" y: "<<QString::number(oXYZ.y, 10, 3);
return oXYZ;
}