https://github.com/tudelft3d/lod2plus
Tip revision: 9df55d1dbb1163a6861f5adf7b4bc8d88b54419c authored by Ken Arroyo Ohori on 23 September 2015, 07:04:34 UTC
Uppdate ref
Uppdate ref
Tip revision: 9df55d1
Building.cpp
#include "Building.h"
#include "globals.h"
#include "polybuilder.h"
class polybuilder;
struct Plane_equation;
/*########################################################
##########################################################
The following functions are geometric
##########################################################
########################################################*/
vector<Point_3> subtractMin (vector<Point_3> points) {
double minX = 100000000000000,
minY = 100000000000000,
minZ = 100000000000000;
vector<Point_3> newPoints;
for (int i = 0; i != points.size(); ++i ) {
double x = CGAL::to_double(points[i].x()),
y = CGAL::to_double(points[i].y()),
z = CGAL::to_double(points[i].z());
if (x < minX) minX = x;
if (y < minY) minY = y;
if (z < minZ) minZ = z;
}
for (int i = 0; i != points.size(); ++i ) {
double x = CGAL::to_double(points[i].x()),
y = CGAL::to_double(points[i].y()),
z = CGAL::to_double(points[i].z());
x -= minX;
y -= minY;
z -= minZ;
newPoints.push_back(Point_3(x,y,z));
}
return newPoints;
}
void determineAngles (double & theta, double & phi, vector<Point_3> points, bool deg = false) {
double const pi = 3.14159265359;
points = subtractMin(points);
Triangle_3 tri(points[0],points[1],points[2]);
Transformation scale (CGAL::SCALING, 4);
tri.transform(scale);
Vector_3 normal = tri.supporting_plane().orthogonal_vector();
double x = CGAL::to_double(normal.x()), y = CGAL::to_double(normal.y()), z = CGAL::to_double(normal.z());
double r = sqrt(CGAL::to_double(normal.squared_length()));
theta = asin(z/r);
if (theta != theta) {
if (z/r < -1) theta = -pi/2;
else if (z/r > 1) theta = pi/2;
else theta = 0;
}
if (abs(x) > 1e-6 && abs(y) > 1e-6) {
phi = atan2(x,y);
} else phi = 0;
if (deg) {
theta *= 180/pi;
phi *= 180/pi;
}
}
double Building::getMinHeight() {
double minZ = 1000000;
Polyhedron::Vertex_iterator vit;
for (vit = polyBuilding.vertices_begin(); vit != polyBuilding.vertices_end(); vit++) {
double z = CGAL::to_double(vit->point().z());
if (z < minZ) minZ = z;
}
return minZ;
}
double Building::getMaxHeight() {
double maxZ = -1000000;
Polyhedron::Vertex_iterator vit;
for (vit = polyBuilding.vertices_begin(); vit != polyBuilding.vertices_end(); vit++) {
double z = CGAL::to_double(vit->point().z());
if (z > maxZ) maxZ = z;
}
return maxZ;
}
double Building::getHeight() {
/*Gets the height of the building relative to zero*/
double minZ = getMinHeight(), maxZ = getMaxHeight();
return maxZ-minZ;
}
vector<Point_2> Building::getConvexHull2D() {
/* Projects all the points of the building onto the x-y plane
and calculates the convex hull of that*/
int nVert = polyBuilding.size_of_vertices();
vector<Point_2> points2;
vector<Point_2> hull;
Polyhedron::Vertex_iterator vit;
for (vit = polyBuilding.vertices_begin(); vit != polyBuilding.vertices_end(); ++vit) {
Point_3 pnt = vit->point();
points2.push_back(Point_2(pnt.x(), pnt.y()));
}
CGAL::convex_hull_2(points2.begin(),points2.end(),back_inserter(hull));
return hull;
}
Polyhedron Building::createSplitPolyhedron (vector<Point_2> points, double minHeight, double maxHeight) {
/* Creates a polyhedron from a convex hull and a minimum and a maximum height*/
Polyhedron poly;
vector<Point_3> points3;
for (int i = 0; i != points.size(); ++i) {
points3.push_back(Point_3(points[i].x(),points[i].y(),minHeight));
points3.push_back(Point_3(points[i].x(),points[i].y(),maxHeight));
}
CGAL::convex_hull_3(points3.begin(),points3.end(),poly);
return poly;
}
void Building::createUnitBox () {
stringstream robot;
robot << "OFF\n8 6 0\n-1 1 1\n-1 -1 1\n1 1 1\n1 -1 1\n-1 1 -1\n-1 -1 -1\n" <<
"1 1 -1\n1 -1 -1\n4 2 3 1 0\n4 4 6 2 0\n4 1 5 4 0\n4 6 4 5 7\n4 3 2 6 7\n4 5 1 3 7\n";
//ifstream robot("D:\\Dropbox\\Data\\robot.off");
CGAL::OFF_to_nef_3(robot,nefBox);
//robot.close();
}
Nef_polyhedron Building::makeRobot (string polyType, vector<Point_3> points) {
Nef_polyhedron box = nefBox;
double length, theta, phi;
if (polyType == "CeilingSurface") length = ceilingThickness;
else if (polyType == "RoofSurface") length = roofThickness;
else if (polyType == "WallSurface") length = wallThickness;
else if (polyType == "InnerWallSurface") length = sharedWallThickness;
else if (polyType == "FloorSurface") length = floorThickness;
else if (polyType == "GroundSurface") length = 0.01;
determineAngles(theta, phi, points);
theta = - theta; //Pitch downwards is defined as positive rotation
Transformation scale(CGAL::SCALING, length);
Transformation rot_z (cos(phi),sin(phi),0,
-sin(phi),cos(phi),0,
0,0,1);
Transformation rot_x (1, 0, 0,
0, cos(theta), sin(theta),
0, -sin(theta), cos(theta));
box.transform(scale);
box.transform(rot_x);
box.transform(rot_z);
return box;
}
string Building::determinePolyType (vector<Point_3> points, bool outer = false, int floor=0) {
string polyType;
double theta,phi;
determineAngles(theta,phi,points, true);
if (!outer) { //Final classification for CityGML output
if (theta < -70) {
polyType = "FloorSurface";
} else if ( abs(theta) < 5) {
polyType = "InteriorWallSurface";
} else polyType = "CeilingSurface";
} else { //First classification for right offset
if (theta < -70) {
if (floor == 0) polyType = "GroundSurface";
else polyType = "FloorSurface";
} else if ( abs(theta) < 5) {
polyType = "WallSurface";
} else if (theta > 85 && theta < 95) {
if (floor == highFloor) polyType = "RoofSurface";
else polyType = "CeilingSurface";
}
else polyType = "RoofSurface";
}
if (polyType == "WallSurface") { //Check whether a wall is a shared wall
if (sharedWalls.size()>0) {
vector<Line_2>::iterator it;
vector<Point_3>::iterator pit;
for (it = sharedWalls.begin(); it != sharedWalls.end(); ++it){
Line_2 line = *it;
int pointsTrue = 0;
for (pit = points.begin(); pit != points.end(); ++pit) {
double px = CGAL::to_double(pit->x()),
py = CGAL::to_double(pit->y());
Point_2 P(px,py);
if (CGAL::squared_distance(line,P)<0.01) {
++pointsTrue;
}
}
if (pointsTrue == 3) {
polyType = "InnerWallSurface";
break;
}
}
}
}
return polyType;
}
string determineExtPolyType (vector<Point_3> points) {
string polyType;
double theta,phi;
determineAngles(theta,phi,points, true);
if (theta < -70) polyType = "GroundSurface";
else if ( abs(theta) < 5) polyType = "WallSurface";
else polyType = "RoofSurface";
return polyType;
}
void Building::exteriorToFinalPolygons () {
string polyType;
Polyhedron::Facet_iterator fit;
Polyhedron::Facet::Halfedge_around_facet_circulator itHDS;
int j = 0;
for (fit = polyBuilding.facets_begin(); fit != polyBuilding.facets_end(); ++fit) {
Vector_3 normal = fit->plane().orthogonal_vector();
vector<Point_3> tempPoints;
itHDS = fit->facet_begin();
do {
typedef Polyhedron::Vertex::Point_3 vertex;
vertex v = itHDS->vertex()->point();
tempPoints.push_back(v);
} while (++itHDS != fit->facet_begin());
polyType = determineExtPolyType(tempPoints);
finalPolygons["exterior"][0][polyType][j] = tempPoints;
++j;
}
}
void Building::addPolyType (int i, bool finalStorey=false) {
string polyType;
Polyhedron::Facet_iterator fit;
Polyhedron::Facet::Halfedge_around_facet_circulator itHDS;
int j = 0;
for (fit = storey.facets_begin(); fit != storey.facets_end(); ++fit) {
Vector_3 normal = fit->plane().orthogonal_vector();
vector<Point_3> tempPoints;
itHDS = fit->facet_begin();
do {
typedef Polyhedron::Vertex::Point_3 vertex;
vertex v = itHDS->vertex()->point();
tempPoints.push_back(v);
} while (++itHDS != fit->facet_begin());
polyType = determinePolyType(tempPoints);
finalPolygons["interior"][i][polyType][j] = tempPoints;
++j;
}
}
void Building::setThickness(double wall,double sharedWall,double floorCeiling) {
wallThickness = wall/100.00;
sharedWallThickness = sharedWall/100.00;
ceilingThickness = floorCeiling/2.00;
floorThickness = floorCeiling/2.00;
roofThickness = 0.30;
}
void Building::removeExtrudedFacets (Nef_polyhedron& Nef_storey, int floor) {
Polyhedron::Facet::Halfedge_around_facet_circulator itHDS;
Polyhedron::Facet_iterator fit;
//std::transform( storey.facets_begin(), storey.facets_end(), storey.planes_begin(), Plane_equation());
for (fit = storey.facets_begin(); fit != storey.facets_end(); ++fit) {
itHDS = fit->facet_begin();
//Vector_3 normal = fit->plane().orthogonal_vector();
vector<Point_3> tempPoints;
do {
typedef Polyhedron::Vertex::Point_3 vertex;
vertex v = itHDS->vertex()->point();
tempPoints.push_back(v);
} while (++itHDS != fit->facet_begin());
if (!isDegen(tempPoints,1e-2)){ // Check degeneracy, if degenerate continue with new face) {
string polyType = determinePolyType(tempPoints,true,floor);
Nef_polyhedron face(tempPoints.begin(),tempPoints.end());
Nef_polyhedron robot = makeRobot(polyType,tempPoints);
Nef_polyhedron diff = CGAL::minkowski_sum_3(robot,face);
//createConvexHullNef(diff);
Nef_storey -= diff;
}
}
}
void Building::determineAreaNetHeight(int i){
Nef_polyhedron Nef_storey(storey);
//writeOffFile(Nef_storey,"D:\\Dropbox\\Data\\Nef_storey.off");
map<int,vector<Point_3>> floorPolygons = finalPolygons["interior"][i]["FloorSurface"];
map<int,vector<Point_3>>::iterator fit;
for (fit = floorPolygons.begin(); fit != floorPolygons.end(); ++fit){
vector<Point_3> pointsVector = fit->second;
vector<Point_3> tempPoints;
vector<Point_3>::iterator vit;
tempPoints.clear();
for (vit = pointsVector.begin(); vit != pointsVector.end(); ++ vit) {
double x = CGAL::to_double(vit->x()), y = CGAL::to_double(vit->y()), z = CGAL::to_double(vit->z());
double newZ = z + 1.5;
tempPoints.push_back(*vit);
tempPoints.push_back(Point_3(x,y,newZ));
}
Polyhedron polyHull;
CGAL::convex_hull_3(tempPoints.begin(),tempPoints.end(),polyHull);
Nef_polyhedron nefHull (polyHull);
//writeOffFile(nefHull,"D:\\Dropbox\\Data\\extrtriangle.off");
Nef_polyhedron diff = nefHull - Nef_storey;
vector<Nef_polyhedron> diffs = splitNefs(diff);
vector<Nef_polyhedron>::iterator vnit;
for (vnit = diffs.begin(); vnit != diffs.end(); ++ vnit) {
if (vnit->is_simple()){
Polyhedron polyDiff;
vnit->convert_to_polyhedron(polyDiff);
Polyhedron::Facet::Halfedge_around_facet_circulator itHDS;
Polyhedron::Facet_iterator pit;
vector<Point_3> trianglePoints;
for (pit = polyDiff.facets_begin(); pit != polyDiff.facets_end(); ++pit) {
trianglePoints.clear();
itHDS = pit->facet_begin();
do {
typedef Polyhedron::Vertex::Point_3 vertex;
vertex v = itHDS->vertex()->point();
trianglePoints.push_back(v);
} while (++itHDS != pit->facet_begin());
Point_2 p1(trianglePoints[0].x(),trianglePoints[0].y());
Point_2 p2(trianglePoints[1].x(),trianglePoints[1].y());
Point_2 p3(trianglePoints[2].x(),trianglePoints[2].y());
Triangle_2 tempTri(p1,p2,p3);
if (! tempTri.is_degenerate()) {
double tArea = CGAL::to_double(tempTri.area());
//cout << tArea << endl;
netHeightArea += abs(tArea)/2.0;
}
}
}
}
}
/*if (Nef_storey.is_simple()) {
Nef_storey.convert_to_polyhedron(storey);
std::transform( storey.facets_begin(), storey.facets_end(), storey.planes_begin(),Plane_equation());
Nef_storey.clear();
}*/
//cout << endl << endl << netHeightArea << endl << endl;
}
vector<double> Building::getMarkedHeights() {
vector<double> markedHeights;
double maxHeight = getMaxHeight(), minRoofHeight= 10000000;
map<int,vector<Point_3>> roofPolygons = finalPolygons["exterior"][0]["RoofSurface"];
map<int,vector<Point_3>>::iterator itRP;
for (itRP = roofPolygons.begin(); itRP != roofPolygons.end(); ++itRP) {
vector<Point_3> tempPoints = itRP->second;
vector<Point_3>::iterator pointIT;
Point_3 pnt;
vector<Point_3> tempPlanePoints;
tempPlanePoints.clear();
double tempMinRoofHeight = 10000;
for (pointIT = tempPoints.begin(); pointIT != tempPoints.end(); ++pointIT) {
pnt = *pointIT;
tempPlanePoints.push_back(pnt);
if (CGAL::to_double(pnt.z()) < tempMinRoofHeight) tempMinRoofHeight = CGAL::to_double(pnt.z());
}
vector<Point_3> tempPlane (tempPlanePoints.begin(), tempPlanePoints.begin()+3);
double theta, phi;
determineAngles(theta, phi, tempPlane,true);
if ((abs(theta)/90.0) > 0.90 && (abs(theta)/90.0) < 1.10) {
if ((abs(tempMinRoofHeight/maxHeight)*100) < 90 ) {
markedHeights.push_back(tempMinRoofHeight);
}
}
else if (tempMinRoofHeight < minRoofHeight) minRoofHeight = tempMinRoofHeight;
}
markedHeights.push_back(minRoofHeight);
return markedHeights;
}
vector<double> Building::setSplitHeights () {
double levels = storeys;
double height = getHeight()-roofThickness;
double minHeight = getMinHeight();
double maxHeight = getMaxHeight();
vector<double> storeyHeights;
for (int i = 0; i != storeys; ++i) {
double lower = i, upper = i+1;
double lowHeight = lower/levels*height+minHeight, highHeight = upper/levels*height + minHeight;
storeyHeights.push_back(lowHeight);
if (i == (storeys - 1)) storeyHeights.push_back(maxHeight);
}
vector<double> markedHeights = getMarkedHeights();
vector<double>::iterator vdIT, vdIT2, vdIT3;
double lastHeight = 0;
int nrOfStorToChange = 0;
int counter = 0;
for (vdIT = storeyHeights.begin(); vdIT != storeyHeights.end()-1; ++vdIT) {
for (vdIT2 = markedHeights.begin(); vdIT2 != markedHeights.end(); ++ vdIT2){
if ((*vdIT - *vdIT2)<0.5 && (*vdIT - *vdIT2)>-0.5) {
*vdIT = *vdIT2;
double curHeight = *vdIT;
for (vdIT3 = storeyHeights.begin(); vdIT3!= vdIT+1; ++vdIT3){
if (*vdIT3 > (lastHeight+0.05) && *vdIT3 < (curHeight-0.05)) {
++nrOfStorToChange;
}
}
int k = 0;
double newLowStoreyHeight = (curHeight - lastHeight)/ static_cast<double>(nrOfStorToChange+1);
double newHighStoreyHeight = (maxHeight - curHeight - roofThickness)/ static_cast<double>(storeys-counter);
for (vdIT3 = storeyHeights.begin(); vdIT3!= storeyHeights.end(); ++vdIT3){
if (*vdIT3 > (lastHeight+0.05) && *vdIT3 < (curHeight-0.05)) {
*vdIT3 = lastHeight + static_cast<double>(k)*newLowStoreyHeight;
} else if (*vdIT3 > (curHeight+0.05) && *vdIT3 < (height - 0.05)) {
*vdIT3 = curHeight + static_cast<double>(k-counter)*newHighStoreyHeight;
}
++k;
}
lastHeight = curHeight;
}
}
++counter;
}
return storeyHeights;
}
void Building::createLoD2Plus() {
createUnitBox (); // Create robot box of size 2
netHeightArea = 0;
vector<Nef_polyhedron> firstNefs, secondNefs;
vector<Nef_polyhedron>::iterator nefIt1, nefIt2;
vector<double> storeyHeights = setSplitHeights();
vector<Point_2> hull = getConvexHull2D();
vector<double>::iterator vdIT;
int i = 0, j = 0;
for (vdIT = storeyHeights.begin(); vdIT!= storeyHeights.end()-1;++vdIT) {
double lowHeight = *vdIT, highHeight = *(vdIT+1);
Polyhedron tempPoly = createSplitPolyhedron(hull,lowHeight,highHeight);
Nef_polyhedron tempNef(tempPoly);
Nef_polyhedron Nef_storeys = Nef_building*tempNef; //Intersect complete building with storey convex hull
firstNefs = splitNefs(Nef_storeys); //Intersection may produce separated volumes, handle separately
for (nefIt1 = firstNefs.begin(); nefIt1 != firstNefs.end(); ++ nefIt1) {
storey.clear();
nefIt1->regularization().convert_to_polyhedron(storey);
storey.keep_largest_connected_components(1);
int floor = lowFloor+i;
removeExtrudedFacets((*nefIt1),floor);
secondNefs = splitNefs(*nefIt1); //Erosion may produce separated volumes, handle separately
for (nefIt2 = secondNefs.begin(); nefIt2 != secondNefs.end(); ++ nefIt2) {
storey.clear();
nefIt2->regularization().convert_to_polyhedron(storey);
storey.keep_largest_connected_components(1);
//fix_degenerate(storey);
addPolyType(j,true);
determineAreaNetHeight(j);
++j;
}
}
cout << "."; ++i;
}
}
void Building::calcArea() {
area = 0;
map<int,map<string,map<int,vector<Point_3>>>> interiorPolygons = finalPolygons["interior"];
map<int,map<string,map<int,vector<Point_3>>>>::iterator itShells;
map<string,map<int,vector<Point_3>>>::iterator itPolyType;
map<int,vector<Point_3>>::iterator itPolyNR;
for (itShells = interiorPolygons.begin(); itShells != interiorPolygons.end(); ++itShells) {
map<string,map<int,vector<Point_3>>> shells = itShells->second;
for (itPolyType = shells.begin(); itPolyType != shells.end(); ++itPolyType){
string type = itPolyType -> first;
map<int,vector<Point_3>> polyTypes = itPolyType->second;
if (type == "FloorSurface") {
for (itPolyNR = polyTypes.begin(); itPolyNR != polyTypes.end(); ++ itPolyNR) {
vector<Point_3> points = itPolyNR->second;
Triangle_3 t(points[0],points[1],points[2]);
if (!t.is_degenerate()) {
double tarea = sqrt(CGAL::to_double(t.squared_area()));
if (tarea<1000) {
area += tarea;
}
}
}
}
}
}
area-=netHeightArea;
}
//void Building::calcGrossVolume() {
// Nef_building.regularization();
// if(Nef_building.is_simple()) {
// try {
// volume = 0;
// Polyhedron building;
// Nef_building.convert_to_polyhedron(building);
// Point_3 inf(-1000, -1000, -1000);
// Polyhedron::Facet::Halfedge_around_facet_circulator itHDS;
// Polyhedron::Facet_iterator fit;
// for (fit = building.facets_begin(); fit != building.facets_end(); ++fit) {
// itHDS = fit->facet_begin();
// vector<Point_3> tempPoints;
// do {
// typedef Polyhedron::Vertex::Point_3 vertex;
// vertex v = itHDS->vertex()->point();
// tempPoints.push_back(v);
// } while (++itHDS != fit->facet_begin());
// CGAL::Tetrahedron_3<Kernel> t(tempPoints[0],tempPoints[1],tempPoints[2],inf);
// if (!t.is_degenerate()) {
// double tvolume = -CGAL::to_double(t.volume());
// volume += tvolume;
// }
// }
// } catch (...) {
// volume = 9999;
// }
// } else volume = 9999;
//}
/*########################################################
##########################################################
The following functions contain methods to write buildings
to CityGML!
##########################################################
########################################################*/
void Building::writeBuildingHeader(ofstream& output){
tabs = 0;
output << stringIndents(1) << "<cityObjectMember>\n";
output << stringIndents(1) << "<bldg:Building gml:id=\"BAG" << bagID << "\">\n";
output << stringIndents(1) << "<gml:name>" << bagID << "</gml:name>\n";
output << stringIndents(0) << "<gen:doubleAttribute name=\"floorArea\" xmlns:gen=\"http://www.opengis.net/citygml/generics/1.0\">\n\t\t\t\t<gen:value>"<< static_cast<int>(area) << "</gen:value>\n\t\t\t</gen:doubleAttribute>\n";
output << stringIndents(0) << "<gen:doubleAttribute name=\"BAG use Area\" xmlns:gen=\"http://www.opengis.net/citygml/generics/1.0\">\n\t\t\t\t<gen:value>"<< bagUseArea << "</gen:value>\n\t\t\t</gen:doubleAttribute>\n";
//output << stringIndents(0) << "<gen:doubleAttribute name=\"Gross Building Volume\" xmlns:gen=\"http://www.opengis.net/citygml/generics/1.0\">\n\t\t\t\t<gen:value>"<< static_cast<int>(volume) << "</gen:value>\n\t\t\t</gen:doubleAttribute>\n";
output << stringIndents(0) << "<gen:doubleAttribute name=\"Net height area\" xmlns:gen=\"http://www.opengis.net/citygml/generics/1.0\">\n\t\t\t\t<gen:value>"<< static_cast<int>(netHeightArea) << "</gen:value>\n\t\t\t</gen:doubleAttribute>\n";
output << stringIndents(0) << "<gml:MultiSolid>\n";
}
void Building::writeGeometry(ofstream& output){
itBuildingPolys itBP;
map<string,int> counter;
counter["RoofSurface"] = 0;
counter["WallSurface"] = 0;
counter["CeilingSurface"] = 0;
counter["InteriorWallSurface"] = 0;
counter["FloorSurface"] = 0;
counter["GroundSurface"] = 0;
map<string,map<int,map<string,map<int,vector<Point_3>>>>>::iterator itPolys;
++tabs;
for (itPolys = finalPolygons.begin(); itPolys != finalPolygons.end(); ++ itPolys) { // interior / exterior
string extint = itPolys->first;
map<int,map<string,map<int,vector<Point_3>>>> extintPolys = itPolys->second;
map<int,map<string,map<int,vector<Point_3>>>>::iterator itEIP;
for (itEIP = extintPolys.begin(); itEIP != extintPolys.end(); ++itEIP) { // shell number
int shellNR = itEIP->first;
map<string,map<int,vector<Point_3>>> bldng = itEIP->second;
map<string,map<int,vector<Point_3>>>::iterator itEP;
output << stringIndents(0) << "<gml:solidMember>\n";
if (extint == "interior"){
output << stringIndents(1) << "<bldg:Storey>\n";
} else {
}
output << stringIndents(1) << "<bldg:lod2Solid>\n";
output << stringIndents(1) << "<gml:Solid>\n";
output << stringIndents(1) << "<gml:exterior>\n";
output << stringIndents(1) << "<gml:CompositeSurface srsName=\"EPSG:28992\" srsDimension=\"3\">\n";
tabs+=1;
for (itEP = bldng.begin(); itEP != bldng.end(); ++itEP) { // string polytype
string polyType = itEP->first;
map<int,vector<Point_3>> polygons = itEP->second;
map<int,vector<Point_3>>::iterator itP;
output << stringIndents(0) << "<bldg:boundedBy>\n";
output << stringIndents(1) << "<bldg:" << polyType << ">\n";
++tabs;
// Write all coordinates for all faces of the building
for (itP = polygons.begin(); itP != polygons.end(); ++itP) { //Poly number / vector of points
stringstream iss;
iss << itP->first;
vector<Point_3> pointVector = itP->second;
if (isDegen(pointVector,1e-8)) continue; // Check degeneracy, if degenerate continue with new face
string polyNR = iss.str();
counter[polyType]++;
int plNR = counter[polyType];
string s;
stringstream out;
out << plNR;
s = out.str();
out.str(string());
out.clear();
string t;
out << polyNR;
t = out.str();
string gmlID = bagID + "_" + polyType + "_" + t + "_" + s;
gmlIDs[polyType].push_back(gmlID);
output << stringIndents(0) << "<gml:surfaceMember>\n";
output << stringIndents(1) << "<gml:Polygon xmlns:gml=\"http://www.opengis.net/gml\" gml:id=\"BAG" << gmlID << "\">\n";
output << stringIndents(1) << "<gml:exterior>\n";
output << stringIndents(1) << "<gml:LinearRing>\n";
output << stringIndents(1) << "<gml:posList>";
int i = 0;
double x0,y0,z0;
vector<Point_3>::iterator itVP;
for (itVP = pointVector.begin(); itVP != pointVector.end(); ++itVP) {
double x = CGAL::to_double(itVP->x()), y = CGAL::to_double(itVP->y()), z = CGAL::to_double(itVP->z());
output.precision(30);
output << dblToStr(x,4) << " " << dblToStr(y,4) << " " << dblToStr(z,4) << " ";
if (i == 0) {
x0=x, y0=y, z0=z;
i = 9;
}
}
output << dblToStr(x0,4) << " " << dblToStr(y0,4) << " " << dblToStr(z0,4) << "</gml:posList>\n";
output << stringIndents(-1) << "</gml:LinearRing>\n";
output << stringIndents(-1) << "</gml:exterior>\n";
output << stringIndents(-1) << "</gml:Polygon>\n";
output << stringIndents(-1) << "</gml:surfaceMember>\n";
}
output << stringIndents(-1) << "</bldg:" << polyType << ">\n";
output << stringIndents(-1) << "</bldg:boundedBy>\n";
}
output << stringIndents(-1) << "</gml:CompositeSurface>\n";
output << stringIndents(-1) << "</gml:exterior>\n";
output << stringIndents(-1) << "</gml:Solid>\n";
output << stringIndents(-1) << "</bldg:lod2Solid>\n";
if (extint == "interior"){
output << stringIndents(-1) << "</bldg:Storey>\n";
} else {
}
output << stringIndents(-1) << "</gml:solidMember>\n";
}
}
output << stringIndents(-1) << "</gml:MultiSolid>\n";
}
void Building::writeGeometry_old(ofstream& output){
itBuildingPolys itBP;
map<string,int> counter;
counter["RoofSurface"] = 0;
counter["WallSurface"] = 0;
counter["CeilingSurface"] = 0;
counter["InteriorWallSurface"] = 0;
counter["FloorSurface"] = 0;
counter["GroundSurface"] = 0;
map<string,map<int,map<string,map<int,vector<Point_3>>>>>::iterator itPolys;
for (itPolys = finalPolygons.begin(); itPolys != finalPolygons.end(); ++ itPolys) { // interior / exterior
string extint = itPolys->first;
map<int,map<string,map<int,vector<Point_3>>>> extintPolys = itPolys->second;
map<int,map<string,map<int,vector<Point_3>>>>::iterator itEIP;
for (itEIP = extintPolys.begin(); itEIP != extintPolys.end(); ++itEIP) { // shell number
int shellNR = itEIP->first;
map<string,map<int,vector<Point_3>>> bldng = itEIP->second;
map<string,map<int,vector<Point_3>>>::iterator itEP;
if (extint == "interior"){
output << "<bldg:consistsOfBuildingPart>\n";
output << "<bldg:BuildingPart gml:id=\"" << bagID << "storey_"<< shellNR << "\">\n";
} else {
output << "<bldg:consistsOfBuildingPart>\n";
output << "<bldg:BuildingPart gml:id=\"" << bagID << "_exterior\">\n";
}
for (itEP = bldng.begin(); itEP != bldng.end(); ++itEP) { // string polytype
string polyType = itEP->first;
map<int,vector<Point_3>> polygons = itEP->second;
map<int,vector<Point_3>>::iterator itP;
output << "\t\t\t" << "<bldg:boundedBy>\n";
output << "\t\t\t\t" << "<bldg:" << polyType << ">\n";
output << "\t\t\t\t\t" << "<bldg:lod2MultiSurface>\n";
output << "\t\t\t\t\t\t" << "<gml:MultiSurface srsName=\"EPSG:28992\" srsDimension=\"3\">\n";
// Write all coordinates for all faces of the building
for (itP = polygons.begin(); itP != polygons.end(); ++itP) { //Poly number / vector of points
stringstream iss;
iss << itP->first;
vector<Point_3> pointVector = itP->second;
if (pointVector.size()<3) {
cout << "Degenerate face \n ";
continue;
}
if (extint == "interior"){
//reverse(pointVector.begin(),pointVector.end());
}
Point_3 pointA = pointVector[0];
Point_3 pointB = pointVector[1];
Point_3 pointC = pointVector[2];
Triangle_3 testTri(pointA,pointB,pointC);
Line_3 lineA(pointA,pointB);
Line_3 lineB(pointB,pointC);
double tol = 1e-10;
if (testTri.is_degenerate()) continue;
//if (CGAL::compare (squared_distance(lineA, pointC), tol) == CGAL::SMALLER ||
// CGAL::compare (squared_distance(lineB, pointA), tol) == CGAL::SMALLER) {
// continue;
//}
string polyNR = iss.str();
counter[polyType]++;
int plNR = counter[polyType];
string s;
stringstream out;
out << plNR;
s = out.str();
out.str(string());
out.clear();
string t;
out << polyNR;
t = out.str();
string gmlID = bagID + "_" + polyType + "_" + t + "_" + s;
gmlIDs[polyType].push_back(gmlID);
output << "\t\t\t\t\t\t\t" << "<gml:surfaceMember>\n";
output << "\t\t\t\t\t\t\t\t" << "<gml:Polygon xmlns:gml=\"http://www.opengis.net/gml\" gml:id=\"" << gmlID << "\">\n";
output << "\t\t\t\t\t\t\t\t\t" << "<gml:exterior>\n";
output << "\t\t\t\t\t\t\t\t\t\t" << "<gml:LinearRing>\n";
output << "\t\t\t\t\t\t\t\t\t\t\t" << "<gml:posList>";
int i = 0;
double x0,y0,z0;
vector<Point_3>::iterator itVP;
for (itVP = pointVector.begin(); itVP != pointVector.end(); ++itVP) {
double x = CGAL::to_double(itVP->x()), y = CGAL::to_double(itVP->y()), z = CGAL::to_double(itVP->z());
output.precision(30);
output << x << " " << y << " " << z << " ";
if (i == 0) {
x0=x, y0=y, z0=z;
i = 9;
}
}
output << x0 << " " << y0 << " " << z0 << "</gml:posList>\n";
output << "\t\t\t\t\t\t\t\t\t\t" << "</gml:LinearRing>\n";
output << "\t\t\t\t\t\t\t\t\t" << "</gml:exterior>\n";
output << "\t\t\t\t\t\t\t\t" << "</gml:Polygon>\n";
output << "\t\t\t\t\t\t\t" << "</gml:surfaceMember>\n";
}
output << "\t\t\t\t\t\t" << "</gml:MultiSurface>\n";
output << "\t\t\t\t\t" << "</bldg:lod2MultiSurface>\n";
output << "\t\t\t\t" << "</bldg:" << polyType << ">\n";
output << "\t\t\t" << "</bldg:boundedBy>\n";
}
output << "</bldg:BuildingPart>\n";
output << "</bldg:consistsOfBuildingPart>\n";
}
}
}
void Building::writeAddress(ofstream& output){
output << stringIndents(0) << "<bldg:address>\n";
output << stringIndents(1) << "<Address>\n";
output << stringIndents(1) << "<xalAddress>\n";
output << stringIndents(1) << "<xAL:AddressDetails>\n";
output << stringIndents(1) << "<xAL:Country>\n";
output << stringIndents(1) << "<xAL:CountryName>The Netherlands</xAL:CountryName>\n";
output << stringIndents(0) << "<xAL:Locality Type=\"Town\">\n";
output << stringIndents(1) << "<xAL:LocalityName>Rotterdam</xAL:LocalityName>\n";
output << stringIndents(0) << "<xAL:Thoroughfare Type=\"Street\">\n";
output << stringIndents(1) << "<xAL:ThoroughfareNumber>" << houseNR << "</xAL:ThoroughfareNumber>\n";
output << stringIndents(0) << "<xAL:ThoroughfareName>" << streetName << "</xAL:ThoroughfareName>\n";
output << stringIndents(-1) << "</xAL:Thoroughfare>\n";
output << stringIndents(0) << "<xAL:PostalCode>\n";
output << stringIndents(1) << "<xAL:PostalCodeNumber>" << postalCode << "</xAL:PostalCodeNumber>\n";
output << stringIndents(-1) << "</xAL:PostalCode>\n";
output << stringIndents(-1) << "</xAL:Locality>\n";
output << stringIndents(-1) << "</xAL:Country>\n";
output << stringIndents(-1) << "</xAL:AddressDetails>\n";
output << stringIndents(-1) << "</xalAddress>\n";
output << stringIndents(-1) << "</Address>\n";
output << stringIndents(-1) << "</bldg:address>\n";
}
void Building::writeAppearance(ofstream& output){
map<string,vector<string>>::iterator it;
string transp, color;
for (it = gmlIDs.begin(); it != gmlIDs.end(); ++it) {
string polyType = it->first;
if (polyType == "RoofSurface") {
color = "1 0 0";
transp = "0.5";
} else if (polyType == "WallSurface") {
color = "0.9 0.9 0.4";
transp = "0.5";
} else if (polyType == "GroundSurface") {
color = "0 1 0";
transp = "0.5";
} else if (polyType == "InteriorWallSurface") {
color = "0.7 0.7 0.7";
transp = "0";
} else if (polyType == "CeilingSurface") {
color = "0.8 0.2 0.2";
transp = "0";
} else if (polyType == "FloorSurface") {
color = "0 0 1";
transp = "0";
}
output << stringIndents(0) << "<app:appearanceMember>\n";
output << stringIndents(1) << "<app:Appearance>\n";
output << stringIndents(1) << "<app:surfaceDataMember>\n";
output << stringIndents(1) << "<app:X3DMaterial>\n";
output << stringIndents(1) << "<app:transparency>" << transp << "</app:transparency>\n";
output << stringIndents(0) << "<app:diffuseColor>" << color << "</app:diffuseColor>\n";
for (int v = 0; v != gmlIDs[it->first].size(); ++v) {
output << stringIndents(0) << "<app:target>BAG" << gmlIDs[it->first][v] << "</app:target>\n";
}
output << stringIndents(-1) << "</app:X3DMaterial>\n";
output << stringIndents(-1) << "</app:surfaceDataMember>\n";
output << stringIndents(-1) << "</app:Appearance>\n";
output << stringIndents(-1) << "</app:appearanceMember>\n";
}
}
void Building::writeBuildingFooter(ofstream& output){
/*Writes the last two lines for the building*/
output << stringIndents(-1) << "</bldg:Building>\n";
output << stringIndents(-1) << "</cityObjectMember>\n";
output.flush();
}
bool Building::writeToCityGML(ofstream& output, bool oldGeometry, bool writeExterior, bool alwaysWrite) {
if ((finalPolygons["interior"].size() >= (size_t) storeys && area > 0) || alwaysWrite) {
/*Write the building to the CityGML file*/
writeBuildingHeader(output);
if (oldGeometry) writeGeometry_old(output);
else writeGeometry(output);
writeAddress(output);
writeAppearance(output);
writeBuildingFooter(output);
return true;
}
else {
cout << "\t\t !! Not writing to CityGML, not succeeded!!\n";
return false;
}
}
string Building::stringIndents(int i) {
string s;
tabs+=i;
for (int j = 0; j < tabs; ++ j) {
s.push_back('\t');
}
return s;
}
/*########################################################
##########################################################
The following function can write a building to the .OFF
file format. For debugging purposes.
##########################################################
########################################################*/
void Building::writeOff(string buildingID) {
string validity;
string closed;
if (polyBuilding.is_closed()) {
closed = "_closed";
}
else closed = "_not_closed";
if (polyBuilding.is_valid()) {
validity = "_valid";
}
else validity = "_not_valid";
boost::filesystem::path dir("D:\\Data\\Temp\\" + buildingID + closed + validity + "\\" + streetName + "_" + houseNR );
boost::filesystem::create_directories(dir);
ofstream out;
out.open("D:\\Data\\Temp\\" + buildingID + closed + validity + "\\" + streetName + "_" + houseNR + "\\exterior.off");
out.precision(15);
out << polyBuilding;
out.close();
}
/*########################################################
########################################################*/