8#include <mapbox/earcut.hpp>
18 Viewer3DSettings* viewer3DSettings = SettingsManager::instance()->viewer3DSettings();
29 _osmParserWorker->thread()->quit();
30 _osmParserWorker->thread()->wait();
31 delete _osmParserWorker;
43 _gpsRefPoint = QGeoCoordinate(0, 0, 0);
48void OsmParser::_setBuildingLevelHeight(
const QVariant &value)
50 _buildingLevelHeight = value.toFloat();
54void OsmParser::_onOsmParserFinished(
bool isValid)
63 _mapLoadedFlag =
true;
65 qCDebug(OsmParserLog) << _osmParserWorker->
mapBuildings().size() <<
"buildings loaded";
72 _mapLoadedFlag =
false;
75 _osmParserWorker->
start(filePath);
80 QByteArray vertexData;
81 const auto &buildings = _osmParserWorker->
mapBuildings();
82 vertexData.reserve(
static_cast<qsizetype
>(buildings.size()) * 1000);
84 for (
auto it = buildings.begin(), end = buildings.end(); it != end; ++it) {
85 const auto &building = it.value();
86 float buildingHeight = 0;
88 std::vector<std::array<float, 2>> allPoints;
89 std::vector<std::array<float, 2>> ringPoints;
90 std::vector<std::vector<std::array<float, 2>>> polygon;
91 std::vector<QVector3D> mesh;
93 if (building.height > 0) {
94 buildingHeight = building.height;
95 }
else if (building.levels > 0) {
96 buildingHeight =
static_cast<float>(building.levels) * _buildingLevelHeight;
101 for (
const auto &pt : building.points_local) {
102 ringPoints.push_back({pt.x(), pt.y()});
103 allPoints.push_back({pt.x(), pt.y()});
105 polygon.push_back(ringPoints);
108 for (
const auto &pt : building.points_local_inner) {
109 ringPoints.push_back({pt.x(), pt.y()});
110 allPoints.push_back({pt.x(), pt.y()});
112 if (!ringPoints.empty()) {
113 polygon.push_back(ringPoints);
116 const std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
118 for (
size_t i = 0; i < indices.size(); i += 3) {
119 uint32_t idx = indices[i];
120 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], buildingHeight));
121 idx = indices[i + 1];
122 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], buildingHeight));
123 idx = indices[i + 2];
124 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], 0));
128 idx = indices[i + 1];
129 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
131 mesh.push_back(QVector3D(allPoints[idx][0], allPoints[idx][1], 0));
134 if (buildingHeight > 0) {
135 _triangulateWallsExtrudedPolygon(mesh, building.points_local, buildingHeight,
false);
136 _triangulateWallsExtrudedPolygon(mesh, building.points_local, buildingHeight,
true);
138 _triangulateWallsExtrudedPolygon(mesh, building.points_local_inner, buildingHeight,
false);
139 _triangulateWallsExtrudedPolygon(mesh, building.points_local_inner, buildingHeight,
true);
142 QByteArray buildingData(mesh.size() * 3 *
sizeof(
float), Qt::Initialization::Uninitialized);
143 float *p =
reinterpret_cast<float *
>(buildingData.data());
145 for (
const auto &vertex : mesh) {
151 vertexData.append(buildingData);
156void OsmParser::_triangulateWallsExtrudedPolygon(std::vector<QVector3D> &triangulatedMesh,
const std::vector<QVector2D> &verticesCcw,
float h,
bool inverseOrder)
158 std::vector<QVector3D> quad(4);
159 const size_t verticesSize = verticesCcw.size();
162 for (
size_t i = 0; i < verticesSize; i++) {
163 const size_t next = (i + 1 < verticesSize) ? (i + 1) :
size_t{0};
164 quad[0] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), 0);
165 quad[1] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), 0);
166 quad[2] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), h);
167 quad[3] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), h);
168 _triangulateRectangle(triangulatedMesh, quad,
false);
170 _triangulateRectangle(triangulatedMesh, quad,
true);
172 for (
size_t i = 0; i < verticesSize; i++) {
173 const size_t next = (i + 1 < verticesSize) ? (i + 1) :
size_t{0};
174 quad[0] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), 0);
175 quad[1] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), 0);
176 quad[2] = QVector3D(verticesCcw[next].x(), verticesCcw[next].y(), h);
177 quad[3] = QVector3D(verticesCcw[i].x(), verticesCcw[i].y(), h);
178 _triangulateRectangle(triangulatedMesh, quad,
false);
180 _triangulateRectangle(triangulatedMesh, quad,
true);
184void OsmParser::_triangulateRectangle(std::vector<QVector3D> &triangulatedMesh,
const std::vector<QVector3D> &verticesCcw,
bool invertNormal)
186 using Vec3i = std::array<unsigned int, 3>;
187 std::array<Vec3i, 2> meshIndices;
190 meshIndices[0] = {3, 1, 0};
191 meshIndices[1] = {3, 2, 1};
193 meshIndices[0] = {0, 1, 3};
194 meshIndices[1] = {1, 2, 3};
197 for (
const auto &tri : meshIndices) {
198 for (
unsigned int vi : tri) {
199 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)
void gpsRefChanged(QGeoCoordinate newGpsRef, bool isRefSet)
Fact *buildingLevelHeight READ buildingLevelHeight CONSTANT Fact * buildingLevelHeight()