PyQt5のQGraphicsViewにGPXファイルを表示してワイプも表示してみた

以前作成したGPXファイルを表示するプログラムにワイプを表示する機能を追加してみました。イメージはAviUtlのVSD for GPSなどで作成する動画のような感じです。

ワイプの表示

GPXファイルの読み込みはgpxpyを使用して、QGraphicsViewのQGraphicsScene上にアイテムを描画していて、これらの処理は以前作成したプログラムと同じです。ワイプ部分は、読み込んだGPXファイルの一部分をnumpy配列のスライスで抜き出して、QGraphicsPathItemとして描画するという処理にしています。

x1, y1 = self.gpx_position[0], self.gpx_position[1]
ellipse1 = QtWidgets.QGraphicsEllipseItem()
ellipse1.setRect(x1 - self.ellipse_size/2, y1 - self.ellipse_size/2, self.ellipse_size, self.ellipse_size)

array = self.gpx[:, s:e]
polygon = QtGui.QPolygonF()
polygon_offset_x, polygon_offset_y = x1 - self.gpx[0][self.gpx_index], y1 - self.gpx[1][self.gpx_index]
for lat, lon in zip(array[0], array[1]):
    polygon.append( QtCore.QPointF(polygon_offset_x + lat, polygon_offset_y + lon) )
path = QtGui.QPainterPath()
path.addPolygon(polygon)
item = QtWidgets.QGraphicsPathItem(path)

ソースコード

import cv2
import gpxpy
import numpy as np
import sys
from PyQt5 import QtWidgets, QtCore, QtGui

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.central_widget = QtWidgets.QWidget(self)
        self.vertical_layout = QtWidgets.QVBoxLayout(self.central_widget)
        self.graphics_view = QtWidgets.QGraphicsView(self.central_widget)
        self.graphics_view.setScene( QtWidgets.QGraphicsScene(0, 0, 600, 600, self.graphics_view) )
        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self.central_widget)
        self.vertical_layout.addWidget(self.graphics_view)
        self.vertical_layout.addWidget(self.slider)
        self.setCentralWidget(self.central_widget)
        self.resize(800, 660)
        self.slider.valueChanged.connect(self.update_view)

        self.gpx = None
        self.gpx_index = 0
        self.gpx_index_max = 0
        self.gpx_range = 20
        self.gpx_size = 600
        self.gpx_position = [500, 100]
        self.ellipse_size = 10
        self.gpx_polygon = None

    def update_view(self):
        self.gpx_index = self.slider.value()
        s, e = self.gpx_index - self.gpx_range, self.gpx_index + self.gpx_range
        if s < 0:
            s = 0
        if e > self.gpx_index_max - 1:
            e = self.gpx_index_max - 1
        x1, y1 = self.gpx_position[0], self.gpx_position[1]

        ellipse1 = QtWidgets.QGraphicsEllipseItem()
        ellipse1.setRect(x1 - self.ellipse_size/2, y1 - self.ellipse_size/2, self.ellipse_size, self.ellipse_size)

        ellipse2 = QtWidgets.QGraphicsEllipseItem()
        x2, y2 = self.gpx_polygon.at(self.gpx_index).x(), self.gpx_polygon.at(self.gpx_index).y()
        ellipse2.setRect(x2 - self.ellipse_size/2, y2 - self.ellipse_size/2, self.ellipse_size, self.ellipse_size)

        array = self.gpx[:, s:e]
        polygon = QtGui.QPolygonF()
        polygon_offset_x, polygon_offset_y = x1 - self.gpx[0][self.gpx_index], y1 - self.gpx[1][self.gpx_index]
        for lat, lon in zip(array[0], array[1]):
            polygon.append( QtCore.QPointF(polygon_offset_x + lat, polygon_offset_y + lon) )
        path = QtGui.QPainterPath()
        path.addPolygon(polygon)
        item = QtWidgets.QGraphicsPathItem(path)

        self.graphics_view.scene().clear()
        self.graphics_view.scene().addItem(QtWidgets.QGraphicsPolygonItem(self.gpx_polygon))
        self.graphics_view.scene().addItem(item)
        self.graphics_view.scene().addItem(ellipse1)
        self.graphics_view.scene().addItem(ellipse2)

    def set_array(self, array):
        self.gpx = array.copy()
        self.gpx[0] = ( self.gpx[0] - min(self.gpx[0]) )
        self.gpx[0] = self.gpx[0] * (self.gpx_size / max(self.gpx[0]) )
        self.gpx[1] = ( self.gpx[1] - min(self.gpx[1]) )
        self.gpx[1] = self.gpx_size - self.gpx[1] * (self.gpx_size / max(self.gpx[1]) )
        self.gpx_index = 0
        self.gpx_index_max = array.shape[1]
        self.slider.setMaximum(self.gpx_index_max-1)
        
        lon_def = array[0] - min(array[0])
        lat_def = array[1] - min(array[1])
        if max(lon_def) > max(lat_def):
            ratio = 600 / max(lon_def)
        else:
            ratio = 600 / max(lat_def)
        polygon = QtGui.QPolygonF()
        longitude = (lon_def) * ratio
        latitude = 600 - (lat_def) * ratio
        for lat, lon in zip(longitude, latitude):
            polygon.append( QtCore.QPointF(lat, lon) )
        self.gpx_polygon = polygon

        self.update_view()

def main():
    gpx_file = open('track-1155.gpx', mode='r', encoding='utf8')
    gpx = gpxpy.parse(gpx_file)

    array = np.array([ 
        [p.longitude for p in gpx.tracks[0].segments[0].points], 
        [p.latitude for p in gpx.tracks[0].segments[0].points] 
    ])

    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.set_array(array)
    window.show()
    app.exec()

if __name__ == '__main__':
    main()

記事の共有

関連記事

コメント

comments powered by Disqus