QGIS API Documentation  3.2.0-Bonn (bc43194)
qgstriangularmesh.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstriangularmesh.cpp
3  ---------------------
4  begin : April 2018
5  copyright : (C) 2018 by Peter Petrik
6  email : zilolv at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgstriangularmesh.h"
19 #include "qgsrendercontext.h"
20 #include "qgscoordinatetransform.h"
21 
22 static void ENP_centroid_step( const QPolygonF &pX, double &cx, double &cy, double &signedArea, int i, int i1 )
23 {
24  double x0 = 0.0; // Current vertex X
25  double y0 = 0.0; // Current vertex Y
26  double x1 = 0.0; // Next vertex X
27  double y1 = 0.0; // Next vertex Y
28  double a = 0.0; // Partial signed area
29 
30  x0 = pX[i].x();
31  y0 = pX[i].y();
32  x1 = pX[i1].x();
33  y1 = pX[i1].y();
34  a = x0 * y1 - x1 * y0;
35  signedArea += a;
36  cx += ( x0 + x1 ) * a;
37  cy += ( y0 + y1 ) * a;
38 }
39 
40 static void ENP_centroid( const QPolygonF &pX, double &cx, double &cy )
41 {
42  // http://stackoverflow.com/questions/2792443/finding-the-centroid-of-a-polygon/2792459#2792459
43  cx = 0;
44  cy = 0;
45 
46  if ( pX.isEmpty() )
47  return;
48 
49  double signedArea = 0.0;
50 
51  // For all vertices except last
52  int i = 0;
53  for ( ; i < pX.size() - 1; ++i )
54  {
55  ENP_centroid_step( pX, cx, cy, signedArea, i, i + 1 );
56  }
57  // Do last vertex separately to avoid performing an expensive
58  // modulus operation in each iteration.
59  ENP_centroid_step( pX, cx, cy, signedArea, i, 0 );
60 
61  signedArea *= 0.5;
62  cx /= ( 6.0 * signedArea );
63  cy /= ( 6.0 * signedArea );
64 }
65 
66 
67 void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
68 {
69  Q_ASSERT( nativeMesh );
70  Q_ASSERT( context );
71 
72  mTriangularMesh.vertices.clear();
73  mTriangularMesh.faces.clear();
74  mTrianglesToNativeFaces.clear();
75  mNativeMeshFaceCentroids.clear();
76 
77  // TRANSFORM VERTICES
78  QgsCoordinateTransform transform = context->coordinateTransform();
79  mTriangularMesh.vertices.resize( nativeMesh->vertices.size() );
80  for ( int i = 0; i < nativeMesh->vertices.size(); ++i )
81  {
82  const QgsMeshVertex &vertex = nativeMesh->vertices.at( i );
83  if ( transform.isValid() )
84  {
85  QgsPointXY mapPoint = transform.transform( QgsPointXY( vertex.x(), vertex.y() ) );
86  QgsMeshVertex mapVertex( mapPoint );
87  mapVertex.setZ( vertex.z() );
88  mapVertex.setM( vertex.m() );
89  mTriangularMesh.vertices[i] = mapVertex;
90  }
91  else
92  {
93  mTriangularMesh.vertices[i] = vertex;
94  }
95  }
96 
97  // CREATE TRIANGULAR MESH
98  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
99  {
100  const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
101  if ( face.size() == 3 )
102  {
103  // triangle
104  mTriangularMesh.faces.push_back( face );
105  mTrianglesToNativeFaces.push_back( i );
106  }
107  else if ( face.size() == 4 )
108  {
109  // quad
110  QgsMeshFace face1;
111  face1.push_back( face[0] );
112  face1.push_back( face[1] );
113  face1.push_back( face[2] );
114 
115  mTriangularMesh.faces.push_back( face1 );
116  mTrianglesToNativeFaces.push_back( i );
117 
118  QgsMeshFace face2;
119  face2.push_back( face[0] );
120  face2.push_back( face[2] );
121  face2.push_back( face[3] );
122 
123  mTriangularMesh.faces.push_back( face2 );
124  mTrianglesToNativeFaces.push_back( i );
125  }
126  }
127 
128  // CALCULATE CENTROIDS
129  mNativeMeshFaceCentroids.resize( nativeMesh->faces.size() );
130  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
131  {
132  const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
133  QVector<QPointF> points;
134  points.reserve( face.size() );
135  for ( int j = 0; j < face.size(); ++j )
136  {
137  int index = face.at( j );
138  const QgsMeshVertex &vertex = mTriangularMesh.vertices[index]; // we need projected vertices
139  points.push_back( vertex.toQPointF() );
140  }
141  QPolygonF poly( points );
142  double cx, cy;
143  ENP_centroid( poly, cx, cy );
144  mNativeMeshFaceCentroids[i] = QgsMeshVertex( cx, cy );
145  }
146 }
147 
148 const QVector<QgsMeshVertex> &QgsTriangularMesh::vertices() const
149 {
150  return mTriangularMesh.vertices;
151 }
152 
153 const QVector<QgsMeshFace> &QgsTriangularMesh::triangles() const
154 {
155  return mTriangularMesh.faces;
156 }
157 
158 const QVector<QgsMeshVertex> &QgsTriangularMesh::centroids() const
159 {
160  return mNativeMeshFaceCentroids;
161 }
162 
163 const QVector<int> &QgsTriangularMesh::trianglesToNativeFaces() const
164 {
165  return mTrianglesToNativeFaces;
166 }
167 
double y
Definition: qgspoint.h:42
QPointF toQPointF() const
Returns the point as a QPointF.
Definition: qgspoint.h:264
void setZ(double z)
Sets the point&#39;s z-coordinate.
Definition: qgspoint.h:237
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
QVector< QgsMeshVertex > vertices
vertices
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
void setM(double m)
Sets the point&#39;s m-value.
Definition: qgspoint.h:252
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context, or an invalid transform is no coordinate tr...
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
void update(QgsMesh *nativeMesh, QgsRenderContext *context)
Constructs triangular mesh from layer&#39;s native mesh and context.
Contains information about the context of a rendering operation.
Mesh - vertices and faces.
QVector< int > QgsMeshFace
List of vertex indexes.
Class for doing transforms between two map coordinate systems.
double z
Definition: qgspoint.h:43
QVector< QgsMeshFace > faces
faces
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map CRS.
const QVector< QgsMeshVertex > & centroids() const
Returns centroids of the native faces in map CRS.
double m
Definition: qgspoint.h:44
QgsPoint QgsMeshVertex
xyz coords of vertex
double x
Definition: qgspoint.h:41