1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from PySide6.QtQuick3D import QQuick3DTextureData
from PySide6.QtQml import QmlElement
from PySide6.QtGui import QImage, QVector3D
from PySide6.QtCore import QByteArray, QObject, Property, Slot, Signal
from request import OSMTileData, OSMRequest
# To be used on the @QmlElement decorator
# (QML_IMPORT_MINOR_VERSION is optional)
QML_IMPORT_NAME = "OSMBuildings"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class OSMManager(QObject):
mapsDataReady = Signal(QByteArray, int, int, int)
def __init__(self, parent=None):
super().__init__(parent)
self.m_request = OSMRequest(self)
self.m_startBuildingTileX = 17605
self.m_startBuildingTileY = 10746
self.m_tileSizeX = 37
self.m_tileSizeY = 37
self.m_request.mapsDataReady.connect(self._slotMapsDataReady)
def tileSizeX(self):
return self.m_tileSizeX
def tileSizeY(self):
return self.m_tileSizeY
@Slot(QByteArray, int, int, int)
def _slotMapsDataReady(self, mapData, tileX, tileY, zoomLevel):
self.mapsDataReady.emit(mapData, tileX - self.m_startBuildingTileX,
tileY - self.m_startBuildingTileY, zoomLevel)
@Slot(QVector3D, QVector3D, float, float, float, float, float, float)
def setCameraProperties(self, position, right,
cameraZoom, minimumZoom, maximumZoom,
cameraTilt, minimumTilt, maximumTilt):
tiltFactor = (cameraTilt - minimumTilt) / max(maximumTilt - minimumTilt, 1.0)
zoomFactor = (cameraZoom - minimumZoom) / max(maximumZoom - minimumZoom, 1.0)
# Forward vector align to the XY plane
forwardVector = QVector3D.crossProduct(right, QVector3D(0.0, 0.0, -1.0)).normalized()
projectionOfForwardOnXY = position + forwardVector * tiltFactor * zoomFactor * 50.0
queue = []
for forwardIndex in range(-20, 21):
for sidewardIndex in range(-20, 21):
vx = float(self.m_tileSizeX * sidewardIndex)
vy = float(self.m_tileSizeY * forwardIndex)
transferredPosition = projectionOfForwardOnXY + QVector3D(vx, vy, 0)
tile_x = self.m_startBuildingTileX + int(transferredPosition.x() / self.m_tileSizeX)
tile_y = self.m_startBuildingTileY - int(transferredPosition.y() / self.m_tileSizeY)
self.addBuildingRequestToQueue(queue, tile_x, tile_y)
projectedTileX = (self.m_startBuildingTileX + int(projectionOfForwardOnXY.x()
/ self.m_tileSizeX))
projectedTileY = (self.m_startBuildingTileY - int(projectionOfForwardOnXY.y()
/ self.m_tileSizeY))
def tile_sort_key(tile_data):
return tile_data.distanceTo(projectedTileX, projectedTileY)
queue.sort(key=tile_sort_key)
self.m_request.getMapsData(queue.copy())
def addBuildingRequestToQueue(self, queue, tileX, tileY, zoomLevel=15):
queue.append(OSMTileData(tileX, tileY, zoomLevel))
@Slot(result=bool)
def isDemoToken(self):
return self.m_request.isDemoToken()
@Slot(str)
def setToken(self, token):
self.m_request.setToken(token)
@Slot(result=str)
def token(self):
return self.m_request.token()
tileSizeX = Property(int, tileSizeX, constant=True)
tileSizeY = Property(int, tileSizeY, constant=True)
@QmlElement
class CustomTextureData(QQuick3DTextureData):
@Slot(QByteArray)
def setImageData(self, data):
image = QImage.fromData(data).convertToFormat(QImage.Format.Format_RGBA8888)
self.setTextureData(QByteArray(bytearray(image.constBits())))
self.setSize(image.size())
self.setHasTransparency(False)
self.setFormat(QQuick3DTextureData.Format.RGBA8)
|