9#include <QtCore/QThread>
11#include <mapbox/earcut.hpp>
22 _setBuildingLevelHeight(viewer3DSettings->buildingLevelHeight()->rawValue());
23 connect(viewer3DSettings->buildingLevelHeight(), &
Fact::rawValueChanged,
this, &OsmParser::_setBuildingLevelHeight);
32 _osmParserWorker->thread()->quit();
33 _osmParserWorker->thread()->wait();
34 delete _osmParserWorker;
46 _gpsRefPoint = QGeoCoordinate(0, 0, 0);
51void OsmParser::_setBuildingLevelHeight(
const QVariant &value)
53 _buildingLevelHeight = value.toFloat();
57void OsmParser::_onOsmParserFinished(
bool isValid)
66 _mapLoadedFlag =
true;
68 qCDebug(OsmParserLog) << _osmParserWorker->
mapBuildings().size() <<
"buildings loaded";
75 _mapLoadedFlag =
false;
78 _osmParserWorker->
start(filePath);
83 QByteArray vertexData;
84 const auto &buildings = _osmParserWorker->
mapBuildings();
85 vertexData.reserve(
static_cast<qsizetype
>(buildings.size()) * 1000);
87 for (
auto it = buildings.begin(), end = buildings.end(); it != end; ++it) {
88 const auto &building = it.value();
89 float buildingHeight = 0;
91 std::vector<std::array<float, 2>> allPoints;
92 std::vector<std::array<float, 2>> ringPoints;
93 std::vector<std::vector<std::array<float, 2>>> polygon;
94 std::vector<QVector3D> mesh;
96 if (building.height > 0) {
97 buildingHeight = building.height;
98 }
else if (building.levels > 0) {
99 buildingHeight =
static_cast<float>(building.levels) * _buildingLevelHeight;
104 for (
const auto &pt : building.points_local) {
105 ringPoints.push_back({pt.x(), pt.y()});
106 allPoints.push_back({pt.x(), pt.y()});
108 polygon.push_back(ringPoints);
111 for (
const auto &pt : building.points_local_inner) {
112 ringPoints.push_back({pt.x(), pt.y()});
113 allPoints.push_back({pt.x(), pt.y()});
115 if (!ringPoints.empty()) {
116 polygon.push_back(ringPoints);
119 const std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
121 for (
size_t i = 0; i < indices.size(); i += 3) {
122 uint32_t idx = indices[i];
123 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], buildingHeight));
124 idx = indices[i + 1];
125 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], buildingHeight));
126 idx = indices[i + 2];
127 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], buildingHeight));
129 idx = indices[i + 2];
130 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
131 idx = indices[i + 1];
132 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
134 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
137 if (buildingHeight > 0) {
138 _triangulateWallsExtrudedPolygon(mesh, building.points_local, buildingHeight,
false);
139 _triangulateWallsExtrudedPolygon(mesh, building.points_local, buildingHeight,
true);
141 _triangulateWallsExtrudedPolygon(mesh, building.points_local_inner, buildingHeight,
false);
142 _triangulateWallsExtrudedPolygon(mesh, building.points_local_inner, buildingHeight,
true);
145 QByteArray buildingData(mesh.size() * 3 *
sizeof(
float), Qt::Initialization::Uninitialized);
146 float *p =
reinterpret_cast<float *
>(buildingData.data());
148 for (
const auto &vertex : mesh) {
154 vertexData.append(buildingData);
159void OsmParser::_triangulateWallsExtrudedPolygon(std::vector<QVector3D> &triangulatedMesh,
const std::vector<QVector2D> &verticesCcw,
float h,
bool inverseOrder)
161 std::vector<QVector3D> quad(4);
162 const size_t verticesSize = verticesCcw.size();
165 for (
size_t i = 0; i < verticesSize; i++) {
166 const size_t next = (i + 1 < verticesSize) ? (i + 1) :
size_t{0};
167 quad[0] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), 0);
168 quad[1] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), 0);
169 quad[2] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), h);
170 quad[3] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), h);
171 _triangulateRectangle(triangulatedMesh, quad,
false);
173 _triangulateRectangle(triangulatedMesh, quad,
true);
175 for (
size_t i = 0; i < verticesSize; i++) {
176 const size_t next = (i + 1 < verticesSize) ? (i + 1) :
size_t{0};
177 quad[0] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), 0);
178 quad[1] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), 0);
179 quad[2] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), h);
180 quad[3] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), h);
181 _triangulateRectangle(triangulatedMesh, quad,
false);
183 _triangulateRectangle(triangulatedMesh, quad,
true);
187void OsmParser::_triangulateRectangle(std::vector<QVector3D> &triangulatedMesh,
const std::vector<QVector3D> &verticesCcw,
bool invertNormal)
189 using Vec3i = std::array<unsigned int, 3>;
190 std::array<Vec3i, 2> meshIndices;
193 meshIndices[0] = {3, 1, 0};
194 meshIndices[1] = {3, 2, 1};
196 meshIndices[0] = {0, 1, 3};
197 meshIndices[1] = {1, 2, 3};
200 for (
const auto &tri : meshIndices) {
201 for (
unsigned int vi : tri) {
202 triangulatedMesh.push_back(verticesCcw[vi]);
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void rawValueChanged(const QVariant &value)
const QGeoCoordinate & coordinateMin() const
void fileParsed(bool isValid)
const QGeoCoordinate & coordinateMax() const
void start(const QString &filePath)
const QMap< uint64_t, BuildingType_t > & mapBuildings() const
const QGeoCoordinate & gpsRefPoint() const
void parseOsmFile(const QString &filePath)
void buildingLevelHeightChanged()
QGeoCoordinate gpsRef() const override
QByteArray buildingToMesh()
void setGpsRef(const QGeoCoordinate &gpsRef)
Viewer3DSettings * viewer3DSettings() const
static SettingsManager * instance()
void gpsRefChanged(QGeoCoordinate newGpsRef, bool isRefSet)