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";
76 _mapLoadedFlag =
false;
81 _osmParserWorker->
start(filePath);
86 QByteArray vertexData;
87 const auto &buildings = _osmParserWorker->
mapBuildings();
88 vertexData.reserve(
static_cast<qsizetype
>(buildings.size()) * 1000);
90 for (
auto it = buildings.begin(), end = buildings.end(); it != end; ++it) {
91 const auto &building = it.value();
92 float buildingHeight = 0;
94 std::vector<std::array<float, 2>> allPoints;
95 std::vector<std::array<float, 2>> ringPoints;
96 std::vector<std::vector<std::array<float, 2>>> polygon;
97 std::vector<QVector3D> mesh;
99 if (building.height > 0) {
100 buildingHeight = building.height;
101 }
else if (building.levels > 0) {
102 buildingHeight =
static_cast<float>(building.levels) * _buildingLevelHeight;
107 for (
const auto &pt : building.points_local) {
108 ringPoints.push_back({pt.x(), pt.y()});
109 allPoints.push_back({pt.x(), pt.y()});
111 polygon.push_back(ringPoints);
114 for (
const auto &pt : building.points_local_inner) {
115 ringPoints.push_back({pt.x(), pt.y()});
116 allPoints.push_back({pt.x(), pt.y()});
118 if (!ringPoints.empty()) {
119 polygon.push_back(ringPoints);
122 const std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
124 for (
size_t i = 0; i < indices.size(); i += 3) {
125 uint32_t idx = indices[i];
126 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], buildingHeight));
127 idx = indices[i + 1];
128 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], buildingHeight));
132 idx = indices[i + 2];
133 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
134 idx = indices[i + 1];
135 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
137 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
140 if (buildingHeight > 0) {
141 _triangulateWallsExtrudedPolygon(mesh, building.points_local, buildingHeight,
false);
142 _triangulateWallsExtrudedPolygon(mesh, building.points_local, buildingHeight,
true);
144 _triangulateWallsExtrudedPolygon(mesh, building.points_local_inner, buildingHeight,
false);
145 _triangulateWallsExtrudedPolygon(mesh, building.points_local_inner, buildingHeight,
true);
148 QByteArray buildingData(mesh.size() * 3 *
sizeof(
float), Qt::Initialization::Uninitialized);
149 float *p =
reinterpret_cast<float *
>(buildingData.data());
151 for (
const auto &vertex : mesh) {
157 vertexData.append(buildingData);
162void OsmParser::_triangulateWallsExtrudedPolygon(std::vector<QVector3D> &triangulatedMesh,
const std::vector<QVector2D> &verticesCcw,
float h,
bool inverseOrder)
164 std::vector<QVector3D> quad(4);
165 const size_t verticesSize = verticesCcw.size();
168 for (
size_t i = 0; i < verticesSize; i++) {
169 const size_t next = (i + 1 < verticesSize) ? (i + 1) :
size_t{0};
170 quad[0] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), 0);
171 quad[1] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), 0);
172 quad[2] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), h);
173 quad[3] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), h);
174 _triangulateRectangle(triangulatedMesh, quad,
false);
176 _triangulateRectangle(triangulatedMesh, quad,
true);
178 for (
size_t i = 0; i < verticesSize; i++) {
179 const size_t next = (i + 1 < verticesSize) ? (i + 1) :
size_t{0};
180 quad[0] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), 0);
181 quad[1] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), 0);
182 quad[2] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), h);
183 quad[3] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), h);
184 _triangulateRectangle(triangulatedMesh, quad,
false);
186 _triangulateRectangle(triangulatedMesh, quad,
true);
190void OsmParser::_triangulateRectangle(std::vector<QVector3D> &triangulatedMesh,
const std::vector<QVector3D> &verticesCcw,
bool invertNormal)
192 using Vec3i = std::array<unsigned int, 3>;
193 std::array<Vec3i, 2> meshIndices;
196 meshIndices[0] = {3, 1, 0};
197 meshIndices[1] = {3, 2, 1};
199 meshIndices[0] = {0, 1, 3};
200 meshIndices[1] = {1, 2, 3};
203 for (
const auto &tri : meshIndices) {
204 for (
unsigned int vi : tri) {
205 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)