QGIS API Documentation 3.99.0-Master (26c88405ac0)
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 <QtCore/QBuffer>
31
33{
34 try
35 {
36 // The latitude and longitude values are given in radians!
37 // 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?
38
39 const double west = region[0].get<double>() * 180 / M_PI;
40 const double south = region[1].get<double>() * 180 / M_PI;
41 const double east = region[2].get<double>() * 180 / M_PI;
42 const double north = region[3].get<double>() * 180 / M_PI;
43 double minHeight = region[4].get<double>();
44 double maxHeight = region[5].get<double>();
45
46 return QgsBox3D( west, south, minHeight, east, north, maxHeight );
47 }
48 catch ( nlohmann::json::exception & )
49 {
50 return QgsBox3D();
51 }
52}
53
54QgsBox3D QgsCesiumUtils::parseRegion( const QVariantList &region )
55{
56 if ( region.size() != 6 )
57 return QgsBox3D();
58
60}
61
63{
64 if ( box.size() != 12 )
65 return QgsOrientedBox3D();
66
67 try
68 {
70 for ( int i = 0; i < 3; ++i )
71 {
72 res.mCenter[i] = box[i].get<double>();
73 }
74 for ( int i = 0; i < 9; ++i )
75 {
76 res.mHalfAxes[i] = box[i + 3].get<double>();
77 }
78 return res;
79 }
80 catch ( nlohmann::json::exception & )
81 {
82 return QgsOrientedBox3D();
83 }
84}
85
87{
88 if ( box.size() != 12 )
89 return QgsOrientedBox3D();
90
92}
93
95{
96 if ( sphere.size() != 4 )
97 return QgsSphere();
98
99 try
100 {
101 const double centerX = sphere[0].get<double>();
102 const double centerY = sphere[1].get<double>();
103 const double centerZ = sphere[2].get<double>();
104 const double radius = sphere[3].get<double>();
105 return QgsSphere( centerX, centerY, centerZ, radius );
106 }
107 catch ( nlohmann::json::exception & )
108 {
109 return QgsSphere();
110 }
111}
112
113QgsSphere QgsCesiumUtils::parseSphere( const QVariantList &sphere )
114{
115 if ( sphere.size() != 4 )
116 return QgsSphere();
117
118 return parseSphere( QgsJsonUtils::jsonFromVariant( sphere ) );
119}
120
122{
123 if ( !transform.isIdentity() )
124 {
125 // center is transformed, radius is scaled by maximum scalar from transform
126 // see https://github.com/CesiumGS/cesium-native/blob/fd20f5e272850dde6b58c74059e6de767fe25df6/Cesium3DTilesSelection/src/BoundingVolume.cpp#L33
127 const QgsVector3D center = transform.map( sphere.centerVector() );
128 const double uniformScale = std::max(
129 std::max(
130 std::sqrt(
131 transform.constData()[0] * transform.constData()[0] +
132 transform.constData()[1] * transform.constData()[1] +
133 transform.constData()[2] * transform.constData()[2] ),
134 std::sqrt(
135 transform.constData()[4] * transform.constData()[4] +
136 transform.constData()[5] * transform.constData()[5] +
137 transform.constData()[6] * transform.constData()[6] ) ),
138 std::sqrt(
139 transform.constData()[8] * transform.constData()[8] +
140 transform.constData()[9] * transform.constData()[9] +
141 transform.constData()[10] * transform.constData()[10] ) );
142
143 return QgsSphere( center.x(), center.y(), center.z(), sphere.radius() * uniformScale );
144 }
145 return sphere;
146}
147
149{
150 struct b3dmHeader
151 {
152 unsigned char magic[4];
153 quint32 version;
154 quint32 byteLength;
155 quint32 featureTableJsonByteLength;
156 quint32 featureTableBinaryByteLength;
157 quint32 batchTableJsonByteLength;
158 quint32 batchTableBinaryByteLength;
159 };
160
162 if ( tileContent.size() < static_cast<int>( sizeof( b3dmHeader ) ) )
163 return res;
164
165 b3dmHeader hdr;
166 memcpy( &hdr, tileContent.constData(), sizeof( b3dmHeader ) );
167
168 const QString featureTableJson( tileContent.mid( sizeof( b3dmHeader ), hdr.featureTableJsonByteLength ) );
169 if ( !featureTableJson.isEmpty() )
170 {
171 try
172 {
173 const json featureTable = json::parse( featureTableJson.toStdString() );
174 if ( featureTable.contains( "RTC_CENTER" ) )
175 {
176 const auto &rtcCenterJson = featureTable[ "RTC_CENTER" ];
177 if ( rtcCenterJson.is_array() && rtcCenterJson.size() == 3 )
178 {
179 res.rtcCenter.setX( rtcCenterJson[0].get<double>() );
180 res.rtcCenter.setY( rtcCenterJson[1].get<double>() );
181 res.rtcCenter.setZ( rtcCenterJson[2].get<double>() );
182 }
183 else
184 {
185 QgsDebugError( QStringLiteral( "Invalid RTC_CENTER value" ) );
186 }
187 }
188 }
189 catch ( json::parse_error &ex )
190 {
191 QgsDebugError( QStringLiteral( "Error parsing feature table JSON: %1" ).arg( ex.what() ) );
192 }
193 }
194
195 res.gltf = tileContent.mid( sizeof( b3dmHeader ) +
196 hdr.featureTableJsonByteLength + hdr.featureTableBinaryByteLength +
197 hdr.batchTableJsonByteLength + hdr.batchTableBinaryByteLength );
198 return res;
199}
200
202{
203 TileContents res;
204 if ( tileContent.startsWith( QByteArray( "b3dm" ) ) )
205 {
206 const B3DMContents b3dmContents = QgsCesiumUtils::extractGltfFromB3dm( tileContent );
207 res.gltf = b3dmContents.gltf;
208 res.rtcCenter = b3dmContents.rtcCenter;
209 return res;
210 }
211 else if ( tileContent.startsWith( QByteArray( "glTF" ) ) )
212 {
213 res.gltf = tileContent;
214 return res;
215 }
216 else
217 {
218 // unsupported tile content type
219 // TODO: we could extract "b3dm" data from a composite tile ("cmpt")
220 return res;
221 }
222}
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:42
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:42
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:140
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:30
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:49
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:51
void setZ(double z)
Sets Z coordinate.
Definition qgsvector3d.h:69
double x() const
Returns X coordinate.
Definition qgsvector3d.h:47
void setX(double x)
Sets X coordinate.
Definition qgsvector3d.h:57
void setY(double y)
Sets Y coordinate.
Definition qgsvector3d.h:63
#define QgsDebugError(str)
Definition qgslogger.h:57
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.