Skip to content

Commit a2ff363

Browse files
committedNov 23, 2017
Fix tessellation of polygons that are not horizontal
Discovered by Nyall while working on PR #5708 Tessellation would shift coordinates because when points got reprojected to the new base, the Z coordinates were considered zero (which worked only when all points were on the same plane).
1 parent d1cf7e6 commit a2ff363

File tree

2 files changed

+30
-18
lines changed

2 files changed

+30
-18
lines changed
 

‎src/3d/qgstessellator.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "poly2tri/poly2tri.h"
2525

2626
#include <QtDebug>
27+
#include <QMatrix4x4>
2728
#include <QVector3D>
2829
#include <algorithm>
2930

@@ -193,7 +194,7 @@ static void _normalVectorToXYVectors( const QVector3D &pNormal, QVector3D &pXVec
193194
}
194195

195196

196-
static void _ringToPoly2tri( const QgsCurve *ring, const QgsPoint &ptFirst, const QVector3D &pXVector, const QVector3D &pYVector, std::vector<p2t::Point *> &polyline, QHash<p2t::Point *, float> &zHash )
197+
static void _ringToPoly2tri( const QgsCurve *ring, const QgsPoint &ptFirst, const QMatrix4x4 &toNewBase, std::vector<p2t::Point *> &polyline, QHash<p2t::Point *, float> &zHash )
197198
{
198199
QgsVertexId::VertexType vt;
199200
QgsPoint pt;
@@ -206,10 +207,11 @@ static void _ringToPoly2tri( const QgsCurve *ring, const QgsPoint &ptFirst, cons
206207
for ( int i = 0; i < pCount - 1; ++i )
207208
{
208209
ring->pointAt( i, pt, vt );
209-
const float z = std::isnan( pt.z() ) ? 0 : pt.z();
210-
QVector3D tempPt( pt.x() - x0, pt.y() - y0, z - z0 );
211-
const float x = QVector3D::dotProduct( tempPt, pXVector );
212-
const float y = QVector3D::dotProduct( tempPt, pYVector );
210+
QVector4D tempPt( pt.x() - x0, pt.y() - y0, std::isnan( pt.z() ) ? 0 : pt.z() - z0, 0 );
211+
QVector4D newBasePt = toNewBase * tempPt;
212+
const float x = newBasePt.x();
213+
const float y = newBasePt.y();
214+
const float z = newBasePt.z();
213215

214216
const bool found = std::find_if( polyline.begin(), polyline.end(), [x, y]( p2t::Point *&p ) { return *p == p2t::Point( x, y ); } ) != polyline.end();
215217

@@ -301,23 +303,35 @@ void QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeigh
301303
QVector3D pXVector, pYVector;
302304
_normalVectorToXYVectors( pNormal, pXVector, pYVector );
303305

306+
// so now we have three orthogonal unit vectors defining new base
307+
// let's build transform matrix. We actually need just a 3x3 matrix,
308+
// but Qt does not have good support for it, so using 4x4 matrix instead.
309+
QMatrix4x4 toNewBase(
310+
pXVector.x(), pXVector.y(), pXVector.z(), 0,
311+
pYVector.x(), pYVector.y(), pYVector.z(), 0,
312+
pNormal.x(), pNormal.y(), pNormal.z(), 0,
313+
0, 0, 0, 0 );
314+
315+
// our 3x3 matrix is orthogonal, so for inverse we only need to transpose it
316+
QMatrix4x4 toOldBase = toNewBase.transposed();
317+
304318
const QgsPoint ptFirst( exterior->startPoint() );
305-
_ringToPoly2tri( exterior, ptFirst, pXVector, pYVector, polyline, z );
319+
_ringToPoly2tri( exterior, ptFirst, toNewBase, polyline, z );
306320
polylinesToDelete << polyline;
307321

308322
// TODO: robustness (no nearly duplicate points, invalid geometries ...)
309323

310-
double x0 = ptFirst.x(), y0 = ptFirst.y();
324+
double x0 = ptFirst.x(), y0 = ptFirst.y(), z0 = ( std::isnan( ptFirst.z() ) ? 0 : ptFirst.z() );
311325
if ( polyline.size() == 3 && polygon.numInteriorRings() == 0 )
312326
{
313327
for ( std::vector<p2t::Point *>::iterator it = polyline.begin(); it != polyline.end(); it++ )
314328
{
315329
p2t::Point *p = *it;
316-
const double zPt = z[p];
317-
QVector3D nPoint = pXVector * p->x + pYVector * p->y;
330+
QVector4D ptInNewBase( p->x, p->y, z[p], 0 );
331+
QVector4D nPoint = toOldBase * ptInNewBase;
318332
const double fx = nPoint.x() - mOriginX + x0;
319333
const double fy = nPoint.y() - mOriginY + y0;
320-
const double fz = extrusionHeight + ( std::isnan( zPt ) ? 0 : zPt );
334+
const double fz = nPoint.z() + extrusionHeight + z0;
321335
mData << fx << fz << -fy;
322336
if ( mAddNormals )
323337
mData << pNormal.x() << pNormal.z() << - pNormal.y();
@@ -333,7 +347,7 @@ void QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeigh
333347
std::vector<p2t::Point *> holePolyline;
334348
const QgsCurve *hole = polygon.interiorRing( i );
335349

336-
_ringToPoly2tri( hole, ptFirst, pXVector, pYVector, holePolyline, z );
350+
_ringToPoly2tri( hole, ptFirst, toNewBase, holePolyline, z );
337351

338352
cdt->AddHole( holePolyline );
339353
polylinesToDelete << holePolyline;
@@ -351,11 +365,11 @@ void QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeigh
351365
for ( int j = 0; j < 3; ++j )
352366
{
353367
p2t::Point *p = t->GetPoint( j );
354-
const double zPt = z[p];
355-
QVector3D nPoint = pXVector * p->x + pYVector * p->y;
368+
QVector4D ptInNewBase( p->x, p->y, z[p], 0 );
369+
QVector4D nPoint = toOldBase * ptInNewBase;
356370
const double fx = nPoint.x() - mOriginX + x0;
357371
const double fy = nPoint.y() - mOriginY + y0;
358-
const double fz = extrusionHeight + ( std::isnan( zPt ) ? 0 : zPt );
372+
const double fz = nPoint.z() + extrusionHeight + z0;
359373
mData << fx << fz << -fy;
360374
if ( mAddNormals )
361375
mData << pNormal.x() << pNormal.z() << - pNormal.y();

‎tests/src/3d/testqgstessellator.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,8 @@ void TestQgsTessellator::testWalls()
174174

175175
QList<TriangleCoords> tc;
176176

177-
// NOTE - these coordinates are wrong, and this test exposes a different bug in the tesselator
178-
// 2.4 should be 2:
179-
tc << TriangleCoords( QVector3D( 1, 2.4, 14 ), QVector3D( 2, 1.4, 12 ), QVector3D( 3, 2, 13 ) );
180-
tc << TriangleCoords( QVector3D( 1, 2.4, 14 ), QVector3D( 1, 1, 11 ), QVector3D( 2, 1.4, 12 ) );
177+
tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 2, 1, 12 ), QVector3D( 3, 2, 13 ) );
178+
tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 1, 1, 11 ), QVector3D( 2, 1, 12 ) );
181179

182180
tc << TriangleCoords( QVector3D( 1, 1, 11 ), QVector3D( 1, 2, 14 ), QVector3D( 1, 1, 1 ) );
183181
tc << TriangleCoords( QVector3D( 1, 1, 1 ), QVector3D( 1, 2, 14 ), QVector3D( 1, 2, 4 ) );

0 commit comments

Comments
 (0)
Please sign in to comment.