357 lines
11 KiB
C++
357 lines
11 KiB
C++
/*
|
||
* © 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 <fstream>
|
||
|
||
namespace Floorplan3D {
|
||
|
||
/**
|
||
* meshed version of the floorplan
|
||
*/
|
||
struct FloorplanMesh {
|
||
|
||
std::vector<Obstacle3D> 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<Material> 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<Material> 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
|