QGIS API Documentation 3.99.0-Master (e9821da5c6b)
Loading...
Searching...
No Matches
qgscesiumutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscesiumutils.cpp
3 --------------------
4 begin : July 2023
5 copyright : (C) 2023 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ******************************************************************
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19#include "qgscesiumutils.h"
20
21#include <nlohmann/json.hpp>
22
23#include "qgsjsonutils.h"
24#include "qgslogger.h"
25#include "qgsmatrix4x4.h"
26#include "qgsorientedbox3d.h"
27#include "qgssphere.h"
28
29#include <QIODevice>
30#include <QString>
31#include <QtCore/QBuffer>
32
33using namespace Qt::StringLiterals;
34
36{
37 try
38 {
39 // The latitude and longitude values are given in radians!
40 // TODO -- is this ALWAYS the case? What if there's a region root bounding volume, but a transform object present? What if there's crs metadata specifying a different crs?
41
42 const double west = region[0].get<double>() * 180 / M_PI;
43 const double south = region[1].get<double>() * 180 / M_PI;
44 const double east = region[2].get<double>() * 180 / M_PI;
45 const double north = region[3].get<double>() * 180 / M_PI;
46 double minHeight = region[4].get<double>();
47 double maxHeight = region[5].get<double>();
48
49 return QgsBox3D( west, south, minHeight, east, north, maxHeight );
50 }
51 catch ( nlohmann::json::exception & )
52 {
53 return QgsBox3D();
54 }
55}
56
57QgsBox3D QgsCesiumUtils::parseRegion( const QVariantList &region )
58{
59 if ( region.size() != 6 )
60 return QgsBox3D();
61
63}
64
66{
67 if ( box.size() != 12 )
68 return QgsOrientedBox3D();
69
70 try
71 {
73 for ( int i = 0; i < 3; ++i )
74 {
75 res.mCenter[i] = box[i].get<double>();
76 }
77 for ( int i = 0; i < 9; ++i )
78 {
79 res.mHalfAxes[i] = box[i + 3].get<double>();
80 }
81 return res;
82 }
83 catch ( nlohmann::json::exception & )
84 {
85 return QgsOrientedBox3D();
86 }
87}
88
90{
91 if ( box.size() != 12 )
92 return QgsOrientedBox3D();
93
95}
96
98{
99 if ( sphere.size() != 4 )
100 return QgsSphere();
101
102 try
103 {
104 const double centerX = sphere[0].get<double>();
105 const double centerY = sphere[1].get<double>();
106 const double centerZ = sphere[2].get<double>();
107 const double radius = sphere[3].get<double>();
108 return QgsSphere( centerX, centerY, centerZ, radius );
109 }
110 catch ( nlohmann::json::exception & )
111 {
112 return QgsSphere();
113 }
114}
115
116QgsSphere QgsCesiumUtils::parseSphere( const QVariantList &sphere )
117{
118 if ( sphere.size() != 4 )
119 return QgsSphere();
120
121 return parseSphere( QgsJsonUtils::jsonFromVariant( sphere ) );
122}
123
125{
126 if ( !transform.isIdentity() )
127 {
128 // center is transformed, radius is scaled by maximum scalar from transform
129 // see https://github.com/CesiumGS/cesium-native/blob/fd20f5e272850dde6b58c74059e6de767fe25df6/Cesium3DTilesSelection/src/BoundingVolume.cpp#L33
130 const QgsVector3D center = transform.map( sphere.centerVector() );
131 const double uniformScale = std::max(
132 std::max(
133 std::sqrt(
134 transform.constData()[0] * transform.constData()[0] +
135 transform.constData()[1] * transform.constData()[1] +
136 transform.constData()[2] * transform.constData()[2] ),
137 std::sqrt(
138 transform.constData()[4] * transform.constData()[4] +
139 transform.constData()[5] * transform.constData()[5] +
140 transform.constData()[6] * transform.constData()[6] ) ),
141 std::sqrt(
142 transform.constData()[8] * transform.constData()[8] +
143 transform.constData()[9] * transform.constData()[9] +
144 transform.constData()[10] * transform.constData()[10] ) );
145
146 return QgsSphere( center.x(), center.y(), center.z(), sphere.radius() * uniformScale );
147 }
148 return sphere;
149}
150
152{
153 struct b3dmHeader
154 {
155 unsigned char magic[4];
156 quint32 version;
157 quint32 byteLength;
158 quint32 featureTableJsonByteLength;
159 quint32 featureTableBinaryByteLength;
160 quint32 batchTableJsonByteLength;
161 quint32 batchTableBinaryByteLength;
162 };
163
165 if ( tileContent.size() < static_cast<int>( sizeof( b3dmHeader ) ) )
166 return res;
167
168 b3dmHeader hdr;
169 memcpy( &hdr, tileContent.constData(), sizeof( b3dmHeader ) );
170
171 const QString featureTableJson( tileContent.mid( sizeof( b3dmHeader ), hdr.featureTableJsonByteLength ) );
172 if ( !featureTableJson.isEmpty() )
173 {
174 try
175 {
176 const json featureTable = json::parse( featureTableJson.toStdString() );
177 if ( featureTable.contains( "RTC_CENTER" ) )
178 {
179 const auto &rtcCenterJson = featureTable[ "RTC_CENTER" ];
180 if ( rtcCenterJson.is_array() && rtcCenterJson.size() == 3 )
181 {
182 res.rtcCenter.setX( rtcCenterJson[0].get<double>() );
183 res.rtcCenter.setY( rtcCenterJson[1].get<double>() );
184 res.rtcCenter.setZ( rtcCenterJson[2].get<double>() );
185 }
186 else
187 {
188 QgsDebugError( u"Invalid RTC_CENTER value"_s );
189 }
190 }
191 }
192 catch ( json::parse_error &ex )
193 {
194 QgsDebugError( u"Error parsing feature table JSON: %1"_s.arg( ex.what() ) );
195 }
196 }
197
198 res.gltf = tileContent.mid( sizeof( b3dmHeader ) +
199 hdr.featureTableJsonByteLength + hdr.featureTableBinaryByteLength +
200 hdr.batchTableJsonByteLength + hdr.batchTableBinaryByteLength );
201 return res;
202}
203
205{
206 TileContents res;
207 if ( tileContent.startsWith( QByteArray( "b3dm" ) ) )
208 {
209 const B3DMContents b3dmContents = QgsCesiumUtils::extractGltfFromB3dm( tileContent );
210 res.gltf = b3dmContents.gltf;
211 res.rtcCenter = b3dmContents.rtcCenter;
212 return res;
213 }
214 else if ( tileContent.startsWith( QByteArray( "glTF" ) ) )
215 {
216 res.gltf = tileContent;
217 return res;
218 }
219 else
220 {
221 // unsupported tile content type
222 // TODO: we could extract "b3dm" data from a composite tile ("cmpt")
223 return res;
224 }
225}
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:45
static QgsSphere parseSphere(const json &sphere)
Parses a sphere object from a Cesium JSON document.
static B3DMContents extractGltfFromB3dm(const QByteArray &tileContent)
Extracts GLTF binary data and other contents from the legacy b3dm (Batched 3D Model) tile format.
static QgsOrientedBox3D parseBox(const json &box)
Parses a box object from a Cesium JSON document to an oriented bounding box.
static QgsBox3D parseRegion(const json &region)
Parses a region object from a Cesium JSON object to a 3D box.
static QgsSphere transformSphere(const QgsSphere &sphere, const QgsMatrix4x4 &transform)
Applies a transform to a sphere.
static TileContents extractGltfFromTileContent(const QByteArray &tileContent)
Parses tile content.
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
A simple 4x4 matrix implementation useful for transformation in 3D space.
bool isIdentity() const
Returns whether this matrix is an identity matrix.
QgsVector3D map(const QgsVector3D &vector) const
Matrix-vector multiplication (vector is converted to homogeneous coordinates [X,Y,...
const double * constData() const
Returns pointer to the matrix data (stored in column-major order).
Represents a oriented (rotated) box in 3 dimensions.
A spherical geometry object.
Definition qgssphere.h:46
QgsVector3D centerVector() const
Returns the vector to the center of the sphere.
Definition qgssphere.cpp:49
double radius() const
Returns the radius of the sphere.
Definition qgssphere.h:144
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:33
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:52
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:54
void setZ(double z)
Sets Z coordinate.
Definition qgsvector3d.h:72
double x() const
Returns X coordinate.
Definition qgsvector3d.h:50
void setX(double x)
Sets X coordinate.
Definition qgsvector3d.h:60
void setY(double y)
Sets Y coordinate.
Definition qgsvector3d.h:66
#define QgsDebugError(str)
Definition qgslogger.h:59
Encapsulates the contents of a B3DM file.
QByteArray gltf
GLTF binary content.
QgsVector3D rtcCenter
Optional RTC center.
Encapsulates the contents of a 3D tile.
QgsVector3D rtcCenter
Center position of relative-to-center coordinates (when used).
QByteArray gltf
GLTF binary content.