From 0bb1b707dee84a79f290953c8c749e31a8b5b936 Mon Sep 17 00:00:00 2001 From: frank Date: Mon, 5 Feb 2018 20:20:48 +0100 Subject: [PATCH] started working on 3D building stuff --- CMakeLists.txt | 4 +- grid/factory/v2/Importance.h | 3 +- main.cpp | 6 +- tests/geo/TestBVH3.cpp | 3 +- wifi/estimate/ray3/FloorplanMesh.h | 48 ++++++++++ wifi/estimate/ray3/ModelFactory.h | 136 +++++++++++++++-------------- wifi/estimate/ray3/Obstacle3.h | 19 +++- 7 files changed, 145 insertions(+), 74 deletions(-) create mode 100644 wifi/estimate/ray3/FloorplanMesh.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8536689..3557ca5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,8 +99,8 @@ ADD_EXECUTABLE( ${SOURCES} ) -SET(EXTRA_LIBS ${EXTRA_LIBS} nl-genl-3 nl-3) -INCLUDE_DIRECTORIES(/usr/include/libnl3/) +#SET(EXTRA_LIBS ${EXTRA_LIBS} nl-genl-3 nl-3) +#INCLUDE_DIRECTORIES(/usr/include/libnl3/) #SET(EXTRA_LIBS ${EXTRA_LIBS} iw) # needed external libraries diff --git a/grid/factory/v2/Importance.h b/grid/factory/v2/Importance.h index 0906fa2..8afd8c1 100644 --- a/grid/factory/v2/Importance.h +++ b/grid/factory/v2/Importance.h @@ -11,7 +11,8 @@ #include "../../../misc/KNNArray.h" #include "../../../math/MiniMat2.h" -#include "../../../math/Distributions.h" +#include "../../../math/distribution/Normal.h" +#include "../../../math/distribution/Triangle.h" diff --git a/main.cpp b/main.cpp index c7515fe..b86cc50 100755 --- a/main.cpp +++ b/main.cpp @@ -10,7 +10,7 @@ class Test : public GridPoint { #include "tests/Tests.h" -#include "sensors/radio/scan/WiFiScanLinux.h" +//#include "sensors/radio/scan/WiFiScanLinux.h" #include "sensors/radio/VAPGrouper.h" #include @@ -18,6 +18,7 @@ class Test : public GridPoint { #include #include +/* void wifi() { K::Gnuplot gp; @@ -80,6 +81,7 @@ void wifi() { } +*/ int main(int argc, char** argv) { @@ -109,7 +111,7 @@ int main(int argc, char** argv) { //::testing::GTEST_FLAG(filter) = "*Matrix4*"; //::testing::GTEST_FLAG(filter) = "*Sphere3*"; - ::testing::GTEST_FLAG(filter) = "NavMeshD*"; + ::testing::GTEST_FLAG(filter) = "FileReader*"; //::testing::GTEST_FLAG(filter) = "Timestamp*"; //::testing::GTEST_FLAG(filter) = "*RayTrace3*"; diff --git a/tests/geo/TestBVH3.cpp b/tests/geo/TestBVH3.cpp index 9d7196e..480667d 100644 --- a/tests/geo/TestBVH3.cpp +++ b/tests/geo/TestBVH3.cpp @@ -146,7 +146,8 @@ TEST(BVH, treeMap) { ModelFactory fac(map); fac.setExportCeilings(false); fac.setFloors({map->floors[3]}); - std::vector obs = fac.triangulize(); + FloorplanMesh mesh = fac.getMesh(); + std::vector obs = mesh.elements; BVH3Debug tree; diff --git a/wifi/estimate/ray3/FloorplanMesh.h b/wifi/estimate/ray3/FloorplanMesh.h new file mode 100644 index 0000000..d29f236 --- /dev/null +++ b/wifi/estimate/ray3/FloorplanMesh.h @@ -0,0 +1,48 @@ +#ifndef FLOORPLANMESH_H +#define FLOORPLANMESH_H + +#include "Obstacle3.h" + +/** + * meshed version of the floorplan + */ +struct FloorplanMesh { + + std::vector elements; + + /** DEBUG: convert to .obj file code for exporting */ + std::string toOBJ() { + + int nVerts = 1; + int nObjs = 0; + std::string res; + + // write each obstacle + for (const Obstacle3D& o : elements) { + + // write the vertices + for (const Triangle3& t : o.triangles) { + res += "v " + std::to_string(t.p1.x) + " " + std::to_string(t.p1.y) + " " + std::to_string(t.p1.z) + "\n"; + res += "v " + std::to_string(t.p2.x) + " " + std::to_string(t.p2.y) + " " + std::to_string(t.p2.z) + "\n"; + res += "v " + std::to_string(t.p3.x) + " " + std::to_string(t.p3.y) + " " + std::to_string(t.p3.z) + "\n"; + } + + // create a new group + res += "g elem_" + std::to_string(++nObjs) + "\n"; + + // write the group's faces + for (size_t i = 0; i < o.triangles.size(); ++i) { + res += "f " + std::to_string(nVerts+0) + " " + std::to_string(nVerts+1) + " " + std::to_string(nVerts+2) + "\n"; + nVerts += 3; + } + + } + + // done + return res; + + } + +}; + +#endif // FLOORPLANMESH_H diff --git a/wifi/estimate/ray3/ModelFactory.h b/wifi/estimate/ray3/ModelFactory.h index 11a6390..c31a7a0 100644 --- a/wifi/estimate/ray3/ModelFactory.h +++ b/wifi/estimate/ray3/ModelFactory.h @@ -6,6 +6,7 @@ #include "ModelFactoryHelper.h" #include "Obstacle3.h" #include "Cube.h" +#include "FloorplanMesh.h" /** * convert an indoor map into a 3D model based on triangles @@ -38,6 +39,18 @@ public: this->exportFloors = floors; } + /** convert floorplan to mesh */ + FloorplanMesh getMesh() { + + FloorplanMesh mesh; + mesh.elements = triangulize(); + return mesh; + + } + +private: + + /** get all triangles grouped by obstacle */ std::vector triangulize() { @@ -50,7 +63,10 @@ public: for (const Floorplan::Floor* f : floors) { // triangulize the floor itself (floor/ceiling) - if (exportCeilings) {res.push_back(getTriangles(f));} + if (exportCeilings) { + std::vector tmp = getFloor(f); + res.insert(res.end(), tmp.begin(), tmp.end()); + } // process each obstacle within the floor for (const Floorplan::FloorObstacle* fo : f->obstacles) { @@ -74,87 +90,75 @@ public: } - /** DEBUG: convert to .obj file code for exporting */ - std::string toOBJ() { - const std::vector obs = triangulize(); - - int nVerts = 1; - int nObjs = 0; - std::string res; - - // write each obstacle - for (const Obstacle3D& o : obs) { - - // write the vertices - for (const Triangle3& t : o.triangles) { - res += "v " + std::to_string(t.p1.x) + " " + std::to_string(t.p1.y) + " " + std::to_string(t.p1.z) + "\n"; - res += "v " + std::to_string(t.p2.x) + " " + std::to_string(t.p2.y) + " " + std::to_string(t.p2.z) + "\n"; - res += "v " + std::to_string(t.p3.x) + " " + std::to_string(t.p3.y) + " " + std::to_string(t.p3.z) + "\n"; - } - - // create a new group - res += "g elem_" + std::to_string(++nObjs) + "\n"; - - // write the group's faces - for (size_t i = 0; i < o.triangles.size(); ++i) { - res += "f " + std::to_string(nVerts+0) + " " + std::to_string(nVerts+1) + " " + std::to_string(nVerts+2) + "\n"; - nVerts += 3; - } - - } - - // done - return res; - - } private: /** convert a floor (floor/ceiling) into triangles */ - Obstacle3D getTriangles(const Floorplan::Floor* f) { + std::vector getFloor(const Floorplan::Floor* f) { // floor uses an outline based on "add" and "remove" areas // we need to create the apropriate triangles to model the polygon // including all holes (remove-areas) - // TODO: variable type? - Obstacle3D res(Floorplan::Material::CONCRETE); - - Polygon poly; - - // append all "add" and "remove" areas + // process all "add" regions by type + // [this allows for overlaps of the same type] + std::unordered_map types; for (Floorplan::FloorOutlinePolygon* fop : f->outline) { - switch (fop->method) { - case Floorplan::OutlineMethod::ADD: poly.add(fop->poly); break; - case Floorplan::OutlineMethod::REMOVE: poly.remove(fop->poly); break; - default: throw 1; + if (fop->method == Floorplan::OutlineMethod::ADD) { + if (fop->outdoor) { + types["outdoor"].add(fop->poly); + } else { + types["indoor"].add(fop->poly); + } } } - // convert them into polygons - std::vector> polys = poly.get(f->getStartingZ()); - - // convert polygons (GL_TRIANGLE_STRIP) to triangles - for (const std::vector& pts : polys) { - for (int i = 0; i < (int)pts.size() - 2; ++i) { - - // floor must be double-sided for reflection to work with the correct normals - Triangle3 tria1 (pts[i+0], pts[i+1], pts[i+2]); - Triangle3 tria2 (pts[i+2], pts[i+1], pts[i+0]); - - // ensure the triangle with the normal pointing downwards (towards bulding's cellar) - // is below the triangle that points upwards (towards the sky) - if (tria1.getNormal().z < 0) {tria1 = tria1 - Point3(0,0,0.02);} - if (tria2.getNormal().z < 0) {tria2 = tria2 - Point3(0,0,0.02);} - - // add both - res.triangles.push_back(tria1); - res.triangles.push_back(tria2); - + // remove the "remove" regions from EVERY "add" region added within the previous step + for (Floorplan::FloorOutlinePolygon* fop : f->outline) { + if (fop->method == Floorplan::OutlineMethod::REMOVE) { + for (auto& it : types) { + it.second.remove(fop->poly); + } } } + std::vector res; + + // create an obstacle for each type (indoor, outdoor) + for (auto& it : types) { + + // TODO: variable type? + Obstacle3D::Type type = (it.first == "indoor") ? (Obstacle3D::Type::GROUND_INDOOR) : (Obstacle3D::Type::GROUND_OUTDOOR); + Obstacle3D obs(type, Floorplan::Material::CONCRETE); + + // convert them into polygons + std::vector> polys = it.second.get(f->getStartingZ()); + + // convert polygons (GL_TRIANGLE_STRIP) to triangles + for (const std::vector& pts : polys) { + for (int i = 0; i < (int)pts.size() - 2; ++i) { + + // floor must be double-sided for reflection to work with the correct normals + Triangle3 tria1 (pts[i+0], pts[i+1], pts[i+2]); + Triangle3 tria2 (pts[i+2], pts[i+1], pts[i+0]); + + // ensure the triangle with the normal pointing downwards (towards bulding's cellar) + // is below the triangle that points upwards (towards the sky) + if (tria1.getNormal().z < 0) {tria1 = tria1 - Point3(0,0,0.02);} + if (tria2.getNormal().z < 0) {tria2 = tria2 - Point3(0,0,0.02);} + + // add both + obs.triangles.push_back(tria1); + obs.triangles.push_back(tria2); + + } + } + + res.push_back(obs); + + } + return res; } @@ -200,7 +204,7 @@ private: Cube cube(pos, size, rot); // done - Obstacle3D res(fol->material); + Obstacle3D res(Obstacle3D::Type::WALL, fol->material); res.triangles = cube.getTriangles(); return res; diff --git a/wifi/estimate/ray3/Obstacle3.h b/wifi/estimate/ray3/Obstacle3.h index 115a88b..ef58e1f 100644 --- a/wifi/estimate/ray3/Obstacle3.h +++ b/wifi/estimate/ray3/Obstacle3.h @@ -7,16 +7,31 @@ #include "../../../floorplan/v2/Floorplan.h" +/** + * 3D obstacle + * based on multiple triangles + * has a material and a type + */ struct Obstacle3D { + enum class Type { + UNKNOWN, + GROUND_INDOOR, + GROUND_OUTDOOR, + STAIR, + DOOR, + WALL, + }; + + Type type; Floorplan::Material mat; std::vector triangles; /** empty ctor */ - Obstacle3D() : mat() {;} + Obstacle3D() : type(Type::UNKNOWN), mat() {;} /** ctor */ - Obstacle3D(Floorplan::Material mat) : mat(mat) {;} + Obstacle3D(Type type, Floorplan::Material mat) : type(type), mat(mat) {;} };