This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Indoor/wifi/estimate/ray3/ModelFactory.h
k-a-z-u c19d18a3a6 modified lib GPC for header only
worked on 3d traytracing
2017-09-06 17:04:19 +02:00

214 lines
5.4 KiB
C++

#ifndef MODELFACTORY_H
#define MODELFACTORY_H
#include "../../../floorplan/v2/Floorplan.h"
#include "../../../geo/Triangle3.h"
#include "ModelFactoryHelper.h"
#include "Obstacle3.h"
#include "Cube.h"
/**
* convert an indoor map into a 3D model based on triangles
*/
class ModelFactory {
private:
bool exportCeilings = true;
bool exportObstacles = true;
bool exportWallTops = false;
std::vector<Floorplan::Floor*> exportFloors;
const Floorplan::IndoorMap* map;
public:
/** ctor */
ModelFactory(const Floorplan::IndoorMap* map) : map(map) {
}
void setExportCeilings(bool exp) {
this->exportCeilings = exp;
}
/** limit to-be-exported floors */
void setFloors(const std::vector<Floorplan::Floor*> floors) {
this->exportFloors = floors;
}
/** get all triangles grouped by obstacle */
std::vector<Obstacle3D> triangulize() {
std::vector<Obstacle3D> res;
// get the to-be-exported floors (either "all" or "user defined")
const std::vector<Floorplan::Floor*>& floors = (exportFloors.empty()) ? (map->floors) : (exportFloors);
// process each floor
for (const Floorplan::Floor* f : floors) {
// triangulize the floor itself (floor/ceiling)
if (exportCeilings) {res.push_back(getTriangles(f));}
// process each obstacle within the floor
for (const Floorplan::FloorObstacle* fo : f->obstacles) {
// handle line obstacles
const Floorplan::FloorObstacleLine* fol = dynamic_cast<const Floorplan::FloorObstacleLine*>(fo);
if (fol) {
if (fol->type == Floorplan::ObstacleType::HANDRAIL) {continue;}
if (exportObstacles) {res.push_back(getTriangles(f, fol));}
}
}
// TODO: remove
//break;
}
return res;
}
/** DEBUG: convert to .obj file code for exporting */
std::string toOBJ() {
const std::vector<Obstacle3D> 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) {
// 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
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;
}
}
// convert them into polygons
std::vector<std::vector<Point3>> polys = poly.get(f->getStartingZ());
// convert polygons (GL_TRIANGLE_STRIP) to triangles
for (const std::vector<Point3>& 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);
}
}
return res;
}
/** convert a line obstacle to 3D triangles */
Obstacle3D getTriangles(const Floorplan::Floor* f, const Floorplan::FloorObstacleLine* fol) {
/*
Obstacle3D res(fol->material);
Point3 p1(fol->from.x, fol->from.y, f->getStartingZ());
Point3 p2(fol->to.x, fol->to.y, f->getStartingZ());
Point3 p3(fol->to.x, fol->to.y, f->getEndingZ());
Point3 p4(fol->from.x, fol->from.y, f->getEndingZ());
Triangle3 t1(p1,p2,p3);
Triangle3 t2(p1,p3,p4);
res.triangles.push_back(t1);
res.triangles.push_back(t2);
*/
const float thickness_m = fol->thickness_m;
const Point2 from = fol->from;
const Point2 to = fol->to;
const Point2 cen2 = (from+to)/2;
const float rad = std::atan2(to.y - from.y, to.x - from.x);
const float deg = rad * 180 / M_PI;
// cube's destination center
const Point3 pos(cen2.x, cen2.y, f->atHeight + f->height/2);
// div by 2.01 to prevent overlapps and z-fi
const float sx = from.getDistance(to) / 2.01f;
const float sy = thickness_m / 2.01f;
const float sz = f->height / 2.01f; // prevent overlaps
const Point3 size(sx, sy, sz);
const Point3 rot(0,0,deg);
// build
Cube cube(pos, size, rot);
// done
Obstacle3D res(fol->material);
res.triangles = cube.getTriangles();
return res;
}
};
#endif // MODELFACTORY_H