mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -04:00
Remove abstract class for bounding volumes, and always treat
bounding volumes as OBB Greatly simplifies the code. There's a small loss of efficiency since we will always be expanding out spheres to their bounding boxes, but given we always require boxes for QGIS 3d nodes anyway this will only impact 2d rendering.
This commit is contained in:
parent
1c265af5e4
commit
0e363e66c2
@ -40,6 +40,11 @@ Parses a ``box`` object from a Cesium JSON document to an oriented bounding box.
|
||||
static QgsSphere parseSphere( const QVariantList &sphere );
|
||||
%Docstring
|
||||
Parses a ``sphere`` object from a Cesium JSON document.
|
||||
%End
|
||||
|
||||
static QgsSphere transformSphere( const QgsSphere &sphere, const QgsMatrix4x4 &transform );
|
||||
%Docstring
|
||||
Applies a ``transform`` to a sphere.
|
||||
%End
|
||||
|
||||
static QByteArray extractGltfFromB3dm( const QByteArray &tileContent );
|
||||
|
@ -10,10 +10,10 @@
|
||||
|
||||
|
||||
|
||||
class QgsAbstractTiledSceneBoundingVolume
|
||||
class QgsTiledSceneBoundingVolume
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
Abstract base class for bounding volumes for tiled scene nodes.
|
||||
Represents a bounding volume for a tiled scene.
|
||||
|
||||
.. versionadded:: 3.34
|
||||
%End
|
||||
@ -23,32 +23,12 @@ Abstract base class for bounding volumes for tiled scene nodes.
|
||||
%End
|
||||
public:
|
||||
|
||||
%ConvertToSubClassCode
|
||||
switch ( sipCpp->type() )
|
||||
{
|
||||
case Qgis::TiledSceneBoundingVolumeType::Region:
|
||||
sipType = sipType_QgsTiledSceneBoundingVolumeRegion;
|
||||
break;
|
||||
case Qgis::TiledSceneBoundingVolumeType::OrientedBox:
|
||||
sipType = sipType_QgsTiledSceneBoundingVolumeBox;
|
||||
break;
|
||||
case Qgis::TiledSceneBoundingVolumeType::Sphere:
|
||||
sipType = sipType_QgsTiledSceneBoundingVolumeSphere;
|
||||
break;
|
||||
default:
|
||||
sipType = 0;
|
||||
break;
|
||||
};
|
||||
%End
|
||||
|
||||
virtual ~QgsAbstractTiledSceneBoundingVolume();
|
||||
|
||||
virtual Qgis::TiledSceneBoundingVolumeType type() const = 0;
|
||||
QgsTiledSceneBoundingVolume( const QgsOrientedBox3D &box = QgsOrientedBox3D() );
|
||||
%Docstring
|
||||
Returns the type of the volume;
|
||||
Constructor for QgsTiledSceneBoundingVolume, with the specified oriented ``box``.
|
||||
%End
|
||||
|
||||
virtual QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const = 0;
|
||||
QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const;
|
||||
%Docstring
|
||||
Returns the axis aligned bounding box of the volume.
|
||||
|
||||
@ -56,12 +36,7 @@ The optional ``transform`` and ``direction`` arguments should be used whenever t
|
||||
to be transformed into a specific destination CRS, in order to correctly handle 3D coordinate transforms.
|
||||
%End
|
||||
|
||||
virtual QgsAbstractTiledSceneBoundingVolume *clone() const = 0 /Factory/;
|
||||
%Docstring
|
||||
Returns a clone of the volume.
|
||||
%End
|
||||
|
||||
virtual QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const = 0 /Factory/;
|
||||
QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const /Factory/;
|
||||
%Docstring
|
||||
Returns a new geometry representing the 2-dimensional X/Y center slice of the volume.
|
||||
|
||||
@ -71,92 +46,16 @@ The optional ``transform`` and ``direction`` arguments should be used whenever t
|
||||
to be transformed into a specific destination CRS, in order to correctly handle 3D coordinate transforms.
|
||||
%End
|
||||
|
||||
virtual void transform( const QgsMatrix4x4 &transform ) = 0;
|
||||
void transform( const QgsMatrix4x4 &transform );
|
||||
%Docstring
|
||||
Applies a ``transform`` to the bounding volume.
|
||||
|
||||
The actual result of transforming a bounding volume depends on subclass specific logic. For instance:
|
||||
|
||||
- transforming a :py:class:`QgsTiledSceneBoundingVolumeRegion` results in no change to the region
|
||||
- transforming a :py:class:`QgsTiledSceneBoundingVolumeSphere` causes the radius to be multiplied by the maximum length of the transform scales
|
||||
%End
|
||||
|
||||
virtual bool intersects( const QgsOrientedBox3D &box ) const = 0;
|
||||
bool intersects( const QgsOrientedBox3D &box ) const;
|
||||
%Docstring
|
||||
Returns ``True`` if this bounds intersects the specified ``box``.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
class QgsTiledSceneBoundingVolumeRegion : QgsAbstractTiledSceneBoundingVolume
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
A region bounding volume for tiled scene nodes.
|
||||
|
||||
.. versionadded:: 3.34
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgstiledsceneboundingvolume.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsTiledSceneBoundingVolumeRegion( const QgsBox3D ®ion );
|
||||
%Docstring
|
||||
Constructor for QgsTiledSceneBoundingVolumeRegion, with the specified ``region``.
|
||||
%End
|
||||
|
||||
virtual Qgis::TiledSceneBoundingVolumeType type() const ${SIP_FINAL};
|
||||
|
||||
virtual void transform( const QgsMatrix4x4 &transform ) ${SIP_FINAL};
|
||||
|
||||
virtual QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const ${SIP_FINAL} throw( QgsCsException );
|
||||
|
||||
virtual QgsTiledSceneBoundingVolumeRegion *clone() const ${SIP_FINAL} /Factory/;
|
||||
|
||||
virtual QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const ${SIP_FINAL} throw( QgsCsException ) /Factory/;
|
||||
|
||||
virtual bool intersects( const QgsOrientedBox3D &box ) const ${SIP_FINAL};
|
||||
|
||||
|
||||
QgsBox3D region() const;
|
||||
%Docstring
|
||||
Returns the volume's region.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
class QgsTiledSceneBoundingVolumeBox : QgsAbstractTiledSceneBoundingVolume
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
A oriented box bounding volume for tiled scene nodes.
|
||||
|
||||
.. versionadded:: 3.34
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgstiledsceneboundingvolume.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsTiledSceneBoundingVolumeBox( const QgsOrientedBox3D &box );
|
||||
%Docstring
|
||||
Constructor for QgsTiledSceneBoundingVolumeBox, with the specified oriented ``box``.
|
||||
%End
|
||||
|
||||
virtual Qgis::TiledSceneBoundingVolumeType type() const ${SIP_FINAL};
|
||||
|
||||
virtual void transform( const QgsMatrix4x4 &transform ) ${SIP_FINAL};
|
||||
|
||||
virtual QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const ${SIP_FINAL} throw( QgsCsException );
|
||||
|
||||
virtual QgsTiledSceneBoundingVolumeBox *clone() const ${SIP_FINAL} /Factory/;
|
||||
|
||||
virtual QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const ${SIP_FINAL} throw( QgsCsException ) /Factory/;
|
||||
|
||||
virtual bool intersects( const QgsOrientedBox3D &box ) const ${SIP_FINAL};
|
||||
|
||||
|
||||
QgsOrientedBox3D box() const;
|
||||
%Docstring
|
||||
Returns the volume's oriented box.
|
||||
@ -164,45 +63,6 @@ Returns the volume's oriented box.
|
||||
|
||||
};
|
||||
|
||||
class QgsTiledSceneBoundingVolumeSphere: QgsAbstractTiledSceneBoundingVolume
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
A spherical bounding volume for tiled scene nodes.
|
||||
|
||||
.. versionadded:: 3.34
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgstiledsceneboundingvolume.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsTiledSceneBoundingVolumeSphere( const QgsSphere &sphere );
|
||||
%Docstring
|
||||
Constructor for QgsTiledSceneBoundingVolumeSphere, with the specified ``sphere``.
|
||||
%End
|
||||
|
||||
virtual Qgis::TiledSceneBoundingVolumeType type() const ${SIP_FINAL};
|
||||
|
||||
virtual void transform( const QgsMatrix4x4 &transform ) ${SIP_FINAL};
|
||||
|
||||
virtual QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const ${SIP_FINAL} throw( QgsCsException );
|
||||
|
||||
virtual QgsTiledSceneBoundingVolumeSphere *clone() const ${SIP_FINAL} /Factory/;
|
||||
|
||||
virtual QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const ${SIP_FINAL} throw( QgsCsException ) /Factory/;
|
||||
|
||||
virtual bool intersects( const QgsOrientedBox3D &box ) const ${SIP_FINAL};
|
||||
|
||||
|
||||
QgsSphere sphere() const;
|
||||
%Docstring
|
||||
Returns the volume's sphere.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
@ -68,7 +68,7 @@ for the data provider for 2D use.
|
||||
transforming bounding volumes or geometries associated with the provider.
|
||||
%End
|
||||
|
||||
virtual const QgsAbstractTiledSceneBoundingVolume *boundingVolume() const = 0;
|
||||
virtual const QgsTiledSceneBoundingVolume &boundingVolume() const = 0;
|
||||
%Docstring
|
||||
Returns the bounding volume for the data provider.
|
||||
|
||||
|
@ -42,16 +42,20 @@ Returns the flags which affect how tiles are fetched.
|
||||
|
||||
QgsOrientedBox3D filterBox() const;
|
||||
%Docstring
|
||||
Returns the box from which data will be taken, in the layer's CRS.
|
||||
Returns the box from which data will be taken.
|
||||
|
||||
The CRS for the box can be retrieved by :py:func:`~QgsTiledSceneRequest.filterBoxCrs`.
|
||||
|
||||
If the returned box is null, then no filter box is set.
|
||||
|
||||
.. seealso:: :py:func:`filterBoxCrs`
|
||||
|
||||
.. seealso:: :py:func:`setFilterBox`
|
||||
%End
|
||||
|
||||
void setFilterBox( const QgsOrientedBox3D &box );
|
||||
%Docstring
|
||||
Sets the ``box`` from which data will be taken, in the layer's CRS.
|
||||
Sets the ``box`` from which data will be taken.
|
||||
|
||||
An null ``box`` removes the filter.
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsTiledSceneTile
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
@ -74,16 +73,14 @@ content is handled when its higher resolution children are also included.
|
||||
.. seealso:: :py:func:`refinementProcess`
|
||||
%End
|
||||
|
||||
void setBoundingVolume( QgsAbstractTiledSceneBoundingVolume *volume /Transfer/ );
|
||||
void setBoundingVolume( const QgsTiledSceneBoundingVolume &volume );
|
||||
%Docstring
|
||||
Sets the bounding ``volume`` for the tile.
|
||||
|
||||
Ownership of ``volume`` is transferred to the tile.
|
||||
|
||||
.. seealso:: :py:func:`boundingVolume`
|
||||
%End
|
||||
|
||||
const QgsAbstractTiledSceneBoundingVolume *boundingVolume() const;
|
||||
const QgsTiledSceneBoundingVolume &boundingVolume() const;
|
||||
%Docstring
|
||||
Returns the bounding volume for the tile.
|
||||
|
||||
|
@ -37,27 +37,8 @@ static bool hasLargeBounds( const QgsTiledSceneTile &t )
|
||||
if ( t.geometricError() > 1e6 )
|
||||
return true;
|
||||
|
||||
switch ( t.boundingVolume()->type() )
|
||||
{
|
||||
case Qgis::TiledSceneBoundingVolumeType::Region:
|
||||
{
|
||||
// TODO: is region always lat/lon in degrees?
|
||||
QgsBox3D region = static_cast<const QgsTiledSceneBoundingVolumeRegion *>( t.boundingVolume() )->region();
|
||||
return region.width() > 15 || region.height() > 15;
|
||||
}
|
||||
|
||||
case Qgis::TiledSceneBoundingVolumeType::OrientedBox:
|
||||
{
|
||||
QgsOrientedBox3D box = static_cast<const QgsTiledSceneBoundingVolumeBox *>( t.boundingVolume() )->box();
|
||||
QgsVector3D size = box.size();
|
||||
return size.x() > 1e5 || size.y() > 1e5 || size.z() > 1e5;
|
||||
}
|
||||
|
||||
case Qgis::TiledSceneBoundingVolumeType::Sphere:
|
||||
return static_cast<const QgsTiledSceneBoundingVolumeSphere *>( t.boundingVolume() )->sphere().diameter() > 1e5;
|
||||
}
|
||||
|
||||
return false;
|
||||
const QgsVector3D size = t.boundingVolume().box().size();
|
||||
return size.x() > 1e5 || size.y() > 1e5 || size.z() > 1e5;
|
||||
}
|
||||
|
||||
|
||||
@ -165,7 +146,6 @@ QgsTiledSceneChunkLoaderFactory::QgsTiledSceneChunkLoaderFactory( const Qgs3DMap
|
||||
: mMap( map ), mRelativePathBase( relativePathBase ), mIndex( index )
|
||||
{
|
||||
mBoundsTransform = QgsCoordinateTransform( QgsCoordinateReferenceSystem( "EPSG:4978" ), mMap.crs(), mMap.transformContext() );
|
||||
mRegionTransform = QgsCoordinateTransform( QgsCoordinateReferenceSystem( "EPSG:4979" ), mMap.crs(), mMap.transformContext() );
|
||||
}
|
||||
|
||||
QgsChunkLoader *QgsTiledSceneChunkLoaderFactory::createChunkLoader( QgsChunkNode *node ) const
|
||||
@ -195,9 +175,8 @@ QgsChunkNode *QgsTiledSceneChunkLoaderFactory::nodeForTile( const QgsTiledSceneT
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isRegion = t.boundingVolume()->type() == Qgis::TiledSceneBoundingVolumeType::Region;
|
||||
QgsBox3D box = t.boundingVolume()->bounds( isRegion ? mRegionTransform : mBoundsTransform );
|
||||
QgsAABB aabb = aabbConvert( box, mMap.origin() );
|
||||
const QgsBox3D box = t.boundingVolume().bounds( mBoundsTransform );
|
||||
const QgsAABB aabb = aabbConvert( box, mMap.origin() );
|
||||
return new QgsChunkNode( nodeId, aabb, t.geometricError() );
|
||||
}
|
||||
}
|
||||
@ -239,29 +218,26 @@ QVector<QgsChunkNode *> QgsTiledSceneChunkLoaderFactory::createChildren( QgsChun
|
||||
// if the tile is huge, let's try to see if our scene is actually inside
|
||||
// (if not, let' skip this child altogether!)
|
||||
// TODO: make OBB of our scene in ECEF rather than just using center of the scene?
|
||||
if ( t.boundingVolume()->type() == Qgis::TiledSceneBoundingVolumeType::OrientedBox )
|
||||
const QgsOrientedBox3D obb = t.boundingVolume().box();
|
||||
|
||||
const QgsPointXY c = mMap.extent().center();
|
||||
const QgsVector3D cEcef = mBoundsTransform.transform( QgsVector3D( c.x(), c.y(), 0 ), Qgis::TransformDirection::Reverse );
|
||||
const QgsVector3D ecef2 = cEcef - obb.center();
|
||||
|
||||
const double *half = obb.halfAxes();
|
||||
|
||||
// this is an approximate check anyway, no need for double precision matrix/vector
|
||||
QMatrix4x4 rot(
|
||||
half[0], half[3], half[6], 0,
|
||||
half[1], half[4], half[7], 0,
|
||||
half[2], half[5], half[8], 0,
|
||||
0, 0, 0, 1 );
|
||||
QVector3D aaa = rot.inverted().map( ecef2.toVector3D() );
|
||||
|
||||
if ( aaa.x() > 1 || aaa.y() > 1 || aaa.z() > 1 ||
|
||||
aaa.x() < -1 || aaa.y() < -1 || aaa.z() < -1 )
|
||||
{
|
||||
QgsOrientedBox3D obb = static_cast<const QgsTiledSceneBoundingVolumeBox *>( t.boundingVolume() )->box();
|
||||
|
||||
QgsPointXY c = mMap.extent().center();
|
||||
QgsVector3D cEcef = mBoundsTransform.transform( QgsVector3D( c.x(), c.y(), 0 ), Qgis::TransformDirection::Reverse );
|
||||
QgsVector3D ecef2 = cEcef - obb.center();
|
||||
|
||||
const double *half = obb.halfAxes();
|
||||
|
||||
// this is an approximate check anyway, no need for double precision matrix/vector
|
||||
QMatrix4x4 rot(
|
||||
half[0], half[3], half[6], 0,
|
||||
half[1], half[4], half[7], 0,
|
||||
half[2], half[5], half[8], 0,
|
||||
0, 0, 0, 1 );
|
||||
QVector3D aaa = rot.inverted().map( ecef2.toVector3D() );
|
||||
|
||||
if ( aaa.x() > 1 || aaa.y() > 1 || aaa.z() > 1 ||
|
||||
aaa.x() < -1 || aaa.y() < -1 || aaa.z() < -1 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,6 @@ class QgsTiledSceneChunkLoaderFactory : public QgsChunkLoaderFactory
|
||||
QString mRelativePathBase;
|
||||
mutable QgsTiledSceneIndex mIndex;
|
||||
QgsCoordinateTransform mBoundsTransform;
|
||||
QgsCoordinateTransform mRegionTransform;
|
||||
};
|
||||
|
||||
|
||||
|
@ -58,7 +58,8 @@ class QgsCesiumTiledSceneIndex final : public QgsAbstractTiledSceneIndex
|
||||
const json &tileset,
|
||||
const QString &rootPath,
|
||||
const QString &authCfg,
|
||||
const QgsHttpHeaders &headers );
|
||||
const QgsHttpHeaders &headers,
|
||||
const QgsCoordinateTransformContext &transformContext );
|
||||
|
||||
std::unique_ptr< QgsTiledSceneTile > tileFromJson( const json &node, const QgsTiledSceneTile *parent );
|
||||
QgsTiledSceneNode *nodeFromJson( const json &node, QgsTiledSceneNode *parent );
|
||||
@ -85,6 +86,7 @@ class QgsCesiumTiledSceneIndex final : public QgsAbstractTiledSceneIndex
|
||||
};
|
||||
|
||||
mutable QRecursiveMutex mLock;
|
||||
QgsCoordinateTransformContext mTransformContext;
|
||||
QString mRootPath;
|
||||
std::unique_ptr< QgsTiledSceneNode > mRootNode;
|
||||
QMap< long long, QgsTiledSceneNode * > mNodeMap;
|
||||
@ -107,7 +109,7 @@ class QgsCesiumTilesDataProviderSharedData
|
||||
|
||||
QgsCoordinateReferenceSystem mLayerCrs;
|
||||
QgsCoordinateReferenceSystem mSceneCrs;
|
||||
std::unique_ptr< QgsAbstractTiledSceneBoundingVolume > mBoundingVolume;
|
||||
QgsTiledSceneBoundingVolume mBoundingVolume;
|
||||
|
||||
QgsRectangle mExtent;
|
||||
nlohmann::json mTileset;
|
||||
@ -126,8 +128,9 @@ class QgsCesiumTilesDataProviderSharedData
|
||||
// QgsCesiumTiledSceneIndex
|
||||
//
|
||||
|
||||
QgsCesiumTiledSceneIndex::QgsCesiumTiledSceneIndex( const json &tileset, const QString &rootPath, const QString &authCfg, const QgsHttpHeaders &headers )
|
||||
: mRootPath( rootPath )
|
||||
QgsCesiumTiledSceneIndex::QgsCesiumTiledSceneIndex( const json &tileset, const QString &rootPath, const QString &authCfg, const QgsHttpHeaders &headers, const QgsCoordinateTransformContext &transformContext )
|
||||
: mTransformContext( transformContext )
|
||||
, mRootPath( rootPath )
|
||||
, mAuthCfg( authCfg )
|
||||
, mHeaders( headers )
|
||||
{
|
||||
@ -159,13 +162,45 @@ std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson( con
|
||||
tile->setTransform( transform );
|
||||
|
||||
const auto &boundingVolume = json[ "boundingVolume" ];
|
||||
std::unique_ptr< QgsAbstractTiledSceneBoundingVolume > volume;
|
||||
QgsTiledSceneBoundingVolume volume;
|
||||
if ( boundingVolume.contains( "region" ) )
|
||||
{
|
||||
const QgsBox3D rootRegion = QgsCesiumUtils::parseRegion( boundingVolume[ "region" ] );
|
||||
QgsBox3D rootRegion = QgsCesiumUtils::parseRegion( boundingVolume[ "region" ] );
|
||||
if ( !rootRegion.isNull() )
|
||||
{
|
||||
volume = std::make_unique< QgsTiledSceneBoundingVolumeRegion >( rootRegion );
|
||||
// we need to transform regions from EPSG:4979 to EPSG:4978
|
||||
QVector< QgsVector3D > corners = rootRegion.corners();
|
||||
|
||||
QVector< double > x;
|
||||
x.reserve( 8 );
|
||||
QVector< double > y;
|
||||
y.reserve( 8 );
|
||||
QVector< double > z;
|
||||
z.reserve( 8 );
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
const QgsVector3D &corner = corners[i];
|
||||
x.append( corner.x() );
|
||||
y.append( corner.y() );
|
||||
z.append( corner.z() );
|
||||
}
|
||||
QgsCoordinateTransform ct( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4979" ) ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4978" ) ), mTransformContext );
|
||||
ct.setBallparkTransformsAreAppropriate( true );
|
||||
try
|
||||
{
|
||||
ct.transformInPlace( x, y, z );
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
{
|
||||
QgsDebugError( QStringLiteral( "Cannot transform region bounding volume" ) );
|
||||
}
|
||||
|
||||
const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
|
||||
const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
|
||||
const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
|
||||
volume = QgsTiledSceneBoundingVolume( QgsOrientedBox3D::fromBox3D( QgsBox3D( *minMaxX.first, *minMaxY.first, *minMaxZ.first, *minMaxX.second, *minMaxY.second, *minMaxZ.second ) ) );
|
||||
|
||||
// note that matrix transforms are NOT applied to region bounding volumes!
|
||||
}
|
||||
}
|
||||
else if ( boundingVolume.contains( "box" ) )
|
||||
@ -173,15 +208,18 @@ std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson( con
|
||||
const QgsOrientedBox3D bbox = QgsCesiumUtils::parseBox( boundingVolume["box"] );
|
||||
if ( !bbox.isNull() )
|
||||
{
|
||||
volume = std::make_unique< QgsTiledSceneBoundingVolumeBox >( bbox );
|
||||
volume = QgsTiledSceneBoundingVolume( bbox );
|
||||
if ( !transform.isIdentity() )
|
||||
volume.transform( transform );
|
||||
}
|
||||
}
|
||||
else if ( boundingVolume.contains( "sphere" ) )
|
||||
{
|
||||
const QgsSphere sphere = QgsCesiumUtils::parseSphere( boundingVolume["sphere"] );
|
||||
QgsSphere sphere = QgsCesiumUtils::parseSphere( boundingVolume["sphere"] );
|
||||
if ( !sphere.isNull() )
|
||||
{
|
||||
volume = std::make_unique< QgsTiledSceneBoundingVolumeSphere >( sphere );
|
||||
sphere = QgsCesiumUtils::transformSphere( sphere, transform );
|
||||
volume = QgsTiledSceneBoundingVolume( QgsOrientedBox3D::fromBox3D( sphere.boundingBox() ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -189,12 +227,7 @@ std::unique_ptr< QgsTiledSceneTile > QgsCesiumTiledSceneIndex::tileFromJson( con
|
||||
QgsDebugError( QStringLiteral( "unsupported boundingVolume format" ) );
|
||||
}
|
||||
|
||||
if ( volume )
|
||||
{
|
||||
if ( !transform.isIdentity() )
|
||||
volume->transform( transform );
|
||||
tile->setBoundingVolume( volume.release() );
|
||||
}
|
||||
tile->setBoundingVolume( volume );
|
||||
|
||||
if ( json.contains( "geometricError" ) )
|
||||
tile->setGeometricError( json["geometricError"].get< double >() );
|
||||
@ -334,7 +367,7 @@ QVector< long long > QgsCesiumTiledSceneIndex::getTiles( const QgsTiledSceneRequ
|
||||
|
||||
// check filter box first -- if the node doesn't intersect, then don't include the node and don't traverse
|
||||
// to its children
|
||||
if ( !request.filterBox().isNull() && !tile->boundingVolume()->intersects( request.filterBox() ) )
|
||||
if ( !request.filterBox().isNull() && !tile->boundingVolume().intersects( request.filterBox() ) )
|
||||
return;
|
||||
|
||||
// TODO -- option to filter out nodes without content
|
||||
@ -608,10 +641,12 @@ void QgsCesiumTilesDataProviderSharedData::initialize( const QString &tileset, c
|
||||
const QgsBox3D rootRegion = QgsCesiumUtils::parseRegion( rootBoundingVolume[ "region" ] );
|
||||
if ( !rootRegion.isNull() )
|
||||
{
|
||||
mBoundingVolume = std::make_unique< QgsTiledSceneBoundingVolumeRegion >( rootRegion );
|
||||
mBoundingVolume = QgsTiledSceneBoundingVolume( QgsOrientedBox3D::fromBox3D( rootRegion ) );
|
||||
|
||||
mZRange = QgsDoubleRange( rootRegion.zMinimum(), rootRegion.zMaximum() );
|
||||
mLayerCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4979" ) );
|
||||
mSceneCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4978" ) );
|
||||
|
||||
mLayerMetadata.setCrs( mSceneCrs );
|
||||
mExtent = rootRegion.toRectangle();
|
||||
spatialExtent.extentCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4979" ) );
|
||||
@ -631,16 +666,16 @@ void QgsCesiumTilesDataProviderSharedData::initialize( const QString &tileset, c
|
||||
mSceneCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4978" ) );
|
||||
mLayerMetadata.setCrs( mSceneCrs );
|
||||
|
||||
const QgsCoordinateTransform transform( mSceneCrs, mLayerCrs, transformContext );
|
||||
|
||||
mBoundingVolume = std::make_unique< QgsTiledSceneBoundingVolumeBox >( bbox );
|
||||
mBoundingVolume->transform( rootTransform );
|
||||
mBoundingVolume = QgsTiledSceneBoundingVolume( bbox );
|
||||
mBoundingVolume.transform( rootTransform );
|
||||
try
|
||||
{
|
||||
const QgsBox3D rootRegion = mBoundingVolume->bounds( transform );
|
||||
QgsCoordinateTransform ct( mSceneCrs, mLayerCrs, transformContext );
|
||||
ct.setBallparkTransformsAreAppropriate( true );
|
||||
const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
|
||||
mZRange = QgsDoubleRange( rootRegion.zMinimum(), rootRegion.zMaximum() );
|
||||
|
||||
std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume->as2DGeometry( transform ) );
|
||||
std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
|
||||
mExtent = extent2D->boundingBox();
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
@ -649,12 +684,12 @@ void QgsCesiumTilesDataProviderSharedData::initialize( const QString &tileset, c
|
||||
}
|
||||
|
||||
spatialExtent.extentCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4978" ) );
|
||||
spatialExtent.bounds = mBoundingVolume->bounds();
|
||||
spatialExtent.bounds = mBoundingVolume.bounds();
|
||||
}
|
||||
}
|
||||
else if ( rootBoundingVolume.contains( "sphere" ) )
|
||||
{
|
||||
const QgsSphere sphere = QgsCesiumUtils::parseSphere( rootBoundingVolume["sphere"] );
|
||||
QgsSphere sphere = QgsCesiumUtils::parseSphere( rootBoundingVolume["sphere"] );
|
||||
if ( !sphere.isNull() )
|
||||
{
|
||||
// layer must advertise as EPSG:4979, as the various QgsMapLayer
|
||||
@ -665,16 +700,17 @@ void QgsCesiumTilesDataProviderSharedData::initialize( const QString &tileset, c
|
||||
mSceneCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4978" ) );
|
||||
mLayerMetadata.setCrs( mSceneCrs );
|
||||
|
||||
const QgsCoordinateTransform transform( mSceneCrs, mLayerCrs, transformContext );
|
||||
sphere = QgsCesiumUtils::transformSphere( sphere, rootTransform );
|
||||
|
||||
mBoundingVolume = std::make_unique< QgsTiledSceneBoundingVolumeSphere >( sphere );
|
||||
mBoundingVolume->transform( rootTransform );
|
||||
mBoundingVolume = QgsTiledSceneBoundingVolume( QgsOrientedBox3D::fromBox3D( sphere.boundingBox() ) );
|
||||
try
|
||||
{
|
||||
const QgsBox3D rootRegion = mBoundingVolume->bounds( transform );
|
||||
QgsCoordinateTransform ct( mSceneCrs, mLayerCrs, transformContext );
|
||||
ct.setBallparkTransformsAreAppropriate( true );
|
||||
const QgsBox3D rootRegion = mBoundingVolume.bounds( ct );
|
||||
mZRange = QgsDoubleRange( rootRegion.zMinimum(), rootRegion.zMaximum() );
|
||||
|
||||
std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume->as2DGeometry( transform ) );
|
||||
std::unique_ptr< QgsAbstractGeometry > extent2D( mBoundingVolume.as2DGeometry( ct ) );
|
||||
mExtent = extent2D->boundingBox();
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
@ -683,7 +719,7 @@ void QgsCesiumTilesDataProviderSharedData::initialize( const QString &tileset, c
|
||||
}
|
||||
|
||||
spatialExtent.extentCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4978" ) );
|
||||
spatialExtent.bounds = mBoundingVolume->bounds();
|
||||
spatialExtent.bounds = mBoundingVolume.bounds();
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -702,7 +738,8 @@ void QgsCesiumTilesDataProviderSharedData::initialize( const QString &tileset, c
|
||||
mTileset,
|
||||
rootPath,
|
||||
authCfg,
|
||||
headers
|
||||
headers,
|
||||
transformContext
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -935,14 +972,15 @@ const QgsCoordinateReferenceSystem QgsCesiumTilesDataProvider::sceneCrs() const
|
||||
return mShared->mSceneCrs ;
|
||||
}
|
||||
|
||||
const QgsAbstractTiledSceneBoundingVolume *QgsCesiumTilesDataProvider::boundingVolume() const
|
||||
const QgsTiledSceneBoundingVolume &QgsCesiumTilesDataProvider::boundingVolume() const
|
||||
{
|
||||
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
|
||||
static QgsTiledSceneBoundingVolume nullVolume;
|
||||
if ( !mShared )
|
||||
return nullptr;
|
||||
return nullVolume;
|
||||
|
||||
QgsReadWriteLocker locker( mShared->mReadWriteLock, QgsReadWriteLocker::Read );
|
||||
return mShared ? mShared->mBoundingVolume.get() : nullptr;
|
||||
return mShared ? mShared->mBoundingVolume : nullVolume;
|
||||
}
|
||||
|
||||
QgsTiledSceneIndex QgsCesiumTilesDataProvider::index() const
|
||||
|
@ -56,7 +56,7 @@ class CORE_EXPORT QgsCesiumTilesDataProvider final: public QgsTiledSceneDataProv
|
||||
QString htmlMetadata() const final;
|
||||
QgsLayerMetadata layerMetadata() const override;
|
||||
const QgsCoordinateReferenceSystem sceneCrs() const final;
|
||||
const QgsAbstractTiledSceneBoundingVolume *boundingVolume() const final;
|
||||
const QgsTiledSceneBoundingVolume &boundingVolume() const final;
|
||||
QgsTiledSceneIndex index() const final;
|
||||
|
||||
private:
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "qgscesiumutils.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "qgsjsonutils.h"
|
||||
#include "qgsmatrix4x4.h"
|
||||
#include "qgssphere.h"
|
||||
#include "qgsorientedbox3d.h"
|
||||
|
||||
@ -114,6 +115,32 @@ QgsSphere QgsCesiumUtils::parseSphere( const QVariantList &sphere )
|
||||
return parseSphere( QgsJsonUtils::jsonFromVariant( sphere ) );
|
||||
}
|
||||
|
||||
QgsSphere QgsCesiumUtils::transformSphere( const QgsSphere &sphere, const QgsMatrix4x4 &transform )
|
||||
{
|
||||
if ( !transform.isIdentity() )
|
||||
{
|
||||
// center is transformed, radius is scaled by maximum scalar from transform
|
||||
// see https://github.com/CesiumGS/cesium-native/blob/fd20f5e272850dde6b58c74059e6de767fe25df6/Cesium3DTilesSelection/src/BoundingVolume.cpp#L33
|
||||
const QgsVector3D center = transform.map( sphere.centerVector() );
|
||||
const double uniformScale = std::max(
|
||||
std::max(
|
||||
std::sqrt(
|
||||
transform.constData()[0] * transform.constData()[0] +
|
||||
transform.constData()[1] * transform.constData()[1] +
|
||||
transform.constData()[2] * transform.constData()[2] ),
|
||||
std::sqrt(
|
||||
transform.constData()[4] * transform.constData()[4] +
|
||||
transform.constData()[5] * transform.constData()[5] +
|
||||
transform.constData()[6] * transform.constData()[6] ) ),
|
||||
std::sqrt(
|
||||
transform.constData()[8] * transform.constData()[8] +
|
||||
transform.constData()[9] * transform.constData()[9] +
|
||||
transform.constData()[10] * transform.constData()[10] ) );
|
||||
|
||||
return QgsSphere( center.x(), center.y(), center.z(), sphere.radius() * uniformScale );
|
||||
}
|
||||
return sphere;
|
||||
}
|
||||
|
||||
QByteArray QgsCesiumUtils::extractGltfFromB3dm( const QByteArray &tileContent )
|
||||
{
|
||||
|
@ -30,6 +30,7 @@ using namespace nlohmann;
|
||||
|
||||
class QgsSphere;
|
||||
class QgsOrientedBox3D;
|
||||
class QgsMatrix4x4;
|
||||
|
||||
/**
|
||||
* \brief Contains utilities for working with Cesium data.
|
||||
@ -87,6 +88,11 @@ class CORE_EXPORT QgsCesiumUtils
|
||||
*/
|
||||
static QgsSphere parseSphere( const QVariantList &sphere );
|
||||
|
||||
/**
|
||||
* Applies a \a transform to a sphere.
|
||||
*/
|
||||
static QgsSphere transformSphere( const QgsSphere &sphere, const QgsMatrix4x4 &transform );
|
||||
|
||||
/**
|
||||
* Extracts GLTF binary data from the legacy b3dm (Batched 3D Model) tile format.
|
||||
* Returns empty byte array on error.
|
||||
|
@ -16,147 +16,24 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgstiledsceneboundingvolume.h"
|
||||
#include "qgscircle.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgsmatrix4x4.h"
|
||||
#include "qgsvector3d.h"
|
||||
#include "qgsmultipoint.h"
|
||||
#include "qgsgeos.h"
|
||||
#include "qgspolygon.h"
|
||||
|
||||
QgsAbstractTiledSceneBoundingVolume::~QgsAbstractTiledSceneBoundingVolume() = default;
|
||||
|
||||
//
|
||||
// QgsTiledSceneBoundingVolumeRegion
|
||||
//
|
||||
|
||||
QgsTiledSceneBoundingVolumeRegion::QgsTiledSceneBoundingVolumeRegion( const QgsBox3D ®ion )
|
||||
: mRegion( region )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Qgis::TiledSceneBoundingVolumeType QgsTiledSceneBoundingVolumeRegion::type() const
|
||||
{
|
||||
return Qgis::TiledSceneBoundingVolumeType::Region;
|
||||
}
|
||||
|
||||
void QgsTiledSceneBoundingVolumeRegion::transform( const QgsMatrix4x4 &transform )
|
||||
{
|
||||
// Regions are not transformed. See https://github.com/CesiumGS/cesium-native/blob/fd20f5e272850dde6b58c74059e6de767fe25df6/Cesium3DTilesSelection/src/BoundingVolume.cpp#L28C6-L28C38
|
||||
( void ) transform;
|
||||
}
|
||||
|
||||
QgsBox3D QgsTiledSceneBoundingVolumeRegion::bounds( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
{
|
||||
if ( transform.isValid() && !transform.isShortCircuited() )
|
||||
{
|
||||
// transform each corner of the box, then collect the min/max x/y/z values of the result
|
||||
QVector<QgsVector3D > corners = mRegion.corners();
|
||||
QVector< double > x;
|
||||
x.reserve( 8 );
|
||||
QVector< double > y;
|
||||
y.reserve( 8 );
|
||||
QVector< double > z;
|
||||
z.reserve( 8 );
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
const QgsVector3D corner = corners[i];
|
||||
x.append( corner.x() );
|
||||
y.append( corner.y() );
|
||||
z.append( corner.z() );
|
||||
}
|
||||
transform.transformInPlace( x, y, z, direction );
|
||||
|
||||
const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
|
||||
const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
|
||||
const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
|
||||
return QgsBox3D( *minMaxX.first, *minMaxY.first, *minMaxZ.first, *minMaxX.second, *minMaxY.second, *minMaxZ.second );
|
||||
}
|
||||
else
|
||||
{
|
||||
return mRegion;
|
||||
}
|
||||
}
|
||||
|
||||
QgsTiledSceneBoundingVolumeRegion *QgsTiledSceneBoundingVolumeRegion::clone() const
|
||||
{
|
||||
return new QgsTiledSceneBoundingVolumeRegion( *this );
|
||||
}
|
||||
|
||||
QgsAbstractGeometry *QgsTiledSceneBoundingVolumeRegion::as2DGeometry( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
{
|
||||
if ( transform.isValid() && !transform.isShortCircuited() )
|
||||
{
|
||||
const QVector< QgsVector3D > corners = mRegion.corners();
|
||||
QVector< double > x;
|
||||
x.reserve( 8 );
|
||||
QVector< double > y;
|
||||
y.reserve( 8 );
|
||||
QVector< double > z;
|
||||
z.reserve( 8 );
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
const QgsVector3D &corner = corners[i];
|
||||
x.append( corner.x() );
|
||||
y.append( corner.y() );
|
||||
z.append( corner.z() );
|
||||
}
|
||||
|
||||
if ( transform.isValid() && !transform.isShortCircuited() )
|
||||
{
|
||||
transform.transformInPlace( x, y, z, direction );
|
||||
}
|
||||
|
||||
std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >( x, y );
|
||||
QgsGeos geosMp( mp.get() );
|
||||
return geosMp.convexHull();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
|
||||
std::unique_ptr< QgsLineString > ext = std::make_unique< QgsLineString >(
|
||||
QVector< double >() << mRegion.xMinimum()
|
||||
<< mRegion.xMaximum()
|
||||
<< mRegion.xMaximum()
|
||||
<< mRegion.xMinimum()
|
||||
<< mRegion.xMinimum(),
|
||||
QVector< double >() << mRegion.yMinimum()
|
||||
<< mRegion.yMinimum()
|
||||
<< mRegion.yMaximum()
|
||||
<< mRegion.yMaximum()
|
||||
<< mRegion.yMinimum() );
|
||||
|
||||
polygon->setExteriorRing( ext.release() );
|
||||
return polygon.release();
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsTiledSceneBoundingVolumeRegion::intersects( const QgsOrientedBox3D &box ) const
|
||||
{
|
||||
return QgsOrientedBox3D::fromBox3D( mRegion ).intersects( box );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsTiledSceneBoundingVolumeBox
|
||||
//
|
||||
|
||||
QgsTiledSceneBoundingVolumeBox::QgsTiledSceneBoundingVolumeBox( const QgsOrientedBox3D &box )
|
||||
QgsTiledSceneBoundingVolume::QgsTiledSceneBoundingVolume( const QgsOrientedBox3D &box )
|
||||
: mBox( box )
|
||||
{
|
||||
}
|
||||
|
||||
Qgis::TiledSceneBoundingVolumeType QgsTiledSceneBoundingVolumeBox::type() const
|
||||
{
|
||||
return Qgis::TiledSceneBoundingVolumeType::OrientedBox;
|
||||
}
|
||||
|
||||
void QgsTiledSceneBoundingVolumeBox::transform( const QgsMatrix4x4 &transform )
|
||||
void QgsTiledSceneBoundingVolume::transform( const QgsMatrix4x4 &transform )
|
||||
{
|
||||
mBox = mBox.transformed( transform );
|
||||
}
|
||||
|
||||
QgsBox3D QgsTiledSceneBoundingVolumeBox::bounds( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
QgsBox3D QgsTiledSceneBoundingVolume::bounds( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
{
|
||||
if ( transform.isValid() && !transform.isShortCircuited() )
|
||||
{
|
||||
@ -187,12 +64,7 @@ QgsBox3D QgsTiledSceneBoundingVolumeBox::bounds( const QgsCoordinateTransform &t
|
||||
}
|
||||
}
|
||||
|
||||
QgsTiledSceneBoundingVolumeBox *QgsTiledSceneBoundingVolumeBox::clone() const
|
||||
{
|
||||
return new QgsTiledSceneBoundingVolumeBox( *this );
|
||||
}
|
||||
|
||||
QgsAbstractGeometry *QgsTiledSceneBoundingVolumeBox::as2DGeometry( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
QgsAbstractGeometry *QgsTiledSceneBoundingVolume::as2DGeometry( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
{
|
||||
std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
|
||||
|
||||
@ -221,135 +93,8 @@ QgsAbstractGeometry *QgsTiledSceneBoundingVolumeBox::as2DGeometry( const QgsCoor
|
||||
return geosMp.convexHull();
|
||||
}
|
||||
|
||||
bool QgsTiledSceneBoundingVolumeBox::intersects( const QgsOrientedBox3D &box ) const
|
||||
bool QgsTiledSceneBoundingVolume::intersects( const QgsOrientedBox3D &box ) const
|
||||
{
|
||||
return mBox.intersects( box );
|
||||
}
|
||||
|
||||
//
|
||||
// QgsTiledSceneBoundingVolumeSphere
|
||||
//
|
||||
|
||||
QgsTiledSceneBoundingVolumeSphere::QgsTiledSceneBoundingVolumeSphere( const QgsSphere &sphere )
|
||||
: mSphere( sphere )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Qgis::TiledSceneBoundingVolumeType QgsTiledSceneBoundingVolumeSphere::type() const
|
||||
{
|
||||
return Qgis::TiledSceneBoundingVolumeType::Sphere;
|
||||
}
|
||||
|
||||
void QgsTiledSceneBoundingVolumeSphere::transform( const QgsMatrix4x4 &transform )
|
||||
{
|
||||
// center is transformed, radius is scaled by maximum scalar from transform
|
||||
// see https://github.com/CesiumGS/cesium-native/blob/fd20f5e272850dde6b58c74059e6de767fe25df6/Cesium3DTilesSelection/src/BoundingVolume.cpp#L33
|
||||
const QgsVector3D center = transform.map( mSphere.centerVector() );
|
||||
const double uniformScale = std::max(
|
||||
std::max(
|
||||
std::sqrt(
|
||||
transform.constData()[0] * transform.constData()[0] +
|
||||
transform.constData()[1] * transform.constData()[1] +
|
||||
transform.constData()[2] * transform.constData()[2] +
|
||||
transform.constData()[3] * transform.constData()[3] ),
|
||||
std::sqrt(
|
||||
transform.constData()[4] * transform.constData()[4] +
|
||||
transform.constData()[5] * transform.constData()[5] +
|
||||
transform.constData()[6] * transform.constData()[6] +
|
||||
transform.constData()[7] * transform.constData()[7] ) ),
|
||||
std::sqrt(
|
||||
transform.constData()[8] * transform.constData()[8] +
|
||||
transform.constData()[9] * transform.constData()[9] +
|
||||
transform.constData()[10] * transform.constData()[10] +
|
||||
transform.constData()[11] * transform.constData()[11] ) );
|
||||
|
||||
mSphere = QgsSphere( center.x(), center.y(), center.z(), mSphere.radius() * uniformScale );
|
||||
}
|
||||
|
||||
QgsBox3D QgsTiledSceneBoundingVolumeSphere::bounds( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
{
|
||||
if ( transform.isValid() && !transform.isShortCircuited() )
|
||||
{
|
||||
const QVector< QgsVector3D > corners = mSphere.boundingBox().corners();
|
||||
QVector< double > x;
|
||||
x.reserve( 8 );
|
||||
QVector< double > y;
|
||||
y.reserve( 8 );
|
||||
QVector< double > z;
|
||||
z.reserve( 8 );
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
const QgsVector3D &corner = corners[i];
|
||||
x.append( corner.x() );
|
||||
y.append( corner.y() );
|
||||
z.append( corner.z() );
|
||||
}
|
||||
transform.transformInPlace( x, y, z, direction );
|
||||
|
||||
const auto minMaxX = std::minmax_element( x.constBegin(), x.constEnd() );
|
||||
const auto minMaxY = std::minmax_element( y.constBegin(), y.constEnd() );
|
||||
const auto minMaxZ = std::minmax_element( z.constBegin(), z.constEnd() );
|
||||
return QgsBox3D( *minMaxX.first, *minMaxY.first, *minMaxZ.first, *minMaxX.second, *minMaxY.second, *minMaxZ.second );
|
||||
}
|
||||
else
|
||||
{
|
||||
return mSphere.boundingBox();
|
||||
}
|
||||
}
|
||||
|
||||
QgsTiledSceneBoundingVolumeSphere *QgsTiledSceneBoundingVolumeSphere::clone() const
|
||||
{
|
||||
return new QgsTiledSceneBoundingVolumeSphere( *this );
|
||||
}
|
||||
|
||||
QgsAbstractGeometry *QgsTiledSceneBoundingVolumeSphere::as2DGeometry( const QgsCoordinateTransform &transform, Qgis::TransformDirection direction ) const
|
||||
{
|
||||
if ( transform.isValid() && !transform.isShortCircuited() )
|
||||
{
|
||||
const QgsVector3D sphereCenter = mSphere.centerVector();
|
||||
QgsVector3D normal = sphereCenter;
|
||||
normal.normalize();
|
||||
|
||||
QgsVector3D axis1 = QgsVector3D::crossProduct( normal, QgsVector3D( 1, 0, 0 ) );
|
||||
if ( axis1.length() == 0 )
|
||||
{
|
||||
axis1 = QgsVector3D::crossProduct( normal, QgsVector3D( 0, 1, 0 ) );
|
||||
}
|
||||
axis1.normalize();
|
||||
const QgsVector3D axis2 = QgsVector3D::crossProduct( normal, axis1 );
|
||||
QVector< double > circleXInPlane;
|
||||
QVector< double > circleYInPlane;
|
||||
QVector< double > circleZInPlane;
|
||||
|
||||
for ( int i = 0; i < 48; ++i )
|
||||
{
|
||||
const double alpha = 2 * i / 48.0 * M_PI;
|
||||
circleXInPlane.append( mSphere.centerX() + mSphere.radius() * ( axis1.x() * std::cos( alpha ) + axis2.x()* std::sin( alpha ) ) );
|
||||
circleYInPlane.append( mSphere.centerY() + mSphere.radius() * ( axis1.y() * std::cos( alpha ) + axis2.y()* std::sin( alpha ) ) );
|
||||
circleZInPlane.append( mSphere.centerZ() + mSphere.radius() * ( axis1.z() * std::cos( alpha ) + axis2.z()* std::sin( alpha ) ) );
|
||||
}
|
||||
transform.transformInPlace( circleXInPlane, circleYInPlane, circleZInPlane, direction );
|
||||
|
||||
std::unique_ptr< QgsLineString > exterior = std::make_unique< QgsLineString>( circleXInPlane, circleYInPlane );
|
||||
exterior->close();
|
||||
std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
|
||||
polygon->setExteriorRing( exterior.release() );
|
||||
return polygon.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr< QgsCurvePolygon > polygon = std::make_unique< QgsCurvePolygon >();
|
||||
std::unique_ptr< QgsCircularString > exterior( mSphere.toCircle().toCircularString() );
|
||||
polygon->setExteriorRing( exterior.release() );
|
||||
return polygon.release();
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsTiledSceneBoundingVolumeSphere::intersects( const QgsOrientedBox3D &box ) const
|
||||
{
|
||||
// just a simple "bounding box of sphere" intersects test for now -- this could obviously be refined, but it's likely not necessary...
|
||||
const QgsBox3D boundingBox = mSphere.boundingBox();
|
||||
return QgsOrientedBox3D::fromBox3D( boundingBox ).intersects( box );
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "qgis.h"
|
||||
#include "qgsbox3d.h"
|
||||
#include "qgsmatrix4x4.h"
|
||||
#include "qgssphere.h"
|
||||
#include "qgsorientedbox3d.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
|
||||
@ -32,40 +31,18 @@ class QgsMatrix4x4;
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \brief Abstract base class for bounding volumes for tiled scene nodes.
|
||||
* \brief Represents a bounding volume for a tiled scene.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class CORE_EXPORT QgsAbstractTiledSceneBoundingVolume
|
||||
class CORE_EXPORT QgsTiledSceneBoundingVolume
|
||||
{
|
||||
public:
|
||||
|
||||
#ifdef SIP_RUN
|
||||
SIP_CONVERT_TO_SUBCLASS_CODE
|
||||
switch ( sipCpp->type() )
|
||||
{
|
||||
case Qgis::TiledSceneBoundingVolumeType::Region:
|
||||
sipType = sipType_QgsTiledSceneBoundingVolumeRegion;
|
||||
break;
|
||||
case Qgis::TiledSceneBoundingVolumeType::OrientedBox:
|
||||
sipType = sipType_QgsTiledSceneBoundingVolumeBox;
|
||||
break;
|
||||
case Qgis::TiledSceneBoundingVolumeType::Sphere:
|
||||
sipType = sipType_QgsTiledSceneBoundingVolumeSphere;
|
||||
break;
|
||||
default:
|
||||
sipType = 0;
|
||||
break;
|
||||
};
|
||||
SIP_END
|
||||
#endif
|
||||
|
||||
virtual ~QgsAbstractTiledSceneBoundingVolume();
|
||||
|
||||
/**
|
||||
* Returns the type of the volume;
|
||||
* Constructor for QgsTiledSceneBoundingVolume, with the specified oriented \a box.
|
||||
*/
|
||||
virtual Qgis::TiledSceneBoundingVolumeType type() const = 0;
|
||||
QgsTiledSceneBoundingVolume( const QgsOrientedBox3D &box = QgsOrientedBox3D() );
|
||||
|
||||
/**
|
||||
* Returns the axis aligned bounding box of the volume.
|
||||
@ -73,12 +50,7 @@ class CORE_EXPORT QgsAbstractTiledSceneBoundingVolume
|
||||
* The optional \a transform and \a direction arguments should be used whenever the volume needs
|
||||
* to be transformed into a specific destination CRS, in order to correctly handle 3D coordinate transforms.
|
||||
*/
|
||||
virtual QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const = 0;
|
||||
|
||||
/**
|
||||
* Returns a clone of the volume.
|
||||
*/
|
||||
virtual QgsAbstractTiledSceneBoundingVolume *clone() const = 0 SIP_FACTORY;
|
||||
QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const;
|
||||
|
||||
/**
|
||||
* Returns a new geometry representing the 2-dimensional X/Y center slice of the volume.
|
||||
@ -88,77 +60,17 @@ class CORE_EXPORT QgsAbstractTiledSceneBoundingVolume
|
||||
* The optional \a transform and \a direction arguments should be used whenever the volume needs
|
||||
* to be transformed into a specific destination CRS, in order to correctly handle 3D coordinate transforms.
|
||||
*/
|
||||
virtual QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const = 0 SIP_FACTORY;
|
||||
QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Applies a \a transform to the bounding volume.
|
||||
*
|
||||
* The actual result of transforming a bounding volume depends on subclass specific logic. For instance:
|
||||
*
|
||||
* - transforming a QgsTiledSceneBoundingVolumeRegion results in no change to the region
|
||||
* - transforming a QgsTiledSceneBoundingVolumeSphere causes the radius to be multiplied by the maximum length of the transform scales
|
||||
*/
|
||||
virtual void transform( const QgsMatrix4x4 &transform ) = 0;
|
||||
void transform( const QgsMatrix4x4 &transform );
|
||||
|
||||
/**
|
||||
* Returns TRUE if this bounds intersects the specified \a box.
|
||||
*/
|
||||
virtual bool intersects( const QgsOrientedBox3D &box ) const = 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \brief A region bounding volume for tiled scene nodes.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class CORE_EXPORT QgsTiledSceneBoundingVolumeRegion : public QgsAbstractTiledSceneBoundingVolume
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsTiledSceneBoundingVolumeRegion, with the specified \a region.
|
||||
*/
|
||||
QgsTiledSceneBoundingVolumeRegion( const QgsBox3D ®ion );
|
||||
|
||||
Qgis::TiledSceneBoundingVolumeType type() const FINAL;
|
||||
void transform( const QgsMatrix4x4 &transform ) FINAL;
|
||||
QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const FINAL SIP_THROW( QgsCsException );
|
||||
QgsTiledSceneBoundingVolumeRegion *clone() const FINAL SIP_FACTORY;
|
||||
QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const FINAL SIP_THROW( QgsCsException ) SIP_FACTORY;
|
||||
bool intersects( const QgsOrientedBox3D &box ) const FINAL;
|
||||
|
||||
/**
|
||||
* Returns the volume's region.
|
||||
*/
|
||||
QgsBox3D region() const { return mRegion; }
|
||||
|
||||
private:
|
||||
QgsBox3D mRegion;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \brief A oriented box bounding volume for tiled scene nodes.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class CORE_EXPORT QgsTiledSceneBoundingVolumeBox : public QgsAbstractTiledSceneBoundingVolume
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsTiledSceneBoundingVolumeBox, with the specified oriented \a box.
|
||||
*/
|
||||
QgsTiledSceneBoundingVolumeBox( const QgsOrientedBox3D &box );
|
||||
|
||||
Qgis::TiledSceneBoundingVolumeType type() const FINAL;
|
||||
void transform( const QgsMatrix4x4 &transform ) FINAL;
|
||||
QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const FINAL SIP_THROW( QgsCsException );
|
||||
QgsTiledSceneBoundingVolumeBox *clone() const FINAL SIP_FACTORY;
|
||||
QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const FINAL SIP_THROW( QgsCsException ) SIP_FACTORY;
|
||||
bool intersects( const QgsOrientedBox3D &box ) const FINAL;
|
||||
bool intersects( const QgsOrientedBox3D &box ) const;
|
||||
|
||||
/**
|
||||
* Returns the volume's oriented box.
|
||||
@ -171,38 +83,4 @@ class CORE_EXPORT QgsTiledSceneBoundingVolumeBox : public QgsAbstractTiledSceneB
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \brief A spherical bounding volume for tiled scene nodes.
|
||||
*
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class CORE_EXPORT QgsTiledSceneBoundingVolumeSphere: public QgsAbstractTiledSceneBoundingVolume
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsTiledSceneBoundingVolumeSphere, with the specified \a sphere.
|
||||
*/
|
||||
QgsTiledSceneBoundingVolumeSphere( const QgsSphere &sphere );
|
||||
|
||||
Qgis::TiledSceneBoundingVolumeType type() const FINAL;
|
||||
void transform( const QgsMatrix4x4 &transform ) FINAL;
|
||||
QgsBox3D bounds( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const FINAL SIP_THROW( QgsCsException );
|
||||
QgsTiledSceneBoundingVolumeSphere *clone() const FINAL SIP_FACTORY;
|
||||
QgsAbstractGeometry *as2DGeometry( const QgsCoordinateTransform &transform = QgsCoordinateTransform(), Qgis::TransformDirection direction = Qgis::TransformDirection::Forward ) const FINAL SIP_THROW( QgsCsException ) SIP_FACTORY;
|
||||
bool intersects( const QgsOrientedBox3D &box ) const FINAL;
|
||||
|
||||
/**
|
||||
* Returns the volume's sphere.
|
||||
*/
|
||||
QgsSphere sphere() const { return mSphere; }
|
||||
|
||||
private:
|
||||
|
||||
QgsSphere mSphere;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSTILEDSCENEBOUNDINGVOLUME_H
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "qgsdataprovider.h"
|
||||
#include "qgis.h"
|
||||
|
||||
class QgsAbstractTiledSceneBoundingVolume;
|
||||
class QgsTiledSceneBoundingVolume;
|
||||
class QgsTiledSceneIndex;
|
||||
|
||||
/**
|
||||
@ -89,7 +89,7 @@ class CORE_EXPORT QgsTiledSceneDataProvider: public QgsDataProvider
|
||||
*
|
||||
* \warning Coordinates in the returned volume are in the sceneCrs() reference system, not the QgsDataProvider::crs() system.
|
||||
*/
|
||||
virtual const QgsAbstractTiledSceneBoundingVolume *boundingVolume() const = 0;
|
||||
virtual const QgsTiledSceneBoundingVolume &boundingVolume() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the provider's tile index.
|
||||
|
@ -41,8 +41,7 @@ QgsTiledSceneLayerRenderer::QgsTiledSceneLayerRenderer( QgsTiledSceneLayer *laye
|
||||
mSceneCrs = layer->dataProvider()->sceneCrs();
|
||||
|
||||
mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( *renderContext(), layer );
|
||||
if ( const QgsAbstractTiledSceneBoundingVolume *layerBoundingVolume = layer->dataProvider()->boundingVolume() )
|
||||
mLayerBoundingVolume.reset( layerBoundingVolume->clone() );
|
||||
mLayerBoundingVolume = layer->dataProvider()->boundingVolume();
|
||||
|
||||
mReadyToCompose = false;
|
||||
}
|
||||
@ -79,39 +78,36 @@ bool QgsTiledSceneLayerRenderer::render()
|
||||
|
||||
bool canceled = false;
|
||||
|
||||
if ( mLayerBoundingVolume )
|
||||
const QgsCoordinateTransform transform = QgsCoordinateTransform( mSceneCrs, renderContext()->coordinateTransform().destinationCrs(), renderContext()->transformContext() );
|
||||
try
|
||||
{
|
||||
const QgsCoordinateTransform transform = QgsCoordinateTransform( mSceneCrs, renderContext()->coordinateTransform().destinationCrs(), renderContext()->transformContext() );
|
||||
try
|
||||
std::unique_ptr< QgsAbstractGeometry > rootBoundsGeometry( mLayerBoundingVolume.as2DGeometry( transform ) );
|
||||
if ( QgsCurvePolygon *polygon = qgsgeometry_cast< QgsCurvePolygon * >( rootBoundsGeometry.get() ) )
|
||||
{
|
||||
std::unique_ptr< QgsAbstractGeometry > rootBoundsGeometry( mLayerBoundingVolume->as2DGeometry( transform ) );
|
||||
if ( QgsCurvePolygon *polygon = qgsgeometry_cast< QgsCurvePolygon * >( rootBoundsGeometry.get() ) )
|
||||
QPolygonF rootBoundsPoly = polygon->exteriorRing()->asQPolygonF();
|
||||
|
||||
// remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
|
||||
rootBoundsPoly.erase( std::remove_if( rootBoundsPoly.begin(), rootBoundsPoly.end(),
|
||||
[]( const QPointF point )
|
||||
{
|
||||
QPolygonF rootBoundsPoly = polygon->exteriorRing()->asQPolygonF();
|
||||
return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
|
||||
} ), rootBoundsPoly.end() );
|
||||
|
||||
// remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
|
||||
rootBoundsPoly.erase( std::remove_if( rootBoundsPoly.begin(), rootBoundsPoly.end(),
|
||||
[]( const QPointF point )
|
||||
{
|
||||
return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
|
||||
} ), rootBoundsPoly.end() );
|
||||
|
||||
QPointF *ptr = rootBoundsPoly.data();
|
||||
for ( int i = 0; i < rootBoundsPoly.size(); ++i, ++ptr )
|
||||
{
|
||||
renderContext()->mapToPixel().transformInPlace( ptr->rx(), ptr->ry() );
|
||||
}
|
||||
|
||||
QgsLineSymbol symbol;
|
||||
symbol.startRender( *renderContext() );
|
||||
symbol.renderPolyline( rootBoundsPoly, nullptr, *renderContext() );
|
||||
symbol.stopRender( *renderContext() );
|
||||
QPointF *ptr = rootBoundsPoly.data();
|
||||
for ( int i = 0; i < rootBoundsPoly.size(); ++i, ++ptr )
|
||||
{
|
||||
renderContext()->mapToPixel().transformInPlace( ptr->rx(), ptr->ry() );
|
||||
}
|
||||
|
||||
QgsLineSymbol symbol;
|
||||
symbol.startRender( *renderContext() );
|
||||
symbol.renderPolyline( rootBoundsPoly, nullptr, *renderContext() );
|
||||
symbol.stopRender( *renderContext() );
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
{
|
||||
QgsDebugError( QStringLiteral( "Error transforming root bounding volume" ) );
|
||||
}
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
{
|
||||
QgsDebugError( QStringLiteral( "Error transforming root bounding volume" ) );
|
||||
}
|
||||
|
||||
mRenderer->stopRender( context );
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "qgis_core.h"
|
||||
#include "qgsmaplayerrenderer.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgstiledsceneboundingvolume.h"
|
||||
|
||||
#include <memory>
|
||||
#include <QElapsedTimer>
|
||||
@ -30,7 +31,6 @@
|
||||
class QgsTiledSceneLayer;
|
||||
class QgsFeedback;
|
||||
class QgsMapClippingRegion;
|
||||
class QgsAbstractTiledSceneBoundingVolume;
|
||||
class QgsTiledSceneRenderer;
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ class CORE_EXPORT QgsTiledSceneLayerRenderer: public QgsMapLayerRenderer
|
||||
QElapsedTimer mElapsedTimer;
|
||||
|
||||
QgsCoordinateReferenceSystem mSceneCrs;
|
||||
std::unique_ptr< QgsAbstractTiledSceneBoundingVolume > mLayerBoundingVolume;
|
||||
QgsTiledSceneBoundingVolume mLayerBoundingVolume;
|
||||
|
||||
std::unique_ptr<QgsFeedback> mFeedback = nullptr;
|
||||
};
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
QgsTiledSceneRequest::QgsTiledSceneRequest() = default;
|
||||
|
||||
|
||||
|
||||
void QgsTiledSceneRequest::setFeedback( QgsFeedback *feedback )
|
||||
{
|
||||
mFeedback = feedback;
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgscoordinatetransformcontext.h"
|
||||
#include "qgsorientedbox3d.h"
|
||||
|
||||
class QgsFeedback;
|
||||
@ -53,16 +55,19 @@ class CORE_EXPORT QgsTiledSceneRequest
|
||||
Qgis::TiledSceneRequestFlags flags() const { return mFlags; }
|
||||
|
||||
/**
|
||||
* Returns the box from which data will be taken, in the layer's CRS.
|
||||
* Returns the box from which data will be taken.
|
||||
*
|
||||
* The CRS for the box can be retrieved by filterBoxCrs().
|
||||
*
|
||||
* If the returned box is null, then no filter box is set.
|
||||
*
|
||||
* \see filterBoxCrs()
|
||||
* \see setFilterBox()
|
||||
*/
|
||||
QgsOrientedBox3D filterBox() const { return mFilterBox; }
|
||||
|
||||
/**
|
||||
* Sets the \a box from which data will be taken, in the layer's CRS.
|
||||
* Sets the \a box from which data will be taken.
|
||||
*
|
||||
* An null \a box removes the filter.
|
||||
*
|
||||
@ -131,6 +136,7 @@ class CORE_EXPORT QgsTiledSceneRequest
|
||||
|
||||
Qgis::TiledSceneRequestFlags mFlags;
|
||||
QgsOrientedBox3D mFilterBox;
|
||||
|
||||
QgsFeedback *mFeedback = nullptr;
|
||||
double mRequiredGeometricError = 0;
|
||||
long long mParentTileId = -1;
|
||||
|
@ -19,12 +19,14 @@
|
||||
#include "qgstiledsceneboundingvolume.h"
|
||||
|
||||
QgsTiledSceneTile::QgsTiledSceneTile()
|
||||
: mBoundingVolume( QgsTiledSceneBoundingVolume( QgsOrientedBox3D() ) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QgsTiledSceneTile::QgsTiledSceneTile( long long id )
|
||||
: mId( id )
|
||||
, mBoundingVolume( QgsTiledSceneBoundingVolume( QgsOrientedBox3D() ) )
|
||||
{
|
||||
|
||||
}
|
||||
@ -34,10 +36,10 @@ QgsTiledSceneTile::~QgsTiledSceneTile() = default;
|
||||
QgsTiledSceneTile::QgsTiledSceneTile( const QgsTiledSceneTile &other )
|
||||
: mId( other.mId )
|
||||
, mRefinementProcess( other.mRefinementProcess )
|
||||
, mBoundingVolume( other.mBoundingVolume )
|
||||
, mResources( other.mResources )
|
||||
, mGeometricError( other.mGeometricError )
|
||||
{
|
||||
mBoundingVolume.reset( other.mBoundingVolume ? other.mBoundingVolume->clone() : nullptr );
|
||||
mTransform.reset( other.mTransform ? new QgsMatrix4x4( *other.mTransform.get() ) : nullptr );
|
||||
}
|
||||
|
||||
@ -48,7 +50,7 @@ QgsTiledSceneTile &QgsTiledSceneTile::operator=( const QgsTiledSceneTile &other
|
||||
mTransform.reset( other.mTransform ? new QgsMatrix4x4( *other.mTransform.get() ) : nullptr );
|
||||
mResources = other.mResources;
|
||||
mGeometricError = other.mGeometricError;
|
||||
mBoundingVolume.reset( other.mBoundingVolume ? other.mBoundingVolume->clone() : nullptr );
|
||||
mBoundingVolume = other.mBoundingVolume;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -57,14 +59,14 @@ void QgsTiledSceneTile::setRefinementProcess( Qgis::TileRefinementProcess proces
|
||||
mRefinementProcess = process;
|
||||
}
|
||||
|
||||
void QgsTiledSceneTile::setBoundingVolume( QgsAbstractTiledSceneBoundingVolume *volume )
|
||||
void QgsTiledSceneTile::setBoundingVolume( const QgsTiledSceneBoundingVolume &volume )
|
||||
{
|
||||
mBoundingVolume.reset( volume );
|
||||
mBoundingVolume = volume;
|
||||
}
|
||||
|
||||
const QgsAbstractTiledSceneBoundingVolume *QgsTiledSceneTile::boundingVolume() const
|
||||
const QgsTiledSceneBoundingVolume &QgsTiledSceneTile::boundingVolume() const
|
||||
{
|
||||
return mBoundingVolume.get();
|
||||
return mBoundingVolume;
|
||||
}
|
||||
|
||||
void QgsTiledSceneTile::setTransform( const QgsMatrix4x4 &transform )
|
||||
|
@ -22,8 +22,7 @@
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsmatrix4x4.h"
|
||||
|
||||
class QgsAbstractTiledSceneBoundingVolume;
|
||||
#include "qgstiledsceneboundingvolume.h"
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
@ -89,18 +88,16 @@ class CORE_EXPORT QgsTiledSceneTile
|
||||
/**
|
||||
* Sets the bounding \a volume for the tile.
|
||||
*
|
||||
* Ownership of \a volume is transferred to the tile.
|
||||
*
|
||||
* \see boundingVolume()
|
||||
*/
|
||||
void setBoundingVolume( QgsAbstractTiledSceneBoundingVolume *volume SIP_TRANSFER );
|
||||
void setBoundingVolume( const QgsTiledSceneBoundingVolume &volume );
|
||||
|
||||
/**
|
||||
* Returns the bounding volume for the tile.
|
||||
*
|
||||
* \see setBoundingVolume()
|
||||
*/
|
||||
const QgsAbstractTiledSceneBoundingVolume *boundingVolume() const;
|
||||
const QgsTiledSceneBoundingVolume &boundingVolume() const;
|
||||
|
||||
/**
|
||||
* Sets the tile's \a transform.
|
||||
@ -152,7 +149,7 @@ class CORE_EXPORT QgsTiledSceneTile
|
||||
private:
|
||||
long long mId = -1;
|
||||
Qgis::TileRefinementProcess mRefinementProcess = Qgis::TileRefinementProcess::Replacement;
|
||||
std::unique_ptr< QgsAbstractTiledSceneBoundingVolume > mBoundingVolume;
|
||||
QgsTiledSceneBoundingVolume mBoundingVolume;
|
||||
std::unique_ptr< QgsMatrix4x4 > mTransform;
|
||||
QVariantMap mResources;
|
||||
double mGeometricError = 0;
|
||||
|
@ -86,28 +86,17 @@ class TestQgsCesium3dTilesLayer(unittest.TestCase):
|
||||
self.assertAlmostEqual(layer.extent().yMaximum(), 40.044339909, 3)
|
||||
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().region().xMinimum(),
|
||||
-75.6144410,
|
||||
layer.dataProvider().boundingVolume().box().centerX(),
|
||||
-75.612094,
|
||||
3,
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().region().xMaximum(),
|
||||
-75.6097475,
|
||||
layer.dataProvider().boundingVolume().box().centerY(),
|
||||
40.0425306,
|
||||
3,
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().region().yMinimum(), 40.0407213, 3
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().region().yMaximum(),
|
||||
40.044339909,
|
||||
3,
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().region().zMinimum(), 1.2, 3
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().region().zMaximum(), 67.00999, 3
|
||||
layer.dataProvider().boundingVolume().box().centerZ(), 34.105, 3
|
||||
)
|
||||
|
||||
# check that version, tileset version, and z range are in html metadata
|
||||
@ -174,13 +163,10 @@ class TestQgsCesium3dTilesLayer(unittest.TestCase):
|
||||
layer = QgsTiledSceneLayer(tmp_file, "my layer", "cesiumtiles")
|
||||
self.assertTrue(layer.dataProvider().isValid())
|
||||
|
||||
layer_bounds = layer.dataProvider().boundingVolume().region()
|
||||
self.assertAlmostEqual(layer_bounds.xMinimum(), -75.6132, 4)
|
||||
self.assertAlmostEqual(layer_bounds.xMaximum(), -75.6075, 4)
|
||||
self.assertAlmostEqual(layer_bounds.yMinimum(), 40.0383, 4)
|
||||
self.assertAlmostEqual(layer_bounds.yMaximum(), 40.044, 4)
|
||||
self.assertAlmostEqual(layer_bounds.zMinimum(), 1.2, 4)
|
||||
self.assertAlmostEqual(layer_bounds.zMaximum(), 67.01, 4)
|
||||
layer_bounds = layer.dataProvider().boundingVolume().box()
|
||||
self.assertAlmostEqual(layer_bounds.centerX(), -75.61037543, 4)
|
||||
self.assertAlmostEqual(layer_bounds.centerY(), 40.0411555, 4)
|
||||
self.assertAlmostEqual(layer_bounds.centerZ(), 34.1050000, 4)
|
||||
|
||||
def test_source_bounding_volume_box(self):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
@ -277,26 +263,23 @@ class TestQgsCesium3dTilesLayer(unittest.TestCase):
|
||||
self.assertEqual(layer.dataProvider().crs().authid(), "EPSG:4979")
|
||||
|
||||
# extent must be in EPSG:4979 to match the layer crs()
|
||||
self.assertAlmostEqual(layer.extent().xMinimum(), 149.5562895, 3)
|
||||
self.assertAlmostEqual(layer.extent().xMaximum(), 149.5989376, 3)
|
||||
self.assertAlmostEqual(layer.extent().yMinimum(), -33.4378807, 3)
|
||||
self.assertAlmostEqual(layer.extent().yMaximum(), -33.402147, 3)
|
||||
self.assertAlmostEqual(layer.extent().xMinimum(), 149.5484313, 3)
|
||||
self.assertAlmostEqual(layer.extent().xMaximum(), 149.60678790, 3)
|
||||
self.assertAlmostEqual(layer.extent().yMinimum(), -33.4484168, 3)
|
||||
self.assertAlmostEqual(layer.extent().yMaximum(), -33.391621, 3)
|
||||
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().sphere().centerX(),
|
||||
layer.dataProvider().boundingVolume().box().centerX(),
|
||||
-4595750.5786,
|
||||
1,
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
layer.dataProvider().boundingVolume().sphere().centerY(),
|
||||
layer.dataProvider().boundingVolume().box().centerY(),
|
||||
2698725.128252,
|
||||
1,
|
||||
)
|
||||
self.assertEqual(
|
||||
layer.dataProvider().boundingVolume().sphere().centerZ(), -3493318.0
|
||||
)
|
||||
self.assertEqual(
|
||||
layer.dataProvider().boundingVolume().sphere().radius(), 1983.0
|
||||
layer.dataProvider().boundingVolume().box().centerZ(), -3493318.0
|
||||
)
|
||||
|
||||
# check that version, tileset version, and z range are in html metadata
|
||||
|
@ -18,9 +18,7 @@ from qgis.core import (
|
||||
Qgis,
|
||||
QgsSphere,
|
||||
QgsOrientedBox3D,
|
||||
QgsTiledSceneBoundingVolumeSphere,
|
||||
QgsTiledSceneBoundingVolumeRegion,
|
||||
QgsTiledSceneBoundingVolumeBox,
|
||||
QgsTiledSceneBoundingVolume,
|
||||
QgsBox3d,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsCoordinateTransform,
|
||||
@ -36,82 +34,18 @@ TEST_DATA_DIR = unitTestDataPath()
|
||||
|
||||
|
||||
class TestQgsTiledSceneBoundingVolume(QgisTestCase):
|
||||
def test_region(self):
|
||||
volume = QgsTiledSceneBoundingVolumeRegion(QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
self.assertEqual(volume.type(), Qgis.TiledSceneBoundingVolumeType.Region)
|
||||
volume.transform(QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0))
|
||||
# should be no change when transforming regions!
|
||||
self.assertEqual(volume.region(), QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
|
||||
cloned = volume.clone()
|
||||
self.assertIsInstance(cloned, QgsTiledSceneBoundingVolumeRegion)
|
||||
self.assertEqual(cloned.region(), QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
|
||||
# bounds
|
||||
bounds = volume.bounds()
|
||||
self.assertEqual(bounds.xMinimum(), 1)
|
||||
self.assertEqual(bounds.xMaximum(), 10)
|
||||
self.assertEqual(bounds.yMinimum(), 2)
|
||||
self.assertEqual(bounds.yMaximum(), 11)
|
||||
self.assertEqual(bounds.zMinimum(), 3)
|
||||
self.assertEqual(bounds.zMaximum(), 12)
|
||||
|
||||
geometry_2d = volume.as2DGeometry()
|
||||
self.assertEqual(geometry_2d.asWkt(), "Polygon ((1 2, 10 2, 10 11, 1 11, 1 2))")
|
||||
|
||||
# with coordinate transform
|
||||
volume = QgsTiledSceneBoundingVolumeRegion(
|
||||
QgsBox3d(
|
||||
-4595750,
|
||||
2698725,
|
||||
-3493318,
|
||||
-4595750 + 1000,
|
||||
2698725 + 1500,
|
||||
-3493318 + 2000,
|
||||
)
|
||||
)
|
||||
transform = QgsCoordinateTransform(
|
||||
QgsCoordinateReferenceSystem("EPSG:4978"),
|
||||
QgsCoordinateReferenceSystem("EPSG:4979"),
|
||||
QgsCoordinateTransformContext(),
|
||||
)
|
||||
bounds = volume.bounds(transform)
|
||||
self.assertAlmostEqual(bounds.xMinimum(), 149.5582617, 3)
|
||||
self.assertAlmostEqual(bounds.xMaximum(), 149.577611, 3)
|
||||
self.assertAlmostEqual(bounds.yMinimum(), -33.424296, 3)
|
||||
self.assertAlmostEqual(bounds.yMaximum(), -33.4011944, 3)
|
||||
self.assertAlmostEqual(bounds.zMinimum(), -1122.81806, 3)
|
||||
self.assertAlmostEqual(bounds.zMaximum(), 1332.44347, 3)
|
||||
|
||||
geometry_2d = volume.as2DGeometry(transform)
|
||||
self.assertEqual(
|
||||
geometry_2d.asWkt(3),
|
||||
"Polygon ((149.572 -33.424, 149.558 -33.421, 149.558 -33.405, 149.564 -33.401, 149.578 -33.405, 149.578 -33.42, 149.572 -33.424))",
|
||||
)
|
||||
|
||||
def test_region_intersects(self):
|
||||
volume = QgsTiledSceneBoundingVolumeRegion(QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
self.assertFalse(
|
||||
volume.intersects(
|
||||
QgsOrientedBox3D.fromBox3D(QgsBox3d(11, 2, 3, 10, 11, 12))
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
volume.intersects(QgsOrientedBox3D.fromBox3D(QgsBox3d(9, 2, 3, 10, 11, 12)))
|
||||
)
|
||||
|
||||
def test_box(self):
|
||||
volume = QgsTiledSceneBoundingVolumeBox(
|
||||
volume = QgsTiledSceneBoundingVolume(
|
||||
QgsOrientedBox3D([1, 2, 3], [10, 0, 0, 0, 20, 0, 0, 0, 30])
|
||||
)
|
||||
self.assertEqual(volume.type(), Qgis.TiledSceneBoundingVolumeType.OrientedBox)
|
||||
volume.transform(QgsMatrix4x4(1.5, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1))
|
||||
self.assertEqual(
|
||||
volume.box(), QgsOrientedBox3D([1.5, 4, 9], [15, 0, 0, 0, 40, 0, 0, 0, 90])
|
||||
)
|
||||
|
||||
cloned = volume.clone()
|
||||
self.assertIsInstance(cloned, QgsTiledSceneBoundingVolumeBox)
|
||||
cloned = QgsTiledSceneBoundingVolume(volume)
|
||||
self.assertIsInstance(cloned, QgsTiledSceneBoundingVolume)
|
||||
self.assertEqual(
|
||||
cloned.box(), QgsOrientedBox3D([1.5, 4, 9], [15, 0, 0, 0, 40, 0, 0, 0, 90])
|
||||
)
|
||||
@ -132,7 +66,7 @@ class TestQgsTiledSceneBoundingVolume(QgisTestCase):
|
||||
)
|
||||
|
||||
# with coordinate transform
|
||||
volume = QgsTiledSceneBoundingVolumeBox(
|
||||
volume = QgsTiledSceneBoundingVolume(
|
||||
QgsOrientedBox3D(
|
||||
[-4595750, 2698725, -3493318], [1000, 0, 0, 0, 1500, 0, 0, 0, 2000]
|
||||
)
|
||||
@ -157,7 +91,7 @@ class TestQgsTiledSceneBoundingVolume(QgisTestCase):
|
||||
)
|
||||
|
||||
def test_box_intersects(self):
|
||||
volume = QgsTiledSceneBoundingVolumeBox(
|
||||
volume = QgsTiledSceneBoundingVolume(
|
||||
QgsOrientedBox3D(
|
||||
[1, 1, 1],
|
||||
[
|
||||
@ -182,7 +116,7 @@ class TestQgsTiledSceneBoundingVolume(QgisTestCase):
|
||||
)
|
||||
)
|
||||
|
||||
volume = QgsTiledSceneBoundingVolumeBox(
|
||||
volume = QgsTiledSceneBoundingVolume(
|
||||
QgsOrientedBox3D(
|
||||
[1, 1, 1], [0.7071, 0, 0.7071, 0, 3, 0, -0.7071 * 2, 0, 0.7071 * 2]
|
||||
)
|
||||
@ -195,67 +129,6 @@ class TestQgsTiledSceneBoundingVolume(QgisTestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_sphere(self):
|
||||
volume = QgsTiledSceneBoundingVolumeSphere(QgsSphere(1, 2, 3, 10))
|
||||
self.assertEqual(volume.type(), Qgis.TiledSceneBoundingVolumeType.Sphere)
|
||||
volume.transform(QgsMatrix4x4(1.5, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1))
|
||||
self.assertEqual(volume.sphere(), QgsSphere(1.5, 4, 9, 30))
|
||||
|
||||
cloned = volume.clone()
|
||||
self.assertIsInstance(cloned, QgsTiledSceneBoundingVolumeSphere)
|
||||
self.assertEqual(cloned.sphere(), QgsSphere(1.5, 4, 9, 30))
|
||||
|
||||
# bounds
|
||||
bounds = volume.bounds()
|
||||
self.assertEqual(bounds.xMinimum(), -28.5)
|
||||
self.assertEqual(bounds.xMaximum(), 31.5)
|
||||
self.assertEqual(bounds.yMinimum(), -26.0)
|
||||
self.assertEqual(bounds.yMaximum(), 34.0)
|
||||
self.assertEqual(bounds.zMinimum(), -21.0)
|
||||
self.assertEqual(bounds.zMaximum(), 39)
|
||||
|
||||
geometry_2d = volume.as2DGeometry()
|
||||
self.assertEqual(
|
||||
geometry_2d.asWkt(),
|
||||
"CurvePolygon (CircularString (1.5 34, 31.5 4, 1.5 -26, -28.5 4, 1.5 34))",
|
||||
)
|
||||
|
||||
# with coordinate transform
|
||||
volume = QgsTiledSceneBoundingVolumeSphere(
|
||||
QgsSphere(-4595750, 2698725, -3493318, 1983)
|
||||
)
|
||||
transform = QgsCoordinateTransform(
|
||||
QgsCoordinateReferenceSystem("EPSG:4978"),
|
||||
QgsCoordinateReferenceSystem("EPSG:4979"),
|
||||
QgsCoordinateTransformContext(),
|
||||
)
|
||||
bounds = volume.bounds(transform)
|
||||
self.assertAlmostEqual(bounds.xMinimum(), 149.5484294320, 3)
|
||||
self.assertAlmostEqual(bounds.xMaximum(), 149.606785943, 3)
|
||||
self.assertAlmostEqual(bounds.yMinimum(), -33.448419, 3)
|
||||
self.assertAlmostEqual(bounds.yMaximum(), -33.39162, 3)
|
||||
self.assertAlmostEqual(bounds.zMinimum(), -2659.1526749, 3)
|
||||
self.assertAlmostEqual(bounds.zMaximum(), 4055.8967716, 3)
|
||||
|
||||
geometry_2d = volume.as2DGeometry(transform)
|
||||
self.assertEqual(
|
||||
geometry_2d.asWkt(3),
|
||||
"Polygon ((149.592 -33.433, 149.594 -33.431, 149.596 -33.429, 149.597 -33.427, 149.598 -33.425, 149.599 -33.423, 149.599 -33.421, 149.599 -33.418, 149.598 -33.416, 149.598 -33.414, 149.596 -33.412, 149.595 -33.41, 149.593 -33.408, 149.591 -33.406, 149.589 -33.405, 149.586 -33.404, 149.584 -33.403, 149.581 -33.402, 149.578 -33.402, 149.576 -33.402, 149.573 -33.403, 149.57 -33.403, 149.568 -33.404, 149.565 -33.405, 149.563 -33.407, 149.561 -33.409, 149.56 -33.411, 149.558 -33.413, 149.557 -33.415, 149.557 -33.417, 149.556 -33.419, 149.556 -33.422, 149.557 -33.424, 149.558 -33.426, 149.559 -33.428, 149.56 -33.43, 149.562 -33.432, 149.564 -33.434, 149.566 -33.435, 149.569 -33.436, 149.571 -33.437, 149.574 -33.438, 149.577 -33.438, 149.58 -33.438, 149.582 -33.437, 149.585 -33.437, 149.588 -33.436, 149.59 -33.435, 149.592 -33.433))",
|
||||
)
|
||||
|
||||
def test_sphere_intersects(self):
|
||||
volume = QgsTiledSceneBoundingVolumeSphere(QgsSphere(1, 2, 3, 6))
|
||||
self.assertFalse(
|
||||
volume.intersects(
|
||||
QgsOrientedBox3D.fromBox3D(QgsBox3d(11, 2, 3, 10, 11, 12))
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
volume.intersects(
|
||||
QgsOrientedBox3D.fromBox3D(QgsBox3d(6.5, 2, 3, 10, 11, 12))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
@ -16,10 +16,11 @@ import unittest
|
||||
import qgis # NOQA
|
||||
from qgis.core import (
|
||||
Qgis,
|
||||
QgsTiledSceneBoundingVolumeRegion,
|
||||
QgsTiledSceneBoundingVolume,
|
||||
QgsBox3d,
|
||||
QgsMatrix4x4,
|
||||
QgsTiledSceneTile,
|
||||
QgsOrientedBox3D
|
||||
)
|
||||
from qgis.testing import start_app, QgisTestCase
|
||||
|
||||
@ -45,9 +46,9 @@ class TestQgsTiledSceneTile(QgisTestCase):
|
||||
|
||||
node = QgsTiledSceneTile()
|
||||
node.setBoundingVolume(
|
||||
QgsTiledSceneBoundingVolumeRegion(QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
QgsTiledSceneBoundingVolume(QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12)))
|
||||
)
|
||||
self.assertEqual(node.boundingVolume().region(), QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
self.assertEqual(node.boundingVolume().box(), QgsOrientedBox3D([5.5, 6.5, 7.5], [4.5, 0, 0, 0, 4.5, 0, 0, 0, 4.5]))
|
||||
|
||||
node = QgsTiledSceneTile()
|
||||
node.setTransform(QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0))
|
||||
@ -68,7 +69,7 @@ class TestQgsTiledSceneTile(QgisTestCase):
|
||||
node = QgsTiledSceneTile(11)
|
||||
node.setRefinementProcess(Qgis.TileRefinementProcess.Additive)
|
||||
node.setBoundingVolume(
|
||||
QgsTiledSceneBoundingVolumeRegion(QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
QgsTiledSceneBoundingVolume(QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12)))
|
||||
)
|
||||
node.setTransform(QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0))
|
||||
node.setResources({"content": "parent"})
|
||||
@ -78,7 +79,7 @@ class TestQgsTiledSceneTile(QgisTestCase):
|
||||
self.assertTrue(copy.isValid())
|
||||
self.assertEqual(copy.id(), 11)
|
||||
self.assertEqual(copy.refinementProcess(), Qgis.TileRefinementProcess.Additive)
|
||||
self.assertEqual(copy.boundingVolume().region(), QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
self.assertEqual(copy.boundingVolume().box(), QgsOrientedBox3D([5.5, 6.5, 7.5], [4.5, 0, 0, 0, 4.5, 0, 0, 0, 4.5]))
|
||||
self.assertEqual(
|
||||
copy.transform(),
|
||||
QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0),
|
||||
@ -90,7 +91,7 @@ class TestQgsTiledSceneTile(QgisTestCase):
|
||||
node = QgsTiledSceneTile()
|
||||
self.assertIsNone(node.transform())
|
||||
node.setBoundingVolume(
|
||||
QgsTiledSceneBoundingVolumeRegion(QgsBox3d(1, 2, 3, 10, 11, 12))
|
||||
QgsTiledSceneBoundingVolume(QgsOrientedBox3D.fromBox3D(QgsBox3d(1, 2, 3, 10, 11, 12)))
|
||||
)
|
||||
node.setTransform(QgsMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user