/* * © Copyright 2014 – Urheberrechtshinweis * Alle Rechte vorbehalten / All Rights Reserved * * Programmcode ist urheberrechtlich geschuetzt. * Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner. * Keine Verwendung ohne explizite Genehmigung. * (vgl. § 106 ff UrhG / § 97 UrhG) */ #ifndef FLOORPLAN_3D_FLOORPLANMESH_H #define FLOORPLAN_3D_FLOORPLANMESH_H #include "Obstacle3.h" #include "../../geo/BBox3.h" #include namespace Floorplan3D { /** * meshed version of the floorplan */ struct FloorplanMesh { std::vector elements; BBox3 getBBox() const { BBox3 bb; for (const Obstacle3D& o : elements) { for (const Triangle3& t : o.triangles) { bb.add(t.p1); bb.add(t.p2); bb.add(t.p3); } } return bb; } void operator -= (const Point3 p) { for (Obstacle3D& o : elements) { for (Triangle3& t : o.triangles) { t -= p; } } } /** export as OBJ file */ void exportOBJsimple(const std::string& file) { std::ofstream out(file.c_str()); out << toOBJsimple(); out.close(); } /** export as OBJ file */ void exportOBJcomplex(const std::string& file, const std::string& nameOnly) { std::ofstream outOBJ((file+".obj").c_str()); std::ofstream outMTL((file+".mtl").c_str()); OBJData data = toOBJ(nameOnly); outOBJ << data.obj; outMTL << data.mtl; outOBJ.close(); outMTL.close(); } /** export as PLY file */ void exportPLY(const std::string& file) { std::ofstream out(file.c_str()); out << toPLY(); out.close(); } /** DEBUG: convert to .obj file code for exporting */ std::string toOBJsimple() { int nVerts = 1; 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"; } } // write each obstacle for (const Obstacle3D& o : elements) { // write the 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; } struct OBJData { std::string obj; std::string mtl; }; /** DEBUG: convert to .obj file code for exporting */ OBJData toOBJ(const std::string name) { const BBox3 bb = getBBox(); const float ox = bb.getCenter().x; const float oy = bb.getCenter().y; bool swapYZ = true; int nVerts = 1; int nObjs = 0; OBJData res; // write material file for (size_t idx = 0; idx < mats.size(); ++idx) { const Material& mat = mats[idx]; res.mtl += "newmtl mat_" + mat.name + "\n"; res.mtl += "Ka 0.000 0.000 0.000 \n"; // ambient res.mtl += "Kd " + std::to_string(mat.r/255.0f) + " " + std::to_string(mat.g/255.0f) + " " + std::to_string(mat.b/255.0f) + "\n"; res.mtl += "Ks 0.000 0.000 0.000 \n"; res.mtl += "d " + std::to_string(mat.a/255.0f) + "\n"; // alpha res.mtl += "Tr " + std::to_string(1.0f-mat.a/255.0f) + "\n"; // inv-alpha res.mtl += "illum 2 \n"; res.mtl += "\n"; } // use material file res.obj += "mtllib " + name + ".mtl" + "\n"; // write each obstacle for (const Obstacle3D& o : elements) { // write the vertices for (const Triangle3& t : o.triangles) { if (!swapYZ) { res.obj += "v " + std::to_string(t.p1.x-ox) + " " + std::to_string(t.p1.y-oy) + " " + std::to_string(t.p1.z) + "\n"; res.obj += "v " + std::to_string(t.p2.x-ox) + " " + std::to_string(t.p2.y-oy) + " " + std::to_string(t.p2.z) + "\n"; res.obj += "v " + std::to_string(t.p3.x-ox) + " " + std::to_string(t.p3.y-oy) + " " + std::to_string(t.p3.z) + "\n"; } else { res.obj += "v " + std::to_string(t.p1.x-ox) + " " + std::to_string(t.p1.z) + " " + std::to_string(t.p1.y-oy) + "\n"; res.obj += "v " + std::to_string(t.p3.x-ox) + " " + std::to_string(t.p3.z) + " " + std::to_string(t.p3.y-oy) + "\n"; res.obj += "v " + std::to_string(t.p2.x-ox) + " " + std::to_string(t.p2.z) + " " + std::to_string(t.p2.y-oy) + "\n"; } } } // write each obstacle for (const Obstacle3D& o : elements) { // create a new group //res.obj += "g elem_" + std::to_string(++nObjs) + "\n"; // create a new object res.obj += "o elem_" + std::to_string(++nObjs) + "\n"; // group's material res.obj += "usemtl mat_" + getMaterial(o).name + "\n"; // write the group's faces for (size_t i = 0; i < o.triangles.size(); ++i) { res.obj += "f " + std::to_string(nVerts+0) + " " + std::to_string(nVerts+1) + " " + std::to_string(nVerts+2) + "\n"; nVerts += 3; } } // done return res; } /** convert to .ply file format */ std::string toPLY() const { std::stringstream res; res << "ply\n"; res << "format ascii 1.0\n"; int faces = 0; int vertices = 0; for (const Obstacle3D& obs : elements) { vertices += obs.triangles.size() * 3; faces += obs.triangles.size(); } res << "element material " << mats.size() << "\n"; res << "property uchar red\n"; res << "property uchar green\n"; res << "property uchar blue\n"; res << "property uchar alpha\n"; res << "element vertex " << vertices << "\n"; res << "property float x\n"; res << "property float y\n"; res << "property float z\n"; res << "property float nx\n"; res << "property float ny\n"; res << "property float nz\n"; res << "property uchar red\n"; res << "property uchar green\n"; res << "property uchar blue\n"; res << "property uchar alpha\n"; res << "property int material_index\n"; res << "element face " << faces << "\n"; res << "property list uchar int vertex_indices\n"; res << "end_header\n"; for (const Material& mat : mats) { res << mat.r << " " << mat.g << " " << mat.b << " " << mat.a << "\n"; } for (const Obstacle3D& obs : elements) { const int matIdx = getMaterialIdx(obs); const Material& mat = mats[matIdx]; for (const Triangle3& tria : obs.triangles) { const Point3 n = cross(tria.p2-tria.p1, tria.p3-tria.p1).normalized(); res << tria.p1.x << " " << tria.p1.y << " " << tria.p1.z << " " << n.x << " " << n.y << " " << n.z << " " << mat.r << " " << mat.g << " " << mat.b << " " << mat.a << " " << matIdx << "\n"; res << tria.p2.x << " " << tria.p2.y << " " << tria.p2.z << " " << n.x << " " << n.y << " " << n.z << " " << mat.r << " " << mat.g << " " << mat.b << " " << mat.a << " " << matIdx << "\n"; res << tria.p3.x << " " << tria.p3.y << " " << tria.p3.z << " " << n.x << " " << n.y << " " << n.z << " " << mat.r << " " << mat.g << " " << mat.b << " " << mat.a << " " << matIdx << "\n"; } } int vidx = 0; for (const Obstacle3D& obs : elements) { for (const Triangle3& tria : obs.triangles) { (void) tria; res << "3 " << (vidx+0) << " " << (vidx+1) << " " << (vidx+2) << "\n"; vidx += 3; } } // done return res.str(); } struct Material { int r, g, b, a; std::string name; Material(int r, int g, int b, int a) : r(r), g(g), b(b), a(a) {;} Material(int r, int g, int b, int a, const std::string& name) : r(r), g(g), b(b), a(a), name(name) {;} }; // // material // std::vector mats = { // Material(0,128,0,255), // ground outdoor // Material(64,64,64,255), // ground outdoor // Material(255,96,96,255), // stair // Material(128,128,128,255), // concrete // Material(64,128,255,64), // glass // Material(200,200,200,255), // default // }; // int getMaterial(const Obstacle3D& o) const { // if (o.type == Obstacle3D::Type::GROUND_OUTDOOR) {return 0;} // if (o.type == Obstacle3D::Type::GROUND_INDOOR) {return 1;} // if (o.type == Obstacle3D::Type::STAIR) {return 2;} // if (o.mat == Floorplan::Material::CONCRETE) {return 3;} // if (o.mat == Floorplan::Material::GLASS) {return 4;} // return 5; // } std::vector mats = { Material(255,0,0,255 , "error"), // error Material(0,128,0,255 , "ground_outdoor"), // ground outdoor Material(64,64,64,255 , "ground_indoor"), // ground outdoor Material(105,105,105,255, "stair"), // stair Material(220,220,220,255, "handrail"), // handrail Material(200,200,255,96 , "door_glass"), // door (glass) Material(140,140,140,255, "door_wood"), // door (wood) Material(135,135,135,255, "concrete"), // concrete Material(240,240,255,96 , "glass"), // glass Material(170,170,255,96 , "glass_metallized"), // glass (metallized) Material(170,120,60,255 , "wood"), // wood Material(200,200,200,255, "drywall"), // drywall Material(255,255,255,255, "metal"), // metal Material(255,255,255,255, "object"), // object Material(235,235,235,255, "dafult"), // default }; int getMaterialIdx(const Obstacle3D& o) const { if (o.type == Floorplan3D::Obstacle3D::Type::ERROR) {return 0;} if (o.type == Floorplan3D::Obstacle3D::Type::GROUND_OUTDOOR) {return 1;} if (o.type == Floorplan3D::Obstacle3D::Type::GROUND_INDOOR) {return 2;} if (o.type == Floorplan3D::Obstacle3D::Type::STAIR) {return 3;} if (o.type == Floorplan3D::Obstacle3D::Type::HANDRAIL) {return 4;} if (o.type == Floorplan3D::Obstacle3D::Type::OBJECT) {return 12;} if (o.type == Floorplan3D::Obstacle3D::Type::DOOR && o.mat == Floorplan::Material::GLASS) {return 5;} if (o.type == Floorplan3D::Obstacle3D::Type::DOOR) {return 6;} if (o.mat == Floorplan::Material::CONCRETE) {return 7;} if (o.mat == Floorplan::Material::GLASS) {return 8;} if (o.mat == Floorplan::Material::METALLIZED_GLAS) {return 9;} if (o.mat == Floorplan::Material::WOOD) {return 10;} if (o.mat == Floorplan::Material::DRYWALL) {return 11;} if (o.mat == Floorplan::Material::METAL) {return 12;} return 13; } const Material& getMaterial(const Obstacle3D& o) const { const int idx = getMaterialIdx(o); return mats[idx]; } // Color getColor(const Obstacle3D& o) const { // if (o.type == Obstacle3D::Type::GROUND_OUTDOOR) {return Color(0,128,0,255);} // if (o.type == Obstacle3D::Type::GROUND_INDOOR) {return Color(64,64,64,255);} // if (o.mat == Floorplan::Material::CONCRETE) {return Color(128,128,128,255);} // if (o.mat == Floorplan::Material::GLASS) {return Color(128,128,255,64);} // return Color(200,200,200,255); // } }; } #endif // FLOORPLAN_3D_FLOORPLANMESH_H