Qt compilation of map comprehensive application 56 - real time dynamic trajectory

Posted by Swede78 on Fri, 11 Feb 2022 20:41:01 +0100

1, Foreword

The real-time dynamic trajectory has undergone many versions of iteration. This function was originally customized by customers. It mainly needs to dynamically display the motion trajectory of GPS on the map. One application scenario is a car with monitoring. In real time, the longitude and latitude information can be received in the background, and the corresponding trajectory needs to be drawn, which is equivalent to that these camera points move dynamically, In this way, the real-time position information of the camera can be observed. Double clicking the camera can also pop up the real-time preview of the picture, which is very intuitive.

The function of GPS trajectory also needs the knowledge of js. In fact, it encapsulates a js function and draws the corresponding line path. The information of this trajectory point may include longitude, latitude, speed, time, whether to mark, time and other information. It is written in a structure package to facilitate later expansion. Whether to mark means whether to change the point and add it as a device point at the same time, Meaning of segment line.

The two key points of setting the rotation angle and filtering the coordinate points are successively added later. The built-in setRotation function is used to set the rotation angle. The process is to first find the current point to be moved from a pile of covers through a unique identifier, such as name, and then call setRotation to set the angle value to be rotated for this marker point. Therefore, another requirement is derived here, How to calculate the rotation angle between two points? This value must be calculated in advance. This requires mathematical knowledge. atan2 is used to calculate and correct it at the same time.

2, Functional features

  1. The timer queues up to download the point coordinate set of the provincial and municipal outline map and stores it in the JS file.
  2. It supports downloading from one administrative region to multiple irregular regions.
  3. Automatically calculate the number of downloaded profiles in the administrative region.
  4. You can accurately select provinces, urban areas and counties, or directly enter the name of administrative regions.
  5. You can set the download interval, start and stop downloading at any time.
  6. It provides the function of editing the boundary. You can directly edit the point set of irregular areas on the map, and then obtain the boundary point set data. This can be used to draw the area and get the data, such as the administrative area data of a township or even a community. It is very awesome.

3, Experience address

  1. Experience address: https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A Extraction code: o05q file name: bin_map.zip
  2. Domestic sites: https://gitee.com/feiyangqingyun
  3. International sites: https://github.com/feiyangqingyun
  4. Personal homepage: https://blog.csdn.net/feiyangqingyun
  5. Zhihu homepage: https://www.zhihu.com/people/feiyangqingyun/

4, Renderings

5, Related code

void frmMapGps::receiveDataFromJs(const QString &type, const QVariant &data)
{
    if (data.isNull()) {
        return;
    }

    //qDebug() << "frmMapGps" << type << data;
    QString result = data.toString();
    if (type == "point") {
        if (ui->ckSelectAddr->isChecked()) {
            //Judge where it is checked and set where it is
            QString point = WebHelper::getLngLat2(result);
            //Judge where it is checked and set where it is
            if (ui->rbtnStartAddr->isChecked()) {
                ui->txtStartAddr->setText(point);
            } else {
                ui->txtEndAddr->setText(point);
            }
        }
    } else if (type == "routepoints") {
        //Convert the query path into longitude and latitude coordinate point set data display
        routeDatas.clear();
        ui->tableWidgetSource->clearContents();
        //There may be multiple path sets. At present, the test is one path set
        QStringList datas = result.split("|");
        foreach (QString data, datas) {
            QStringList points = data.split(";");
            routeDatas << points;
            int count = points.count();
            ui->tableWidgetSource->setRowCount(count);
            for (int i = 0; i < count; ++i) {
                addItem(ui->tableWidgetSource, i, points.at(i));
            }
        }

        setInfo(0, 0, 0);
    }
}

void frmMapGps::runJs(const QString &js)
{
    web->runJs(js);
}

void frmMapGps::on_btnSearchData_clicked()
{
    QString startAddr = ui->txtStartAddr->text().trimmed();
    QString endAddr = ui->txtEndAddr->text().trimmed();
    baidu->setRotueInfo(2, 0, startAddr, endAddr);
    this->loadMap();
}

void frmMapGps::moveMarker()
{
    QTableWidget *tableWidget = getTableWidget();
    int row = tableWidget->currentRow();
    int count = tableWidget->rowCount();
    if (row >= 0 && row < count) {
        //Find the angle from the previous point
        int angle = 0;
        QString point = tableWidget->item(row, 1)->data(Qt::UserRole).toString();
        //The first and last points are not handled
        if (row > 0 && row < count - 1) {
            //Previous point coordinates
            QString point2 = tableWidget->item(row - 1, 1)->data(Qt::UserRole).toString();
            //Calculates the rotation angle between the current previous point and the current point
            angle = WebHelper::getAngle(point2, point);
        }

        //Execute the mobile device point function, with the parameter of rotation angle
        QString js = QString("moveMarker('%1', '%2', %3)").arg(name).arg(point).arg(angle);
        runJs(js);

        //Redraw track points
        if (ui->cboxMoveMode->currentIndex() == 0) {
            //Clear previous track points
            js = QString("deleteOverlay('Polyline')");
            runJs(js);

            //Take out the points from the first point to the line where the current focus is located to form the set of track points that have been passed and draw again
            QStringList points;
            for (int i = 0; i <= row; ++i) {
                points << tableWidget->item(i, 1)->data(Qt::UserRole).toString();
            }

            js = QString("addPolyline('%1')").arg(points.join("|"));
            runJs(js);
        }

        //Display the current data
        setInfo(angle, row + 1, count);
        tableWidget->setCurrentCell(row + 1, 0);
    } else {
        on_btnTestData_clicked();
    }
}

void frmMapGps::on_btnTestData_clicked()
{
    QTableWidget *tableWidget = getTableWidget();
    if (ui->btnTestData->text() == "Simulated trajectory") {
        //Limit minimum quantity
        if (tableWidget->rowCount() < 2) {
            return;
        }

        //Step 1: add a tag
        name = ui->txtDeviceName->text().trimmed();
        if (name.isEmpty()) {
            name = "Malaysia Airlines MH370";
        }

        //The image file is in the config/device directory under the executable file
        QString icon = "./device/device_airplane.png";
        int size = 60;
        QString js = QString("addMarker('%1', '', '', '', 60, '%1', 0, 0, '%2', %3)").arg(name).arg(icon).arg(size);
        runJs(js);

        //Step 2: move to the first point
        tableWidget->setFocus();
        tableWidget->setCurrentCell(0, 0);
        ui->btnTestData->setText("Stop simulation");
        ui->tabWidget->setTabEnabled(ui->tableWidgetSource->isVisible() ? 1 : 0, false);

        //Step 3: start the timer and execute it immediately
        int index = ui->cboxMoveInterval->currentIndex();
        timer->start(ui->cboxMoveInterval->itemData(index).toInt());
        moveMarker();
    } else {
        //Empty tag
        QString js = QString("deleteMarker('%1')").arg(name);
        runJs(js);

        //Stop Timer 
        timer->stop();
        ui->btnTestData->setText("Simulated trajectory");
        ui->tabWidget->setTabEnabled(ui->tableWidgetSource->isVisible() ? 1 : 0, true);
    }
}

void frmMapGps::on_btnCheckData_clicked()
{
    if (timer->isActive()) {
        return;
    }

    //Step 1: calculate the total number, and find the average value = actual total number / expected total number + 1. If the expected total number > = actual total number, it does not need to be processed
    int countSource = ui->tableWidgetSource->rowCount();
    int countTarget = ui->txtPointCount->text().trimmed().toInt();
    if (countTarget >= countSource) {
        QUIHelper::showMessageBoxError("The target number of points cannot be greater than or equal to the original data!");
        ui->txtPointCount->setFocus();
        return;
    }

    //Step 2: take out the values one by one according to the average value
    QStringList points;
    int avg = countSource / countTarget + 1;
    for (int i = 0; i < countSource; i += avg) {
        QString point = ui->tableWidgetSource->item(i, 1)->data(Qt::UserRole).toString();
        points << point;
    }

    //The end must be added as the end. If it is just divided, it is not used
    QString point = ui->tableWidgetSource->item(countSource - 1, 1)->data(Qt::UserRole).toString();
    if (points.last() != point) {
        points << point;
    }

    //Step 3: refill the data into the filtered data list
    int count = points.count();
    ui->tableWidgetTarget->clearContents();
    ui->tableWidgetTarget->setRowCount(count);
    for (int i = 0; i < count; ++i) {
        addItem(ui->tableWidgetTarget, i, points.at(i));
    }

    ui->tabWidget->setCurrentIndex(1);
}

void frmMapGps::on_btnDrawData_clicked()
{
    if (routeDatas.count() == 0) {
        QUIHelper::showMessageBoxError("Please click query route to obtain the coordinate point collection of the route!");
        return;
    }

    //Clear previous track points
    runJs("deleteOverlay('Polyline')");

    //Draw the received set of path points into segments
    foreach (QStringList data, routeDatas) {
        QString points = data.join("|");
        QString js = QString("addPolyline('%1', '#ff0000')").arg(points);
        runJs(js);
    }
}

Topics: Qt Computer Vision