Qt C++ chartdir学习 demo

2023-12-27 13:44:55

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;
}

文章来源:https://blog.csdn.net/tadpole_java/article/details/135239380
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。