16 auto *viewer3DSettings = SettingsManager::instance()->viewer3DSettings();
17 connect(viewer3DSettings->osmFilePath(), &
Fact::rawValueChanged,
this, &Viewer3DTerrainGeometry::_clearScene);
24 const int stride = 3 *
sizeof(float)
29 qCDebug(Viewer3DTerrainGeometryLog) <<
"buildTerrain returned false (sector/stack count likely 0)";
33 QByteArray vertexData;
34 vertexData.resize(_vertices.size() * stride);
35 float *p =
reinterpret_cast<float *
>(vertexData.data());
37 for (
size_t i = 0; i < _vertices.size(); ++i) {
38 *p++ = _vertices[i].x();
39 *p++ = _vertices[i].y();
40 *p++ = _vertices[i].z();
42 *p++ = _normals[i].x();
43 *p++ = _normals[i].y();
44 *p++ = _normals[i].z();
46 *p++ = _texCoords[i].x();
47 *p++ = _texCoords[i].y();
50 qCDebug(Viewer3DTerrainGeometryLog) <<
"Terrain built:" << _vertices.size() <<
"vertices," << _sectorCount <<
"sectors," << _stackCount <<
"stacks";
52 setVertexData(vertexData);
55 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
56 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
58 QQuick3DGeometry::Attribute::F32Type);
59 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
61 QQuick3DGeometry::Attribute::F32Type);
62 addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic,
64 QQuick3DGeometry::Attribute::F32Type);
69QVector3D Viewer3DTerrainGeometry::_computeFaceNormal(
const QVector3D &x1,
const QVector3D &x2,
const QVector3D &x3)
71 constexpr float EPSILON = 0.000001f;
73 QVector3D normal(0, 0, 0);
75 const float ex1 = x2.x() - x1.x();
76 const float ey1 = x2.y() - x1.y();
77 const float ez1 = x2.z() - x1.z();
78 const float ex2 = x3.x() - x1.x();
79 const float ey2 = x3.y() - x1.y();
80 const float ez2 = x3.z() - x1.z();
82 const float nx = ey1 * ez2 - ez1 * ey2;
83 const float ny = ez1 * ex2 - ex1 * ez2;
84 const float nz = ex1 * ey2 - ey1 * ex2;
86 const float length = std::sqrt(nx * nx + ny * ny + nz * nz);
87 if (length > EPSILON) {
88 const float lengthInv = 1.0f / length;
89 normal.setX(nx * lengthInv);
90 normal.setY(ny * lengthInv);
91 normal.setZ(nz * lengthInv);
97void Viewer3DTerrainGeometry::_clearScene()
110 if (_sectorCount == newSectorCount) {
113 _sectorCount = newSectorCount;
119 if (_stackCount == newStackCount) {
122 _stackCount = newStackCount;
126bool Viewer3DTerrainGeometry::_buildTerrain(
const QGeoCoordinate &roiMinCoordinate,
const QGeoCoordinate &roiMaxCoordinate,
const QGeoCoordinate &refCoordinate,
bool scale)
128 if (_sectorCount == 0 || _stackCount == 0) {
132 const float sectorLength = std::abs(roiMaxCoordinate.longitude() - roiMinCoordinate.longitude());
133 const float stackLength = std::abs(roiMaxCoordinate.latitude() - roiMinCoordinate.latitude());
134 const float stackRef = roiMaxCoordinate.latitude();
135 const float sectorRef = roiMinCoordinate.longitude();
140 std::vector<Vertex> tmpVertices;
148 const float sectorStep = sectorLength / _sectorCount;
149 const float stackStep = stackLength / _stackCount;
150 float sectorAngle, stackAngle;
152 for (
int i = 0; i <= _stackCount; ++i) {
153 stackAngle = stackRef - i * stackStep;
155 for (
int j = 0; j <= _sectorCount; ++j) {
156 sectorAngle = sectorRef + j * sectorStep;
160 vertex.x = localPoint.x();
161 vertex.y = localPoint.y();
164 vertex.s = (sectorAngle + 180.0f) / 360.0f;
165 minS = std::fmin(minS, vertex.s);
166 maxS = std::fmax(maxS, vertex.s);
169 const double sinLatitude = std::sin(qDegreesToRadians(stackAngle));
170 vertex.t = 0.5 - std::log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * M_PI);
172 vertex.t = (stackRef - stackAngle) / 180;
174 minT = std::fmin(minT, vertex.t);
175 maxT = std::fmax(maxT, vertex.t);
177 tmpVertices.push_back(vertex);
181 const float scaleT = maxT - minT;
182 const float scaleS = maxS - minS;
187 Vertex v1, v2, v3, v4;
191 for (
int i = 0; i < _stackCount; ++i) {
192 vi1 = i * (_sectorCount + 1);
193 vi2 = (i + 1) * (_sectorCount + 1);
194 stackAngle = stackRef - i * stackStep;
196 for (
int j = 0; j < _sectorCount; ++j, ++vi1, ++vi2) {
197 v1 = tmpVertices[vi1];
198 v2 = tmpVertices[vi2];
199 v3 = tmpVertices[vi1 + 1];
200 v4 = tmpVertices[vi2 + 1];
203 v1.s = (v1.s - minS) / scaleS;
204 v1.t = (v1.t - minT) / scaleT;
205 v2.s = (v2.s - minS) / scaleS;
206 v2.t = (v2.t - minT) / scaleT;
207 v3.s = (v3.s - minS) / scaleS;
208 v3.t = (v3.t - minT) / scaleT;
209 v4.s = (v4.s - minS) / scaleS;
210 v4.t = (v4.t - minT) / scaleT;
213 if (stackAngle < 90) {
214 _vertices.push_back(QVector3D(v1.x, v1.y, v1.z));
215 _vertices.push_back(QVector3D(v2.x, v2.y, v2.z));
216 _vertices.push_back(QVector3D(v3.x, v3.y, v3.z));
218 _texCoords.push_back(QVector2D(v1.s, v1.t));
219 _texCoords.push_back(QVector2D(v2.s, v2.t));
220 _texCoords.push_back(QVector2D(v3.s, v3.t));
222 n = _computeFaceNormal(QVector3D(v1.x, v1.y, v1.z),
223 QVector3D(v2.x, v2.y, v2.z),
224 QVector3D(v3.x, v3.y, v3.z));
226 for (
int k = 0; k < 3; ++k) {
227 _normals.push_back(n);
231 if (stackAngle > -90) {
232 _vertices.push_back(QVector3D(v3.x, v3.y, v3.z));
233 _vertices.push_back(QVector3D(v2.x, v2.y, v2.z));
234 _vertices.push_back(QVector3D(v4.x, v4.y, v4.z));
236 _texCoords.push_back(QVector2D(v3.s, v3.t));
237 _texCoords.push_back(QVector2D(v2.s, v2.t));
238 _texCoords.push_back(QVector2D(v4.s, v4.t));
240 n = _computeFaceNormal(QVector3D(v3.x, v3.y, v3.z),
241 QVector3D(v2.x, v2.y, v2.z),
242 QVector3D(v4.x, v4.y, v4.z));
244 for (
int k = 0; k < 3; ++k) {
245 _normals.push_back(n);
256 if (_roiMin == newRoiMin) {
265 if (_roiMax == newRoiMax) {
274 if (_refCoordinate == newRefCoordinate) {
277 _refCoordinate = newRefCoordinate;
Geographic coordinate conversion utilities using GeographicLib.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
static constexpr double kMaxLatitude
void rawValueChanged(const QVariant &value)
void setRoiMax(const QGeoCoordinate &newRoiMax)
void setRoiMin(const QGeoCoordinate &newRoiMin)
QGeoCoordinate roiMin() const
void setStackCount(int newStackCount)
void refCoordinateChanged()
QGeoCoordinate roiMax() const
void sectorCountChanged()
QGeoCoordinate refCoordinate() const
void setSectorCount(int newSectorCount)
void setRefCoordinate(const QGeoCoordinate &newRefCoordinate)
QVector3D convertGpsToEnu(const QGeoCoordinate &coord, const QGeoCoordinate &ref)