Except for roof tops most building parts are exported well

parent 6815b904
......@@ -76,13 +76,14 @@ namespace ITAGeo
*/
bool Store( const std::string& sGMLFilePath, bool bOverwrite = true ) const;
void GetBuildingMesh( const CCityBuilding* pBuilding, ITAGeo::CHalfedgeMeshModel* pBuildingMesh );
void GetBuildingMesh( const CCityBuilding* pBuilding, ITAGeo::CHalfedgeMeshModel* pBuildingMesh, const VistaVector3D v3Shift = VistaVector3D( 0.0f, 0.0f, 0.0f ) );
std::vector< const ITAGeo::CCityGMLModel::CCityBuilding* > GetBuildings() const;
void DistanceCulling( const double dDetourDistance, const ITAGeo::CPropagationAnchor& v3Source, const ITAGeo::CPropagationAnchor& v3Target, std::vector< const ITAGeo::CCityGMLModel::CCityBuilding* >& vpResidualBuildings );
void CalculateObjectCentroids();
std::vector< double > GetCityCenter() const;
protected:
CCityGMLPtr* m_pCityModel; //!< Encapsuled pointer to the city GML instance
......
......@@ -57,100 +57,70 @@ public:
//! Resolved for Polygons without Holes // throws Polygon Connectivity error at seemingly random points.
void ITAGeo::CCityGMLModel::GetBuildingMesh( const ITAGeo::CCityGMLModel::CCityBuilding* pBuilding, ITAGeo::CHalfedgeMeshModel* pMeshModel )
void ITAGeo::CCityGMLModel::GetBuildingMesh( const ITAGeo::CCityGMLModel::CCityBuilding* pBuilding, ITAGeo::CHalfedgeMeshModel* pMeshModel, const VistaVector3D v3Shift )
{
const citygml::CityObject& oCityRootObject = m_pCityModel->pCityModel->getRootCityObject( pBuilding->iNum - 1 );
const citygml::CityObject& oBuilding = m_pCityModel->pCityModel->getRootCityObject( pBuilding->iNum - 1 );
CITAMesh* pMesh = pMeshModel->GetMesh()->pTopLevelMesh;
for( unsigned int j = 0; j < oCityRootObject.getChildCityObjectsCount(); j++ )
std::vector< TVec3d > voPointCloud;
std::vector< CITAMesh::VertexHandle > vvhVertices;
CITAMesh::Point vpGlobalShift( v3Shift[ Vista::X ], v3Shift[ Vista::Y ], v3Shift[ Vista::Z ] );
std::cout << "Building mesh for object " << oBuilding.getId() << std::endl;
for( unsigned int j = 0; j < oBuilding.getChildCityObjectsCount(); j++ )
{
for( unsigned int k = 0; k < oCityRootObject.getChildCityObject( j ).getGeometriesCount(); k++ )
for( unsigned int k = 0; k < oBuilding.getChildCityObject( j ).getGeometriesCount(); k++ )
{
for( unsigned int l = 0; l < oCityRootObject.getChildCityObject( j ).getGeometry( k ).getPolygonsCount(); l++ )
for( unsigned int l = 0; l < oBuilding.getChildCityObject( j ).getGeometry( k ).getPolygonsCount(); l++ )
{
std::shared_ptr<const citygml::Polygon> pPolygon = oCityRootObject.getChildCityObject( j ).getGeometry( k ).getPolygon( l );
std::vector<TVec3d> vPolygonVertices = pPolygon->getVertices();
const citygml::CityObject& oBuildingPart = oBuilding.getChildCityObject( j );
std::shared_ptr<const citygml::Polygon> pPolygon = oBuildingPart.getGeometry( k ).getPolygon( l );
std::vector< TVec3d > vPolygonVertices = pPolygon->getVertices();
assert( vPolygonVertices.size() > 2 );
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//! Necessary workaround for the duplicate Vertices (always consecutive) that citygml::Polygon::getVertices() occasionally produces.
// coordinates in the duplicates vary around the 10 decimal spot, hence the rounding to the 3rd spot
for( unsigned int m = 0; m < vPolygonVertices.size(); m++ )
{
vPolygonVertices[ m ].x = std::floor( vPolygonVertices[ m ].x * 100000 + 0.5 ) / 100000;
vPolygonVertices[ m ].y = std::floor( vPolygonVertices[ m ].y * 100000 + 0.5 ) / 100000;
vPolygonVertices[ m ].z = std::floor( vPolygonVertices[ m ].z * 100000 + 0.5 ) / 100000;
}
// erases duplicates, but can only remove consecutive duplicates.
vPolygonVertices.erase( std::unique( vPolygonVertices.begin(), vPolygonVertices.end() ), vPolygonVertices.end() );
if( vPolygonVertices.size() < 3 )
{
std::cerr << "Found invalid line ring with less than three unique vertices. Skipping this face." << std::endl;
continue;
}
// First and last vertex are always identical by gml definition of a line ring; has to be removed so OpenMesh can produce a face
while( vPolygonVertices.front() == vPolygonVertices.back() )
{
vPolygonVertices.pop_back();
}
if( vPolygonVertices.size() < 3 )
{
std::cerr << "Found invalid line ring with less than three independent vertices. Skipping this face." << std::endl;
continue;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//! Actual Mesh conversion
std::vector<CITAMesh::VertexHandle> vFaceVertices;
// Multiple faces can share the same vertices, following loop makes sure only new vertices are added to mesh
for( unsigned int m = 0; m < vPolygonVertices.size(); m++ )
for( unsigned int m = 0; m < vPolygonVertices.size() - 1; m++ )
{
TVec3d& v( vPolygonVertices[ m ] );
bool bSkip = false;
const CITAMesh::Point CurrentPoint = CityGMLPoint3DToITAMeshPoint( vPolygonVertices[ m ] );
CITAMesh::VertexIter it_v;
for( it_v = pMesh->vertices_begin(); it_v != pMesh->vertices_end(); it_v++ )
for( size_t n = 0; n < voPointCloud.size(); n++ )
{
CITAMesh::VertexHandle vhVertex( *it_v );
if( CurrentPoint == pMesh->point( vhVertex ) )
const TVec3d& p( voPointCloud[ n ] );
if( v.x == p.x && v.y == p.y && v.z == p.z )
{
vFaceVertices.push_back( vhVertex );
bSkip = true;
break;
vFaceVertices.push_back( vvhVertices[ n ] );
}
}
if( bSkip )
if( !bSkip )
{
continue; //need to exit both loops to check next vertex
}
vFaceVertices.push_back( pMesh->add_vertex( CurrentPoint ) );
}
CITAMesh::VertexHandle vh = pMesh->add_vertex( CityGMLPoint3DToITAMeshPoint( v ) + vpGlobalShift );
size_t iNumVerticesPre = vFaceVertices.size();
vFaceVertices.erase( std::unique( vFaceVertices.begin(), vFaceVertices.end() ), vFaceVertices.end() );
if( vFaceVertices.size() != iNumVerticesPre )
{
std::cout << "For an unkown reason, detected non-unique vertices to be added as face during mesh conversion. Will skip this face for safety." << std::endl;
//continue;
}
voPointCloud.push_back( v );
vvhVertices.push_back( vh );
iNumVerticesPre = vFaceVertices.size();
std::set< CITAMesh::VertexHandle > s( vFaceVertices.begin(), vFaceVertices.end() );
vFaceVertices.assign( s.begin(), s.end() );
if( vFaceVertices.size() != iNumVerticesPre )
std::cout << "For an unkown reason, detected non-unique vertices to be added as face during mesh conversion. Made them unique." << std::endl;
vFaceVertices.push_back( vh );
}
}
// Unique check on vertex handles for new face
std::set< CITAMesh::VertexHandle > sVertexSet( vFaceVertices.begin(), vFaceVertices.end() );
std::vector< CITAMesh::VertexHandle > vPrunedFaceVertices;
vPrunedFaceVertices.assign( sVertexSet.begin(), sVertexSet.end() );
if( vFaceVertices.size() < 3 )
if( vPrunedFaceVertices.size() != vFaceVertices.size() )
{
std::cerr << "Found invalid number of face vertices after mesh conversion. Skipping this face." << std::endl;
std::cerr << "Found non-unique entries in linear ring at " << oBuildingPart.getId() << ", skipping building part." << std::endl;
continue;
}
pMesh->add_face( vFaceVertices );
}
}
......@@ -292,6 +262,13 @@ void ITAGeo::CCityGMLModel::CalculateObjectCentroids()
}
}
std::vector< double > ITAGeo::CCityGMLModel::GetCityCenter() const
{
auto p = m_pCityModel->pCityModel->getEnvelope().getLowerBound();
const std::vector< double > v = { p.x, p.y, p.z };
return v;
}
/**
*@brief Creates list of objects that are relevant to the sound propagation, based on maximum propagation distance and sender & receiver positions
*
......
......@@ -54,13 +54,21 @@ using namespace std;
typedef OpenMesh::PolyMesh_ArrayKernelT<> CITAMesh;
// Resource (CC BY-SA 4.0 Filip Biljecki): https://3d.bk.tudelft.nl/biljecki/Random3Dcity.html
static vector< string > vsAachenCityFilePaths = {
static vector< string > vsAachenCityFilePaths =
{
//"corrupt_building_2"
"LoD2_293_5628_1_NW",
"LoD2_293_5629_1_NW",
"LoD2_294_5628_1_NW",
"LoD2_294_5629_1_NW",
"LoD2_295_5628_1_NW",
"LoD2_295_5629_1_NW" };
};
const VistaVector3D v3GlobalExportShift( -293000.0f, -5628000.0f, 0.0f );
static string sExportFileName = "AachenCityCulling.skp";
// Resource (Land NRW, 2017, https://www.govdata.de/dl-de/by-2-0): https://www.opengeodata.nrw.de/produkte/geobasis/3d-gm/3d-gm_lod2/
//static string sCityGMLFilePath = "Aachen/LoD2_287_5631_1_NW_no_terrain_intersection.gml";
......@@ -81,7 +89,7 @@ int main( int, char** )
ITAGeo::CSensor oReceiver;
oReceiver.vPos.SetValues( 294605.0f, 5628758.0f, 164.0f );
cout << "Source: " << oSource.ToString() << endl;
cout << "Source: " << oSource.ToString() << endl;
cout << "Receiver: " << oReceiver.ToString() << endl;
vector< ITAGeo::CHalfedgeMeshModel* > vpRemainingBuildingModels;
......@@ -108,7 +116,7 @@ int main( int, char** )
for( size_t n = 0; n < vpCityBuildings.size(); n++ )
{
auto pBuildingModel = new ITAGeo::CHalfedgeMeshModel();
oModel.GetBuildingMesh( vpCityBuildings[ n ], pBuildingModel );
oModel.GetBuildingMesh( vpCityBuildings[ n ], pBuildingModel, v3GlobalExportShift );
voSketchUpCity.AddVisualizationMesh( pBuildingModel, "CityBuildings_" + sCityGMLFileName );
vpRemainingBuildingModels.push_back( pBuildingModel );
}
......@@ -124,14 +132,13 @@ int main( int, char** )
for( unsigned int i = 0; i < RemainingObjects.size(); i++ )
{
auto pBuildingModel = new ITAGeo::CHalfedgeMeshModel();
oModel.GetBuildingMesh( RemainingObjects[ i ], pBuildingModel );
oModel.GetBuildingMesh( RemainingObjects[ i ], pBuildingModel, v3GlobalExportShift );
voSketchUpCity.AddVisualizationMesh( pBuildingModel, "CullingAlgo_" + sCityGMLFileName );
vpAachenBuildingModels.push_back( pBuildingModel );
}
cout << "done." << endl;
}
string sExportFileName = "AachenCityCulling.skp";
cout << "Storing city as SketchUp file to " << sExportFileName << " ... ";
voSketchUpCity.Store( sExportFileName );
cout << "done." << endl;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment