diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 6041671f..aa8fc523 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -2,6 +2,7 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}/external") add_subdirectory(crop) add_subdirectory(reconstruct) +add_subdirectory(reconstruct_api) if(WIN32) install (DIRECTORY ${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/share/proj diff --git a/apps/crop/crop.cpp b/apps/crop/crop.cpp index 5f63188c..b72740c8 100644 --- a/apps/crop/crop.cpp +++ b/apps/crop/crop.cpp @@ -259,14 +259,14 @@ int main(int argc, const char * argv[]) { return EXIT_FAILURE; } - auto pj = roofer::createProjHelper(); - auto VectorReader = roofer::createVectorReaderOGR(*pj); - auto VectorWriter = roofer::createVectorWriterOGR(*pj); + auto pj = roofer::misc::createProjHelper(); + auto VectorReader = roofer::io::createVectorReaderOGR(*pj); + auto VectorWriter = roofer::io::createVectorWriterOGR(*pj); VectorWriter->srs = output_crs; - auto RasterWriter = roofer::createRasterWriterGDAL(*pj); - auto PointCloudCropper = roofer::createPointCloudCropper(*pj); - auto VectorOps = roofer::createVector2DOpsGEOS(); - auto LASWriter = roofer::createLASWriter(*pj); + auto RasterWriter = roofer::io::createRasterWriterGDAL(*pj); + auto PointCloudCropper = roofer::io::createPointCloudCropper(*pj); + auto VectorOps = roofer::misc::createVector2DOpsGEOS(); + auto LASWriter = roofer::io::createLASWriter(*pj); VectorReader->open(path_footprint); logger.info("Reading footprints from {}", path_footprint); @@ -333,14 +333,14 @@ int main(int argc, const char * argv[]) { // auto& r_nodata = attributes.insert_vec("r_nodata_"+ipc.name); roofer::arr2f nodata_c; for(unsigned i=0; i 1){ auto& is_mutated = attributes.insert_vec( "is_mutated_"+input_pointclouds[0].name+"_"+input_pointclouds[1].name ); is_mutated.reserve(N_fp); for (unsigned i=0; i candidates; + std::vector candidates; candidates.reserve(input_pointclouds.size()); - std::vector candidates_just_for_data; + std::vector candidates_just_for_data; { int j=0; for (auto& ipc : input_pointclouds) { - auto cpc = roofer::CandidatePointCloud { + auto cpc = roofer::misc::CandidatePointCloud { ipc.nodata_radii[i], ipc.nodata_fractions[i], ipc.building_rasters[i], @@ -453,8 +453,8 @@ int main(int argc, const char * argv[]) { jsonl_paths.insert({"", roofer::vec1s{}}); } - roofer::PointCloudSelectResult sresult = roofer::selectPointCloud(candidates, select_pc_cfg); - const roofer::CandidatePointCloud* selected = sresult.selected_pointcloud; + roofer::misc::PointCloudSelectResult sresult = roofer::misc::selectPointCloud(candidates, select_pc_cfg); + const roofer::misc::CandidatePointCloud* selected = sresult.selected_pointcloud; // this is a sanity check and should never happen if (!selected) { @@ -467,7 +467,7 @@ int main(int argc, const char * argv[]) { if (yoc != -1 && yoc > selected->date) { // force selection of latest pointcloud selected = getLatestPointCloud(candidates); - sresult.explanation = roofer::PointCloudSelectExplanation::_LATEST; + sresult.explanation = roofer::misc::PointCloudSelectExplanation::_LATEST; // overrule if there was a more recent pointcloud with select_only_for_date = true if (candidates_just_for_data.size()) { if ( candidates_just_for_data[0].date > selected->date ) { @@ -477,15 +477,15 @@ int main(int argc, const char * argv[]) { } } - if (sresult.explanation == roofer::PointCloudSelectExplanation::PREFERRED_AND_LATEST ) + if (sresult.explanation == roofer::misc::PointCloudSelectExplanation::PREFERRED_AND_LATEST ) pc_select.push_back("PREFERRED_AND_LATEST"); - else if (sresult.explanation == roofer::PointCloudSelectExplanation::PREFERRED_NOT_LATEST ) + else if (sresult.explanation == roofer::misc::PointCloudSelectExplanation::PREFERRED_NOT_LATEST ) pc_select.push_back("PREFERRED_NOT_LATEST"); - else if (sresult.explanation == roofer::PointCloudSelectExplanation::LATEST_WITH_MUTATION ) + else if (sresult.explanation == roofer::misc::PointCloudSelectExplanation::LATEST_WITH_MUTATION ) pc_select.push_back("LATEST_WITH_MUTATION"); - else if (sresult.explanation == roofer::PointCloudSelectExplanation::_HIGHEST_YET_INSUFFICIENT_COVERAGE ) + else if (sresult.explanation == roofer::misc::PointCloudSelectExplanation::_HIGHEST_YET_INSUFFICIENT_COVERAGE ) pc_select.push_back("_HIGHEST_YET_INSUFFICIENT_COVERAGE"); - else if (sresult.explanation == roofer::PointCloudSelectExplanation::_LATEST ) { + else if (sresult.explanation == roofer::misc::PointCloudSelectExplanation::_LATEST ) { pc_select.push_back("_LATEST"); // // clear pc // ipc[selected->index].building_clouds[i].clear(); diff --git a/apps/reconstruct/reconstruct.cpp b/apps/reconstruct/reconstruct.cpp index 713a2a80..3c0eb8ec 100644 --- a/apps/reconstruct/reconstruct.cpp +++ b/apps/reconstruct/reconstruct.cpp @@ -71,14 +71,14 @@ namespace fs = std::filesystem; enum LOD {LOD12=12, LOD13=13, LOD22=22}; std::unordered_map extrude( - Arrangement_2 arrangement, + roofer::Arrangement_2 arrangement, float floor_elevation, #ifdef RF_USE_VAL3DITY std::vector >& attr_val3dity, #endif std::vector >& attr_rmse, - roofer::detection::SegmentRasteriserInterface* SegmentRasteriser, - roofer::detection::PlaneDetectorInterface* PlaneDetector, + roofer::reconstruction::SegmentRasteriserInterface* SegmentRasteriser, + roofer::reconstruction::PlaneDetectorInterface* PlaneDetector, LOD lod ) { bool dissolve_step_edges = false; @@ -98,7 +98,7 @@ std::unordered_map extrude( auto &logger = roofer::logger::Logger::get_logger(); - auto ArrangementDissolver = roofer::detection::createArrangementDissolver(); + auto ArrangementDissolver = roofer::reconstruction::createArrangementDissolver(); ArrangementDissolver->compute( arrangement, SegmentRasteriser->heightfield, @@ -110,18 +110,18 @@ std::unordered_map extrude( logger.info("Completed ArrangementDissolver"); logger.info("Roof partition has {} faces", arrangement.number_of_faces()); #ifdef RF_USE_RERUN - rec.log(worldname+"ArrangementDissolver", rerun::LineStrips3D( roofer::detection::arr2polygons(arrangement) )); + rec.log(worldname+"ArrangementDissolver", rerun::LineStrips3D( roofer::reconstruction::arr2polygons(arrangement) )); #endif - auto ArrangementSnapper = roofer::detection::createArrangementSnapper(); + auto ArrangementSnapper = roofer::reconstruction::createArrangementSnapper(); ArrangementSnapper->compute( arrangement ); logger.info("Completed ArrangementSnapper"); #ifdef RF_USE_RERUN - // rec.log(worldname+"ArrangementSnapper", rerun::LineStrips3D( roofer::detection::arr2polygons(arrangement) )); + // rec.log(worldname+"ArrangementSnapper", rerun::LineStrips3D( roofer::reconstruction::arr2polygons(arrangement) )); #endif - auto ArrangementExtruder = roofer::detection::createArrangementExtruder(); + auto ArrangementExtruder = roofer::reconstruction::createArrangementExtruder(); ArrangementExtruder->compute( arrangement, floor_elevation, @@ -134,7 +134,7 @@ std::unordered_map extrude( rec.log(worldname+"ArrangementExtruder", rerun::LineStrips3D(ArrangementExtruder->faces).with_class_ids(ArrangementExtruder->labels)); #endif - auto MeshTriangulator = roofer::detection::createMeshTriangulatorLegacy(); + auto MeshTriangulator = roofer::reconstruction::createMeshTriangulatorLegacy(); MeshTriangulator->compute( ArrangementExtruder->multisolid ); @@ -143,7 +143,7 @@ std::unordered_map extrude( rec.log(worldname+"MeshTriangulator", rerun::Mesh3D(MeshTriangulator->triangles).with_vertex_normals(MeshTriangulator->normals).with_class_ids(MeshTriangulator->ring_ids)); #endif - auto PC2MeshDistCalculator = roofer::detection::createPC2MeshDistCalculator(); + auto PC2MeshDistCalculator = roofer::misc::createPC2MeshDistCalculator(); PC2MeshDistCalculator->compute( PlaneDetector->pts_per_roofplane, MeshTriangulator->multitrianglecol, @@ -156,7 +156,7 @@ std::unordered_map extrude( #endif #ifdef RF_USE_VAL3DITY - auto Val3dator = roofer::detection::createVal3dator(); + auto Val3dator = roofer::reconstruction::createVal3dator(); Val3dator->compute( ArrangementExtruder->multisolid ); @@ -327,7 +327,7 @@ int main(int argc, const char * argv[]) { } // Create Writer. TODO: check if we can write to output file prior to doing reconstruction? - auto pj = roofer::createProjHelper(); + auto pj = roofer::misc::createProjHelper(); auto CityJsonWriter = roofer::io::createCityJsonWriter(*pj); CityJsonWriter->CRS_ = crs_output; CityJsonWriter->identifier_attribute = building_bid_attribute; @@ -342,8 +342,8 @@ int main(int argc, const char * argv[]) { pj->set_process_crs(crs_process.c_str()); roofer::arr3d offset = {offset_x, offset_y, offset_z}; pj->set_data_offset(offset); - auto PointReader = roofer::createPointCloudReaderLASlib(*pj); - auto VectorReader = roofer::createVectorReaderOGR(*pj); + auto PointReader = roofer::io::createPointCloudReaderLASlib(*pj); + auto VectorReader = roofer::io::createVectorReaderOGR(*pj); VectorReader->open(path_footprint); std::vector footprints; @@ -386,7 +386,7 @@ int main(int argc, const char * argv[]) { rec.log("world/raw_points", rerun::Points3D(points).with_class_ids(classification)); #endif - auto PlaneDetector = roofer::detection::createPlaneDetector(); + auto PlaneDetector = roofer::reconstruction::createPlaneDetector(); PlaneDetector->detect(points_roof); logger.info("Completed PlaneDetector (roof), found {} roofplanes", PlaneDetector->pts_per_roofplane.size()); @@ -416,7 +416,7 @@ int main(int argc, const char * argv[]) { ); } - auto PlaneDetector_ground = roofer::detection::createPlaneDetector(); + auto PlaneDetector_ground = roofer::reconstruction::createPlaneDetector(); PlaneDetector_ground->detect(points_ground); logger.info("Completed PlaneDetector (ground), found {} groundplanes", PlaneDetector_ground->pts_per_roofplane.size()); @@ -441,7 +441,7 @@ int main(int argc, const char * argv[]) { attr_skip.push_back(skip); if (skip) { - auto SimplePolygonExtruder = roofer::detection::createSimplePolygonExtruder(); + auto SimplePolygonExtruder = roofer::reconstruction::createSimplePolygonExtruder(); SimplePolygonExtruder->compute( footprints[fp_i], floor_elevation, @@ -459,42 +459,42 @@ int main(int argc, const char * argv[]) { ); logger.info("Completed CityJsonWriter to {}", path_output_jsonl); } else { - auto AlphaShaper = roofer::detection::createAlphaShaper(); + auto AlphaShaper = roofer::reconstruction::createAlphaShaper(); AlphaShaper->compute(PlaneDetector->pts_per_roofplane); logger.info("Completed AlphaShaper (roof), found {} rings, {} labels", AlphaShaper->alpha_rings.size(), AlphaShaper->roofplane_ids.size()); #ifdef RF_USE_RERUN rec.log("world/alpha_rings_roof", rerun::LineStrips3D(AlphaShaper->alpha_rings).with_class_ids(AlphaShaper->roofplane_ids)); #endif - auto AlphaShaper_ground = roofer::detection::createAlphaShaper(); + auto AlphaShaper_ground = roofer::reconstruction::createAlphaShaper(); AlphaShaper_ground->compute(PlaneDetector_ground->pts_per_roofplane); logger.info("Completed AlphaShaper (ground), found {} rings, {} labels", AlphaShaper_ground->alpha_rings.size(), AlphaShaper_ground->roofplane_ids.size()); #ifdef RF_USE_RERUN rec.log("world/alpha_rings_ground", rerun::LineStrips3D(AlphaShaper_ground->alpha_rings).with_class_ids(AlphaShaper_ground->roofplane_ids)); #endif - auto LineDetector = roofer::detection::createLineDetector(); + auto LineDetector = roofer::reconstruction::createLineDetector(); LineDetector->detect(AlphaShaper->alpha_rings, AlphaShaper->roofplane_ids, PlaneDetector->pts_per_roofplane); logger.info("Completed LineDetector"); #ifdef RF_USE_RERUN rec.log("world/boundary_lines", rerun::LineStrips3D(LineDetector->edge_segments)); #endif - auto PlaneIntersector = roofer::detection::createPlaneIntersector(); + auto PlaneIntersector = roofer::reconstruction::createPlaneIntersector(); PlaneIntersector->compute(PlaneDetector->pts_per_roofplane, PlaneDetector->plane_adjacencies); logger.info("Completed PlaneIntersector"); #ifdef RF_USE_RERUN rec.log("world/intersection_lines", rerun::LineStrips3D(PlaneIntersector->segments)); #endif - auto LineRegulariser = roofer::detection::createLineRegulariser(); + auto LineRegulariser = roofer::reconstruction::createLineRegulariser(); LineRegulariser->compute(LineDetector->edge_segments, PlaneIntersector->segments); logger.info("Completed LineRegulariser"); #ifdef RF_USE_RERUN rec.log("world/regularised_lines", rerun::LineStrips3D(LineRegulariser->regularised_edges)); #endif - auto SegmentRasteriser = roofer::detection::createSegmentRasteriser(); + auto SegmentRasteriser = roofer::reconstruction::createSegmentRasteriser(); SegmentRasteriser->compute( AlphaShaper->alpha_triangles, AlphaShaper_ground->alpha_triangles @@ -513,8 +513,8 @@ int main(int argc, const char * argv[]) { ); #endif - Arrangement_2 arrangement; - auto ArrangementBuilder = roofer::detection::createArrangementBuilder(); + roofer::Arrangement_2 arrangement; + auto ArrangementBuilder = roofer::reconstruction::createArrangementBuilder(); ArrangementBuilder->compute( arrangement, footprints[fp_i], @@ -523,10 +523,10 @@ int main(int argc, const char * argv[]) { logger.info("Completed ArrangementBuilder"); logger.info("Roof partition has {} faces", arrangement.number_of_faces()); #ifdef RF_USE_RERUN - rec.log("world/initial_partition", rerun::LineStrips3D( roofer::detection::arr2polygons(arrangement) )); + rec.log("world/initial_partition", rerun::LineStrips3D( roofer::reconstruction::arr2polygons(arrangement) )); #endif - auto ArrangementOptimiser = roofer::detection::createArrangementOptimiser(); + auto ArrangementOptimiser = roofer::reconstruction::createArrangementOptimiser(); ArrangementOptimiser->compute( arrangement, SegmentRasteriser->heightfield, @@ -534,7 +534,7 @@ int main(int argc, const char * argv[]) { PlaneDetector_ground->pts_per_roofplane ); logger.info("Completed ArrangementOptimiser"); - // rec.log("world/optimised_partition", rerun::LineStrips3D( roofer::detection::arr2polygons(arrangement) )); + // rec.log("world/optimised_partition", rerun::LineStrips3D( roofer::reconstruction::arr2polygons(arrangement) )); // LoDs // attributes to be filled during reconstruction diff --git a/apps/reconstruct_api/CMakeLists.txt b/apps/reconstruct_api/CMakeLists.txt new file mode 100644 index 00000000..e8539f33 --- /dev/null +++ b/apps/reconstruct_api/CMakeLists.txt @@ -0,0 +1,16 @@ +set(APP_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/reconstruct_api.cpp") + +add_executable("reconstruct_api" ${APP_SOURCES}) +set_target_properties("reconstruct_api" PROPERTIES CXX_STANDARD 20) + +set(RECONSTRUCT_LINK_LIBS + roofer-extra + cmake_git_version_tracking +) +if(RF_USE_RERUN) + list(APPEND RECONSTRUCT_LINK_LIBS rerun_sdk) +endif() + +target_link_libraries( + "reconstruct_api" + PRIVATE ${RECONSTRUCT_LINK_LIBS}) \ No newline at end of file diff --git a/apps/reconstruct_api/reconstruct_api.cpp b/apps/reconstruct_api/reconstruct_api.cpp new file mode 100644 index 00000000..bb1dfd6c --- /dev/null +++ b/apps/reconstruct_api/reconstruct_api.cpp @@ -0,0 +1,142 @@ +#include + +#include +#include "argh.h" +#include "fmt/format.h" +#include "git.h" +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Point_3 Point_3; + +void print_help(std::string program_name) { + // see http://docopt.org/ + fmt::print("Usage:\n"); + fmt::print(" {}", program_name); + fmt::print("Options:\n"); + // std::cout << " -v, --version Print version information\n"; + fmt::print(" -h, --help Show this help message\n"); + fmt::print(" -V, --version Show version\n"); + fmt::print(" -v, --verbose Be more verbose\n"); +} + +void print_version() { + fmt::print("roofer {} ({}{}{})\n", + git_Describe(), + std::strcmp(git_Branch(), "main") ? "" : fmt::format("{}, ", git_Branch()), + git_AnyUncommittedChanges() ? "dirty, " : "", + git_CommitDate() + ); +} + +int main(int argc, const char * argv[]) { + + auto cmdl = argh::parser({ "-c", "--config" }); + + cmdl.parse(argc, argv); + std::string program_name = cmdl[0]; + + std::string path_pointcloud = "./input.laz"; + std::string path_footprint = "./input.gpkg"; + float floor_elevation = -0.16899998486042023; + + bool verbose = cmdl[{"-v", "--verbose"}]; + bool version = cmdl[{"-V", "--version"}]; + + if (cmdl[{"-h", "--help"}]) { + print_help(program_name); + return EXIT_SUCCESS; + } + if (version) { + print_version(); + return EXIT_SUCCESS; + } + + // if (verbose) { + // spdlog::set_level(spdlog::level::debug); + // } else { + // spdlog::set_level(spdlog::level::warn); + // } + + // read inputs + auto pj = roofer::misc::createProjHelper(); + auto PointReader = roofer::io::createPointCloudReaderLASlib(*pj); + auto VectorReader = roofer::io::createVectorReaderOGR(*pj); + + VectorReader->open(path_footprint); + std::vector footprints; + VectorReader->readPolygons(footprints); + + PointReader->open(path_pointcloud); + // spdlog::info("Reading pointcloud from {}", path_pointcloud); + roofer::vec1i classification; + roofer::PointCollection points, points_ground, points_roof; + roofer::AttributeVecMap attributes; + PointReader->readPointCloud(points, &classification); + // spdlog::info("Read {} points", points.size()); + + // split into ground and roof points + for (size_t i=0; i meshes = {mesh_lod22, mesh_lod13, mesh_lod12}; + std::vector meshes = {mesh_lod22}; + std::vector names = {"lod22", "lod13", "lod12"}; + + // spdlog::info("Outputting to OBJ files"); + // spdlog::info("Converting to CGAL mesh"); + int i = 0; + for (auto& mesh : meshes) { + // spdlog::info(names[i] + ": converting to CGAL mesh and outputting"); + CGAL::Surface_mesh cgalmesh = roofer::misc::Mesh2CGALSurfaceMesh(mesh); + + // spdlog::info("Writing to obj file"); + std::string filename("output_" + names[i++] + ".obj"); + CGAL::IO::write_OBJ(filename, cgalmesh); + } +} \ No newline at end of file diff --git a/include/roofer/common/Raster.hpp b/include/roofer/common/Raster.hpp index fcc0918d..aaa04419 100644 --- a/include/roofer/common/Raster.hpp +++ b/include/roofer/common/Raster.hpp @@ -29,7 +29,8 @@ // #include // #include // #include -namespace RasterTools { +namespace roofer { + namespace RasterTools { enum alg {MIN,MAX,ZERO}; class Raster { @@ -195,4 +196,5 @@ namespace RasterTools { // void cnt(double &x, double &y); // OGRSpatialReference oSRS; }; + } } \ No newline at end of file diff --git a/include/roofer/common/datastructures.hpp b/include/roofer/common/datastructures.hpp index bb8d3494..dee76e4a 100644 --- a/include/roofer/common/datastructures.hpp +++ b/include/roofer/common/datastructures.hpp @@ -2,6 +2,8 @@ #include +namespace roofer { + class rooferException: public std::exception { public: @@ -14,4 +16,6 @@ class rooferException: public std::exception protected: std::string msg_; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/include/roofer/common/pip_util.hpp b/include/roofer/common/pip_util.hpp index 8565c948..4397e856 100644 --- a/include/roofer/common/pip_util.hpp +++ b/include/roofer/common/pip_util.hpp @@ -19,6 +19,10 @@ #include #include -#include "ptinpoly.h" +#include -pGridSet build_grid(const roofer::vec3f& ring); \ No newline at end of file +namespace roofer { + +pGridSet build_grid(const roofer::vec3f& ring); + +} \ No newline at end of file diff --git a/include/roofer/io/CityJsonWriter.hpp b/include/roofer/io/CityJsonWriter.hpp index 3260e28a..d06547d5 100644 --- a/include/roofer/io/CityJsonWriter.hpp +++ b/include/roofer/io/CityJsonWriter.hpp @@ -1,4 +1,4 @@ - +#pragma once #include #include @@ -26,9 +26,9 @@ namespace roofer::io { float scale_y_ = 1.; float scale_z_ = 1.; - projHelperInterface& pjHelper; + roofer::misc::projHelperInterface& pjHelper; - CityJsonWriterInterface(projHelperInterface& pjh) : pjHelper(pjh) {}; + CityJsonWriterInterface(roofer::misc::projHelperInterface& pjh) : pjHelper(pjh) {}; virtual ~CityJsonWriterInterface() = default; // add_poly_input("part_attributes", {typeid(bool), typeid(int), typeid(float), typeid(std::string), typeid(Date), typeid(Time), typeid(DateTime)}); @@ -43,5 +43,5 @@ namespace roofer::io { const AttributeVecMap& attributes) = 0; }; - std::unique_ptr createCityJsonWriter(projHelperInterface& pjh); + std::unique_ptr createCityJsonWriter(roofer::misc::projHelperInterface& pjh); } \ No newline at end of file diff --git a/include/roofer/io/PointCloudReader.hpp b/include/roofer/io/PointCloudReader.hpp index 40574208..9a679113 100644 --- a/include/roofer/io/PointCloudReader.hpp +++ b/include/roofer/io/PointCloudReader.hpp @@ -1,15 +1,15 @@ - +#pragma once #include #include #include -namespace roofer { +namespace roofer::io { struct PointCloudReaderInterface { - projHelperInterface& pjHelper; + roofer::misc::projHelperInterface& pjHelper; - PointCloudReaderInterface(projHelperInterface& pjh) : pjHelper(pjh) {}; + PointCloudReaderInterface(roofer::misc::projHelperInterface& pjh) : pjHelper(pjh) {}; virtual ~PointCloudReaderInterface() = default; virtual void open(const std::string& source) = 0; @@ -23,5 +23,5 @@ namespace roofer { ) = 0; }; - std::unique_ptr createPointCloudReaderLASlib(projHelperInterface& pjh); + std::unique_ptr createPointCloudReaderLASlib(roofer::misc::projHelperInterface& pjh); } \ No newline at end of file diff --git a/include/roofer/io/PointCloudWriter.hpp b/include/roofer/io/PointCloudWriter.hpp index 9d51863f..abeaacbe 100644 --- a/include/roofer/io/PointCloudWriter.hpp +++ b/include/roofer/io/PointCloudWriter.hpp @@ -1,16 +1,15 @@ - - +#pragma once #include #include #include -namespace roofer { +namespace roofer::io { struct LASWriterInterface { - projHelperInterface& pjHelper; + roofer::misc::projHelperInterface& pjHelper; - LASWriterInterface(projHelperInterface& pjh) : pjHelper(pjh) {}; + LASWriterInterface(roofer::misc::projHelperInterface& pjh) : pjHelper(pjh) {}; virtual ~LASWriterInterface() = default; virtual void write_pointcloud( @@ -21,9 +20,5 @@ namespace roofer { }; - std::unique_ptr createLASWriter(projHelperInterface& pjh); -} -namespace roofer { - - + std::unique_ptr createLASWriter(roofer::misc::projHelperInterface& pjh); } \ No newline at end of file diff --git a/include/roofer/io/RasterWriter.hpp b/include/roofer/io/RasterWriter.hpp index 59631c59..1d863b77 100644 --- a/include/roofer/io/RasterWriter.hpp +++ b/include/roofer/io/RasterWriter.hpp @@ -1,16 +1,16 @@ - +#pragma once #include #include #include #include -namespace roofer { +namespace roofer::io { struct RasterWriterInterface { - projHelperInterface& pjHelper; + roofer::misc::projHelperInterface& pjHelper; - RasterWriterInterface(projHelperInterface& pjh) : pjHelper(pjh) {}; + RasterWriterInterface(roofer::misc::projHelperInterface& pjh) : pjHelper(pjh) {}; virtual ~RasterWriterInterface() = default; virtual void writeBands( @@ -18,5 +18,5 @@ namespace roofer { ImageMap& bands) = 0; }; - std::unique_ptr createRasterWriterGDAL(projHelperInterface& pjh); + std::unique_ptr createRasterWriterGDAL(roofer::misc::projHelperInterface& pjh); } \ No newline at end of file diff --git a/include/roofer/io/StreamCropper.hpp b/include/roofer/io/StreamCropper.hpp index ece6717f..aecb47ad 100644 --- a/include/roofer/io/StreamCropper.hpp +++ b/include/roofer/io/StreamCropper.hpp @@ -1,10 +1,10 @@ - +#pragma once #include #include #include -namespace roofer { +namespace roofer::io { struct PointCloudCropperConfig { std::string filepaths_ = ""; float cellsize = 50.0; @@ -21,9 +21,9 @@ namespace roofer { }; struct PointCloudCropperInterface { - projHelperInterface& pjHelper; + roofer::misc::projHelperInterface& pjHelper; - PointCloudCropperInterface(projHelperInterface& pjh) : pjHelper(pjh) {}; + PointCloudCropperInterface(roofer::misc::projHelperInterface& pjh) : pjHelper(pjh) {}; virtual ~PointCloudCropperInterface() = default; virtual void process( @@ -37,5 +37,5 @@ namespace roofer { ) = 0; }; - std::unique_ptr createPointCloudCropper(projHelperInterface& pjh); + std::unique_ptr createPointCloudCropper(roofer::misc::projHelperInterface& pjh); } \ No newline at end of file diff --git a/include/roofer/io/VectorReader.hpp b/include/roofer/io/VectorReader.hpp index 211dfc5a..e3250db4 100644 --- a/include/roofer/io/VectorReader.hpp +++ b/include/roofer/io/VectorReader.hpp @@ -1,15 +1,15 @@ - +#pragma once #include #include #include -namespace roofer { +namespace roofer::io { struct VectorReaderInterface { - projHelperInterface& pjHelper; + roofer::misc::projHelperInterface& pjHelper; - VectorReaderInterface(projHelperInterface& pjh) : pjHelper(pjh) {}; + VectorReaderInterface(roofer::misc::projHelperInterface& pjh) : pjHelper(pjh) {}; virtual ~VectorReaderInterface() = default; virtual void open(const std::string& source) = 0; @@ -17,5 +17,5 @@ namespace roofer { virtual void readPolygons(std::vector&, AttributeVecMap* attributes=nullptr) = 0; }; - std::unique_ptr createVectorReaderOGR(projHelperInterface& pjh); + std::unique_ptr createVectorReaderOGR(roofer::misc::projHelperInterface& pjh); } \ No newline at end of file diff --git a/include/roofer/io/VectorWriter.hpp b/include/roofer/io/VectorWriter.hpp index 3f58c83b..1711f264 100644 --- a/include/roofer/io/VectorWriter.hpp +++ b/include/roofer/io/VectorWriter.hpp @@ -1,11 +1,11 @@ - +#pragma once #include #include #include #include -namespace roofer { +namespace roofer::io { struct VectorWriterInterface { std::string srs = "";// "EPSG:7415"; @@ -18,9 +18,9 @@ namespace roofer { bool do_transactions_ = false; int transaction_batch_size_ = 1000; - projHelperInterface& pjHelper; + roofer::misc::projHelperInterface& pjHelper; - VectorWriterInterface(projHelperInterface& pjh) : pjHelper(pjh) {}; + VectorWriterInterface(roofer::misc::projHelperInterface& pjh) : pjHelper(pjh) {}; virtual ~VectorWriterInterface() = default; virtual void writePolygons( @@ -38,5 +38,5 @@ namespace roofer { }; }; - std::unique_ptr createVectorWriterOGR(projHelperInterface& pjh); + std::unique_ptr createVectorWriterOGR(roofer::misc::projHelperInterface& pjh); } \ No newline at end of file diff --git a/include/roofer/misc/NodataCircleComputer.hpp b/include/roofer/misc/NodataCircleComputer.hpp index 860bc74a..5845297a 100644 --- a/include/roofer/misc/NodataCircleComputer.hpp +++ b/include/roofer/misc/NodataCircleComputer.hpp @@ -1,10 +1,10 @@ - +#pragma once #include #include #include -namespace roofer { +namespace roofer::misc { void draw_circle( LinearRing& polygon, diff --git a/include/roofer/misc/PC2MeshDistCalculator.hpp b/include/roofer/misc/PC2MeshDistCalculator.hpp index db5d561a..d9e6f08c 100644 --- a/include/roofer/misc/PC2MeshDistCalculator.hpp +++ b/include/roofer/misc/PC2MeshDistCalculator.hpp @@ -1,9 +1,10 @@ +#pragma once #include #include #include -namespace roofer::detection { +namespace roofer::misc { struct PC2MeshDistCalculatorConfig{ }; diff --git a/include/roofer/misc/PointcloudRasteriser.hpp b/include/roofer/misc/PointcloudRasteriser.hpp index 6512df7e..4b94b22f 100644 --- a/include/roofer/misc/PointcloudRasteriser.hpp +++ b/include/roofer/misc/PointcloudRasteriser.hpp @@ -6,7 +6,7 @@ #include #include -namespace roofer { +namespace roofer::misc { void RasterisePointcloud( PointCollection& pointcloud, diff --git a/include/roofer/misc/Val3dator.hpp b/include/roofer/misc/Val3dator.hpp index b603c981..34dc98e7 100644 --- a/include/roofer/misc/Val3dator.hpp +++ b/include/roofer/misc/Val3dator.hpp @@ -1,9 +1,10 @@ +#pragma once #include #include "roofer/reconstruction/cgal_shared_definitions.hpp" #include -namespace roofer::detection { +namespace roofer::misc { struct Val3datorConfig{ // bool log_invalids=false; diff --git a/include/roofer/misc/Vector2DOps.hpp b/include/roofer/misc/Vector2DOps.hpp index a4c3c065..4c3496be 100644 --- a/include/roofer/misc/Vector2DOps.hpp +++ b/include/roofer/misc/Vector2DOps.hpp @@ -1,10 +1,10 @@ - +#pragma once #include #include #include -namespace roofer { +namespace roofer::misc { struct Vector2DOpsInterface { virtual ~Vector2DOpsInterface() = default; diff --git a/include/roofer/misc/cgal_utils.hpp b/include/roofer/misc/cgal_utils.hpp new file mode 100644 index 00000000..6804e491 --- /dev/null +++ b/include/roofer/misc/cgal_utils.hpp @@ -0,0 +1,101 @@ +// This file is part of gfp-building-reconstruction +// Copyright (C) 2018-2022 Ravi Peters + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace roofer::misc { + +template +CGAL::Surface_mesh Mesh2CGALSurfaceMesh(const roofer::Mesh& gfmesh) { + typedef typename CGAL::Surface_mesh SurfaceMesh; + typedef typename SurfaceMesh::Vertex_index VertexIndex; + typedef typename Point::FT FT; + namespace PMP = CGAL::Polygon_mesh_processing; + + SurfaceMesh smesh; + typename std::vector points; + + // method of triangulating everything + /* + auto mesh_triangulator = detection::createMeshTriangulatorLegacy(); + std::vector temp_mesh; temp_mesh.push_back(gfmesh); + mesh_triangulator->compute(temp_mesh); + + std::vector> polygons; + for (const auto &tri : mesh_triangulator->triangles) + { + std::vector rindices; rindices.reserve(3); + for (auto &v : tri) + { + points.push_back(CGAL::make_array(v[0], v[1], v[2])); + rindices.push_back(points.size() - 1); + } + polygons.push_back(rindices); + } + */ + + // method of triangulating polygons that have holes + std::vector> polygons; + for (const auto &ring : gfmesh.get_polygons()) + { + if (ring.interior_rings().empty()) { + std::vector rindices; + rindices.reserve(ring.vertex_count()); + for (auto& v: ring) { + points.push_back(Point(v[0], v[1], v[2])); + rindices.push_back(points.size() - 1); + } + polygons.push_back(rindices); + } else { + auto poly_triangulator = roofer::reconstruction::createMeshTriangulatorLegacy(); + std::vector temp_ring; temp_ring.push_back(ring); + poly_triangulator->compute(temp_ring); + for (const auto &tri : poly_triangulator->triangles) + { + std::vector rindices; rindices.reserve(3); + for (auto &v : tri) + { + points.push_back(Point(v[0], v[1], v[2])); + rindices.push_back(points.size() - 1); + } + polygons.push_back(rindices); + } + } + } + + + // turn polygon soup into polygon mesh + PMP::repair_polygon_soup(points, polygons); + PMP::orient_polygon_soup(points, polygons); + PMP::duplicate_non_manifold_edges_in_polygon_soup(points, polygons); + PMP::polygon_soup_to_polygon_mesh(points, polygons, smesh); + + if(!CGAL::is_triangle_mesh(smesh)) PMP::triangulate_faces(smesh); + + PMP::duplicate_non_manifold_vertices(smesh); + + return smesh; +} + +} // namespace roofer diff --git a/include/roofer/misc/projHelper.hpp b/include/roofer/misc/projHelper.hpp index c4e1d3af..b646ccc0 100644 --- a/include/roofer/misc/projHelper.hpp +++ b/include/roofer/misc/projHelper.hpp @@ -4,7 +4,7 @@ #include #include -namespace roofer { +namespace roofer::misc { struct projHelperInterface { diff --git a/include/roofer/misc/select_pointcloud.hpp b/include/roofer/misc/select_pointcloud.hpp index 04516bd0..299b3d76 100644 --- a/include/roofer/misc/select_pointcloud.hpp +++ b/include/roofer/misc/select_pointcloud.hpp @@ -1,7 +1,8 @@ +#pragma once #include -#include "PointcloudRasteriser.hpp" +#include -namespace roofer { +namespace roofer::misc { struct CandidatePointCloud { float nodata_radius; // radius of the incribed circle in the largest gap diff --git a/include/roofer/reconstruction/AlphaShaper.hpp b/include/roofer/reconstruction/AlphaShaper.hpp index 62b448b1..04df7bde 100644 --- a/include/roofer/reconstruction/AlphaShaper.hpp +++ b/include/roofer/reconstruction/AlphaShaper.hpp @@ -1,9 +1,10 @@ +#pragma once #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct AlphaShaperConfig{ float thres_alpha = 0.25; diff --git a/include/roofer/reconstruction/ArrangementBase.hpp b/include/roofer/reconstruction/ArrangementBase.hpp index e30b1abb..8d846e5f 100644 --- a/include/roofer/reconstruction/ArrangementBase.hpp +++ b/include/roofer/reconstruction/ArrangementBase.hpp @@ -21,9 +21,11 @@ #include #include -#include "cgal_shared_definitions.hpp" +#include #include +namespace roofer::reconstruction { + typedef CGAL::Polygon_2 Polygon_2; // 2D arrangement @@ -44,7 +46,7 @@ typedef CGAL::Arr_accessor Arr_accessor; typedef Arr_accessor::Dcel_vertex DVertex; typedef Arrangement_2::Face Face; struct overlay_functor { - FaceInfo operator()(const FaceInfo a, const FaceInfo b) const { + FaceInfo operator()(const FaceInfo a, const FaceInfo b) const { auto r = FaceInfo(); r.segid=0; // if (a.is_finite && b.is_finite) @@ -66,7 +68,7 @@ struct overlay_functor { r.in_footprint = true; } - return r; + return r; } }; typedef CGAL::Arr_face_overlay_traits } }; class Face_merge_observer : public CGAL::Arr_observer -{ +{ public: Face_merge_observer (Arrangement_2& arr) : CGAL::Arr_observer (arr) {}; @@ -166,13 +168,13 @@ class Face_merge_observer : public CGAL::Arr_observer if (sum_count!=0){ auto w1 = (count1/sum_count); auto w2 = (count2/sum_count); - remaining_face->data().elevation_50p = + remaining_face->data().elevation_50p = remaining_face->data().elevation_50p * w1 + discarded_face->data().elevation_50p * w2; - remaining_face->data().elevation_70p = + remaining_face->data().elevation_70p = remaining_face->data().elevation_70p * w1 + discarded_face->data().elevation_70p * w2; - remaining_face->data().elevation_97p = + remaining_face->data().elevation_97p = std::max(remaining_face->data().elevation_97p, discarded_face->data().elevation_97p); - remaining_face->data().data_coverage = + remaining_face->data().data_coverage = remaining_face->data().data_coverage * w1 + discarded_face->data().data_coverage * w2; // and sum the counts remaining_face->data().pixel_count = sum_count; @@ -189,7 +191,7 @@ class Face_merge_observer : public CGAL::Arr_observer }; class Snap_observer : public CGAL::Arr_observer -{ +{ public: Snap_observer (Arrangement_2& arr) : CGAL::Arr_observer (arr) {}; @@ -218,4 +220,6 @@ void arr_dissolve_step_edges_naive(Arrangement_2& arr, float step_height_thresho void arr_dissolve_step_edges(Arrangement_2& arr, float step_height_threshold); void arr_dissolve_fp(Arrangement_2& arr, bool inside, bool outside); void arr_snap_duplicates(Arrangement_2& arr, double dupe_threshold); -void arr_label_buildingparts(Arrangement_2& arr); \ No newline at end of file +void arr_label_buildingparts(Arrangement_2& arr); + +} // namespace roofer \ No newline at end of file diff --git a/include/roofer/reconstruction/ArrangementBuilder.hpp b/include/roofer/reconstruction/ArrangementBuilder.hpp index 484d8ed6..5393be6d 100644 --- a/include/roofer/reconstruction/ArrangementBuilder.hpp +++ b/include/roofer/reconstruction/ArrangementBuilder.hpp @@ -1,9 +1,10 @@ +#pragma once #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct ArrangementBuilderConfig{ int max_arr_complexity = 400; diff --git a/include/roofer/reconstruction/ArrangementDissolver.hpp b/include/roofer/reconstruction/ArrangementDissolver.hpp index b0cdba16..9e1f2fe7 100644 --- a/include/roofer/reconstruction/ArrangementDissolver.hpp +++ b/include/roofer/reconstruction/ArrangementDissolver.hpp @@ -1,10 +1,11 @@ +#pragma once #include #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct ArrangementDissolverConfig{ bool dissolve_seg_edges = true; diff --git a/include/roofer/reconstruction/ArrangementExtruder.hpp b/include/roofer/reconstruction/ArrangementExtruder.hpp index e0a5cf83..c5d33a7e 100644 --- a/include/roofer/reconstruction/ArrangementExtruder.hpp +++ b/include/roofer/reconstruction/ArrangementExtruder.hpp @@ -1,10 +1,12 @@ +#pragma once #include #include -#include "cgal_shared_definitions.hpp" +#include #include +#include -namespace roofer::detection { +namespace roofer::reconstruction { struct ArrangementExtruderConfig{ bool do_walls=true, do_roofs=true, do_floor=true; @@ -30,12 +32,19 @@ namespace roofer::detection { // add_output("multisolid", typeid(std::unordered_map)); virtual ~ArrangementExtruderInterface() = default; + virtual void compute( - Arrangement_2& arrangement, - const float floor_elevation, - ArrangementExtruderConfig config=ArrangementExtruderConfig() + Arrangement_2& arrangement, + const ElevationProvider& elevation_provider, + ArrangementExtruderConfig config=ArrangementExtruderConfig() ) = 0; - + + virtual void compute( + Arrangement_2& arrangement, + const float base_elevation, + ArrangementExtruderConfig config=ArrangementExtruderConfig() + ) = 0; + }; std::unique_ptr createArrangementExtruder(); diff --git a/include/roofer/reconstruction/ArrangementOptimiser.hpp b/include/roofer/reconstruction/ArrangementOptimiser.hpp index a8f8bc8d..d914ccb3 100644 --- a/include/roofer/reconstruction/ArrangementOptimiser.hpp +++ b/include/roofer/reconstruction/ArrangementOptimiser.hpp @@ -1,10 +1,11 @@ +#pragma once #include #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct ArrangementOptimiserConfig{ float data_multiplier = 8.0; diff --git a/include/roofer/reconstruction/ArrangementSnapper.hpp b/include/roofer/reconstruction/ArrangementSnapper.hpp index 003bcbf4..e80bac17 100644 --- a/include/roofer/reconstruction/ArrangementSnapper.hpp +++ b/include/roofer/reconstruction/ArrangementSnapper.hpp @@ -1,9 +1,10 @@ +#pragma once #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct ArrangementSnapperConfig{ float dist_thres = 0.005; diff --git a/include/roofer/reconstruction/ElevationProvider.hpp b/include/roofer/reconstruction/ElevationProvider.hpp new file mode 100644 index 00000000..b42afc14 --- /dev/null +++ b/include/roofer/reconstruction/ElevationProvider.hpp @@ -0,0 +1,35 @@ +// This file is part of gfp-building-reconstruction +// Copyright (C) 2018-2022 Ravi Peters + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +#pragma once + +#include +#include + +namespace roofer::reconstruction { + + struct ElevationProvider { + virtual ~ElevationProvider() = default; + + virtual float get(const Point_2 pt) const = 0; + + virtual float get_percentile(float percentile) const = 0; + + }; + + std::unique_ptr createElevationProvider(const float floor_elevation); + std::unique_ptr createElevationProvider(const proj_tri_util::DT& base_cdt); + +} // namespace roofer::detection \ No newline at end of file diff --git a/include/roofer/reconstruction/LineDetector.hpp b/include/roofer/reconstruction/LineDetector.hpp index d019a715..abbe1146 100644 --- a/include/roofer/reconstruction/LineDetector.hpp +++ b/include/roofer/reconstruction/LineDetector.hpp @@ -1,9 +1,10 @@ +#pragma once #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct LineDetectorConfig{ float dist_thres = 0.4; diff --git a/include/roofer/reconstruction/LineDetectorBase.hpp b/include/roofer/reconstruction/LineDetectorBase.hpp index 9ff9b70b..e43e5bd6 100644 --- a/include/roofer/reconstruction/LineDetectorBase.hpp +++ b/include/roofer/reconstruction/LineDetectorBase.hpp @@ -25,11 +25,11 @@ #include #include -typedef CGAL::Cartesian SCK; - #include -namespace linedect { +namespace roofer::linedect { + typedef CGAL::Cartesian SCK; + typedef CGAL::Exact_predicates_inexact_constructions_kernel cgal_kernel; typedef cgal_kernel::Vector_3 Vector; typedef cgal_kernel::Point_3 Point; diff --git a/include/roofer/reconstruction/LineRegulariser.hpp b/include/roofer/reconstruction/LineRegulariser.hpp index 0718d043..be067e1d 100644 --- a/include/roofer/reconstruction/LineRegulariser.hpp +++ b/include/roofer/reconstruction/LineRegulariser.hpp @@ -1,9 +1,10 @@ +#pragma once #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct LineRegulariserConfig{ float dist_threshold = 0.5; diff --git a/include/roofer/reconstruction/LineRegulariserBase.hpp b/include/roofer/reconstruction/LineRegulariserBase.hpp index 5129ae90..121d0ff8 100644 --- a/include/roofer/reconstruction/LineRegulariserBase.hpp +++ b/include/roofer/reconstruction/LineRegulariserBase.hpp @@ -24,7 +24,7 @@ #include -namespace linereg { +namespace roofer::linereg { typedef CGAL::Exact_predicates_exact_constructions_kernel K; // typedef CGAL::Exact_predicates_inexact_constructions_kernel K; diff --git a/include/roofer/reconstruction/MeshTriangulator.hpp b/include/roofer/reconstruction/MeshTriangulator.hpp index f781cb80..fb21dcb9 100644 --- a/include/roofer/reconstruction/MeshTriangulator.hpp +++ b/include/roofer/reconstruction/MeshTriangulator.hpp @@ -1,9 +1,10 @@ +#pragma once #include #include "cgal_shared_definitions.hpp" #include -namespace roofer::detection { +namespace roofer::reconstruction { struct MeshTriangulatorConfig{ int dupe_threshold_exp = 6; diff --git a/include/roofer/reconstruction/PlaneDetector.hpp b/include/roofer/reconstruction/PlaneDetector.hpp index 58ab73a7..9ab8d408 100644 --- a/include/roofer/reconstruction/PlaneDetector.hpp +++ b/include/roofer/reconstruction/PlaneDetector.hpp @@ -1,9 +1,10 @@ +#pragma once #include #include "cgal_shared_definitions.hpp" #include -namespace roofer::detection { +namespace roofer::reconstruction { struct PlaneDetectorConfig{ float horiz_min_count = 0.95; diff --git a/include/roofer/reconstruction/PlaneDetectorBase.hpp b/include/roofer/reconstruction/PlaneDetectorBase.hpp index ec366f50..16e0c7f1 100644 --- a/include/roofer/reconstruction/PlaneDetectorBase.hpp +++ b/include/roofer/reconstruction/PlaneDetectorBase.hpp @@ -22,11 +22,13 @@ #include #include -#include "RegionGrower.hpp" -#include "RegionGrower_DS_CGAL.hpp" -#include "cgal_shared_definitions.hpp" +#include +#include +#include #include +namespace roofer { + namespace planedect { class PlaneDS : public regiongrower::CGAL_RegionGrowerDS { @@ -105,4 +107,7 @@ class DistAndNormalTester { return valid; } }; -}; \ No newline at end of file + +} // namespace planedect + +} // namespace roofer \ No newline at end of file diff --git a/include/roofer/reconstruction/PlaneIntersector.hpp b/include/roofer/reconstruction/PlaneIntersector.hpp index 5803acbd..cac645f7 100644 --- a/include/roofer/reconstruction/PlaneIntersector.hpp +++ b/include/roofer/reconstruction/PlaneIntersector.hpp @@ -1,9 +1,10 @@ +#pragma once #include #include "cgal_shared_definitions.hpp" #include -namespace roofer::detection { +namespace roofer::reconstruction { struct PlaneIntersectorConfig{ int min_neighb_pts = 5; diff --git a/include/roofer/reconstruction/RegionGrower.hpp b/include/roofer/reconstruction/RegionGrower.hpp index 6b704dbf..a9f56d12 100644 --- a/include/roofer/reconstruction/RegionGrower.hpp +++ b/include/roofer/reconstruction/RegionGrower.hpp @@ -4,6 +4,8 @@ #include #include +namespace roofer { + namespace regiongrower { using namespace std; @@ -12,13 +14,13 @@ namespace regiongrower { size_t region_id; public: Region(size_t region_id) : region_id(region_id) {}; - + size_t get_region_id() { return region_id; } }; -// typename std::enable_if::value, bool>::type +// typename std::enable_if::value, bool>::type template class RegionGrower { size_t cur_region_id=1; public: @@ -83,4 +85,7 @@ namespace regiongrower { } }; }; -} \ No newline at end of file + +} // namespace regiongrower + +} // namespace roofer \ No newline at end of file diff --git a/include/roofer/reconstruction/RegionGrower_DS_CGAL.hpp b/include/roofer/reconstruction/RegionGrower_DS_CGAL.hpp index f0c43099..b48a3dd7 100644 --- a/include/roofer/reconstruction/RegionGrower_DS_CGAL.hpp +++ b/include/roofer/reconstruction/RegionGrower_DS_CGAL.hpp @@ -12,7 +12,9 @@ #include #include -#include "cgal_shared_definitions.hpp" +#include + +namespace roofer { namespace regiongrower { @@ -32,22 +34,22 @@ class CGAL_RegionGrowerDS { roofer::PointCollection& points; vecvecui neighbours; size_t size; - - CGAL_RegionGrowerDS(roofer::PointCollection& points, size_t N=15) + + CGAL_RegionGrowerDS(roofer::PointCollection& points, size_t N=15) : points(points) { size = points.size(); - + std::vector indexed_points; indexed_points.reserve(size); - + size_t i=0; for(auto p: points) indexed_points.push_back(std::make_pair(Point(p[0], p[1], p[2]),i++)); Tree tree; tree.insert(indexed_points.begin(), indexed_points.end()); neighbours.resize(size); - + for(auto pi : indexed_points){ auto p = pi.first; neighbours[pi.second].reserve(N); @@ -75,4 +77,7 @@ class CGAL_RegionGrowerDS { } }; -} \ No newline at end of file +} // namespace regiongrower + +} // namespace roofer + diff --git a/include/roofer/reconstruction/SegmentRasteriser.hpp b/include/roofer/reconstruction/SegmentRasteriser.hpp index c5c9d24b..8593186d 100644 --- a/include/roofer/reconstruction/SegmentRasteriser.hpp +++ b/include/roofer/reconstruction/SegmentRasteriser.hpp @@ -1,10 +1,11 @@ +#pragma once #include #include -#include "cgal_shared_definitions.hpp" +#include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct SegmentRasteriserConfig{ float cellsize = 0.05; diff --git a/include/roofer/reconstruction/SimplePolygonExtruder.hpp b/include/roofer/reconstruction/SimplePolygonExtruder.hpp index 31d2c79c..1b53b6bd 100644 --- a/include/roofer/reconstruction/SimplePolygonExtruder.hpp +++ b/include/roofer/reconstruction/SimplePolygonExtruder.hpp @@ -1,8 +1,9 @@ +#pragma once #include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct SimplePolygonExtruderConfig{ }; diff --git a/include/roofer/reconstruction/cdt_util.hpp b/include/roofer/reconstruction/cdt_util.hpp index c6da75ed..0db47c45 100644 --- a/include/roofer/reconstruction/cdt_util.hpp +++ b/include/roofer/reconstruction/cdt_util.hpp @@ -13,17 +13,27 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +#pragma once + +#include +#include +#include +#include +#include #include #include #include #include +#include +#include #include +namespace roofer { + namespace tri_util { typedef CGAL::Exact_predicates_inexact_constructions_kernel K; - typedef CGAL::Exact_predicates_inexact_constructions_kernel Epeck; typedef CGAL::Exact_predicates_tag Tag; struct VertexInfo { bool hasPoint = false; @@ -61,4 +71,22 @@ namespace tri_util { void insert_ring(roofer::vec3f& ring, CDT& cdt); CDT create_from_polygon(roofer::LinearRing& poly); -} \ No newline at end of file + +} // namespace tri_util + +// utils for triangulation with projection traits +namespace proj_tri_util { + typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + typedef CGAL::Projection_traits_xy_3 Projection_traits; + typedef CGAL::Delaunay_triangulation_2 DT; + + DT cdt_from_linearing(const roofer::LinearRing& poly); + + float interpolate_from_cdt(const Point_2& p, const DT& cdt); + + //todo temp for testing + void write_cdt_to_obj(const DT& cdt, const std::string& filename); + +} // namespace proj_tri_util + +} // namespace roofer \ No newline at end of file diff --git a/include/roofer/reconstruction/cgal_shared_definitions.hpp b/include/roofer/reconstruction/cgal_shared_definitions.hpp index 49ce8ca7..3cd4271b 100644 --- a/include/roofer/reconstruction/cgal_shared_definitions.hpp +++ b/include/roofer/reconstruction/cgal_shared_definitions.hpp @@ -2,6 +2,11 @@ #include #include +#include +#include +#include + +namespace roofer { typedef CGAL::Exact_predicates_exact_constructions_kernel EPECK; typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK; @@ -15,10 +20,6 @@ typedef std::unordered_map>> IndexedPla // Arrangment definitions -#include -#include -#include - typedef CGAL::Arr_linear_traits_2 Traits_2; typedef Traits_2::Segment_2 Segment_2; typedef Traits_2::Point_2 Point_2; @@ -54,4 +55,6 @@ struct EdgeInfo { double edge_weight; }; typedef CGAL::Arr_extended_dcel Dcel; -typedef CGAL::Arrangement_2 Arrangement_2; \ No newline at end of file +typedef CGAL::Arrangement_2 Arrangement_2; + +} // namespace roofer \ No newline at end of file diff --git a/include/roofer/roofer.h b/include/roofer/roofer.h new file mode 100644 index 00000000..fad27c56 --- /dev/null +++ b/include/roofer/roofer.h @@ -0,0 +1,247 @@ +// This file is part of gfp-building-reconstruction +// Copyright (C) 2018-2022 Ravi Peters + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CGAL/Polygon_with_holes_2.h" + +namespace roofer { + /* + * @brief Configuration parameters for single instance building reconstruction + * + * //todo doc + */ + struct ReconstructionConfig { + // control optimisation + float lambda = 1./9.; + // enable clipping parts off the footprint where ground planes are detected + bool clip_ground = true; + // requested LoD + int lod = 22; + // step height used for LoD13 generalisation + float lod13_step_height = 3.; + // floor elevation + float floor_elevation = 0.; + // force flat floor + bool override_with_floor_elevation = false; + + bool is_valid() { + return (lambda>=0 && lambda <=1.0) && + lod==12 || lod==13 || lod ==22 && + lod13_step_height > 0; + } + }; + + /* + * @brief Reconstructs a single instance of a building from a point cloud with + * one floor elevation + * + * //todo doc + */ + template + Mesh reconstruct_single_instance(const PointCollection& points_roof, + const PointCollection& points_ground, + Footprint& footprint, + ReconstructionConfig cfg=ReconstructionConfig()) + { + try { + // check if configuration is valid + if (!cfg.is_valid()) { + throw rooferException("Invalid roofer configuration."); + } + + // prepare footprint data type + // template deduction will fail if not convertible to LinearRing + if constexpr (std::is_same_v>) { + // convert 2D footprint to LinearRing + roofer::LinearRing linearRing; + for (auto& p : footprint.outer_boundary()) { + float x = p.x(); + float y = p.y(); + linearRing.push_back({x, y, 0.}); + } + for (auto& hole : footprint.holes()) { + vec3f iring; + for (auto& p : hole) { + float x = p.x(); + float y = p.y(); + iring.push_back({x, y, 0.}); + } + linearRing.interior_rings().push_back(iring); + } + cfg.override_with_floor_elevation = true; + } + + std::unique_ptr elevation_provider = nullptr; + if (!cfg.override_with_floor_elevation) { + proj_tri_util::DT base_cdt = + proj_tri_util::cdt_from_linearing(footprint); + auto base_cdt_ptr = std::make_unique(base_cdt); + elevation_provider = roofer::reconstruction::createElevationProvider(*base_cdt_ptr); + } else { + elevation_provider = roofer::reconstruction::createElevationProvider(cfg.floor_elevation); + } + +#ifdef ROOFER_VERBOSE + std::cout << "Reconstructing single instance" << std::endl; + std::cout << "Running plane detectors" << std::endl; +#endif + auto PlaneDetector = roofer::reconstruction::createPlaneDetector(); + PlaneDetector->detect(points_roof); + if (PlaneDetector->roof_type == "no points" || + PlaneDetector->roof_type == "no planes") { + throw rooferException( + "Pointcloud insufficient; unable to detect planes"); + } + auto PlaneDetector_ground = roofer::reconstruction::createPlaneDetector(); + PlaneDetector_ground->detect(points_ground); + +#ifdef ROOFER_VERBOSE + std::cout << "Computing alpha shapes" << std::endl; +#endif + auto AlphaShaper = roofer::reconstruction::createAlphaShaper(); + AlphaShaper->compute(PlaneDetector->pts_per_roofplane); + if (AlphaShaper->alpha_rings.size() == 0) { + throw rooferException( + "Pointcloud insufficient; unable to extract boundary lines"); + } + auto AlphaShaper_ground = roofer::reconstruction::createAlphaShaper(); + AlphaShaper_ground->compute(PlaneDetector_ground->pts_per_roofplane); + +#ifdef ROOFER_VERBOSE + std::cout << "Running line detector" << std::endl; +#endif + auto LineDetector = roofer::reconstruction::createLineDetector(); + LineDetector->detect(AlphaShaper->alpha_rings, AlphaShaper->roofplane_ids, + PlaneDetector->pts_per_roofplane); + +#ifdef ROOFER_VERBOSE + std::cout << "Running plane intersector" << std::endl; +#endif + auto PlaneIntersector = roofer::reconstruction::createPlaneIntersector(); + PlaneIntersector->compute(PlaneDetector->pts_per_roofplane, + PlaneDetector->plane_adjacencies); + +#ifdef ROOFER_VERBOSE + std::cout << "Running line regulariser" << std::endl; +#endif + auto LineRegulariser = roofer::reconstruction::createLineRegulariser(); + LineRegulariser->compute(LineDetector->edge_segments, + PlaneIntersector->segments); + +#ifdef ROOFER_VERBOSE + std::cout << "Running segment rasteriser" << std::endl; +#endif + auto SegmentRasteriser = roofer::reconstruction::createSegmentRasteriser(); + auto SegmentRasterizerCfg = roofer::reconstruction::SegmentRasteriserConfig(); + if (points_ground.empty()) { + SegmentRasterizerCfg.use_ground = false; + cfg.clip_ground = false; + } + SegmentRasteriser->compute(AlphaShaper->alpha_triangles, + AlphaShaper_ground->alpha_triangles, + SegmentRasterizerCfg); + +#ifdef ROOFER_VERBOSE + std::cout << "Running arrangement builder" << std::endl; +#endif + Arrangement_2 arrangement; + auto ArrangementBuilder = roofer::reconstruction::createArrangementBuilder(); + ArrangementBuilder->compute(arrangement, footprint, + LineRegulariser->exact_regularised_edges); + +#ifdef ROOFER_VERBOSE + std::cout << "Running arrangement optimiser" << std::endl; +#endif + auto ArrangementOptimiser = + roofer::reconstruction::createArrangementOptimiser(); + ArrangementOptimiser->compute(arrangement, SegmentRasteriser->heightfield, + PlaneDetector->pts_per_roofplane, + PlaneDetector_ground->pts_per_roofplane, + {.data_multiplier = cfg.lambda, + .smoothness_multiplier = (1 - cfg.lambda), + .use_ground = cfg.clip_ground}); + +#ifdef ROOFER_VERBOSE + std::cout << "Running arrangement dissolver" << std::endl; +#endif + auto ArrangementDissolver = + roofer::reconstruction::createArrangementDissolver(); + ArrangementDissolver->compute( + arrangement, SegmentRasteriser->heightfield, + {.dissolve_step_edges = cfg.lod == 13, + .dissolve_all_interior = cfg.lod == 12, + .step_height_threshold = cfg.lod13_step_height}); + +#ifdef ROOFER_VERBOSE + std::cout << "Running arrangement snapper" << std::endl; +#endif + auto ArrangementSnapper = roofer::reconstruction::createArrangementSnapper(); + ArrangementSnapper->compute(arrangement); + +#ifdef ROOFER_VERBOSE + std::cout << "Running arrangement extruder" << std::endl; +#endif + auto ArrangementExtruder = roofer::reconstruction::createArrangementExtruder(); + ArrangementExtruder->compute(arrangement, + *elevation_provider, + {.LoD2 = cfg.lod == 22}); + +// assert(ArrangementExtruder->meshes.size() == 1); + //todo temp + if (ArrangementExtruder->meshes.size() != 1) { + throw rooferException("More than one output mesh!"); + } + return ArrangementExtruder->meshes.front(); + } catch (const std::exception& e) { +#ifdef ROOFER_VERBOSE + std::cout << "Reconstruction failed, exception thrown: " << e.what() << std::endl; +#endif + throw rooferException(e.what()); + } + } + + /* + * @brief Reconstructs a single instance of a building from a point cloud with + * one floor elevation + * + * Overload for when the ground points are not available + * //todo doc + */ + template + Mesh reconstruct_single_instance(const PointCollection& points_roof, + Footprint& footprint, + ReconstructionConfig cfg=ReconstructionConfig()) + { + PointCollection points_ground = PointCollection(); + return reconstruct_single_instance(points_roof, points_ground, footprint, cfg); + } + +} // namespace roofer \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 437cc3c0..cb78a843 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,2 +1,2 @@ add_subdirectory(core) -add_subdirectory(extra) \ No newline at end of file +add_subdirectory(extra) diff --git a/src/core/common/Raster.cpp b/src/core/common/Raster.cpp index dcc3d31d..cbc2a460 100644 --- a/src/core/common/Raster.cpp +++ b/src/core/common/Raster.cpp @@ -17,253 +17,255 @@ #include #include -namespace RasterTools { +namespace roofer { + namespace RasterTools { - Raster::Raster(double cellsize, double min_x, double max_x, double min_y, double max_y): - cellSize_(cellsize), minx_(min_x), maxx_(max_x), miny_(min_y), maxy_(max_y) - { - dimx_ = (maxx_-minx_)/cellSize_ + 1; - dimy_ = (maxy_-miny_)/cellSize_ + 1; - vals_ = std::make_unique>(); - vals_->resize(dimx_*dimy_); - // counts_ = std::make_unique>(); - // counts_->resize(dimx_*dimy_); - } - Raster::Raster(const Raster& r) - { - cellSize_ = r.cellSize_; - maxx_ = r.maxx_; - minx_ = r.minx_; - maxy_ = r.maxy_; - miny_ = r.miny_; - noDataVal_ = r.noDataVal_; - dimx_ = (maxx_-minx_)/cellSize_ + 1; - dimy_ = (maxy_-miny_)/cellSize_ + 1; - vals_ = std::make_unique>(*r.vals_); - // counts_ = std::make_unique>(*r.counts_); - } - void Raster::operator=(const Raster& r) - { - cellSize_ = r.cellSize_; - maxx_ = r.maxx_; - minx_ = r.minx_; - maxy_ = r.maxy_; - miny_ = r.miny_; - noDataVal_ = r.noDataVal_; - dimx_ = (maxx_-minx_)/cellSize_ + 1; - dimy_ = (maxy_-miny_)/cellSize_ + 1; - vals_ = std::make_unique>(*r.vals_); - // counts_ = std::make_unique>(*r.counts_); - } + Raster::Raster(double cellsize, double min_x, double max_x, double min_y, double max_y): + cellSize_(cellsize), minx_(min_x), maxx_(max_x), miny_(min_y), maxy_(max_y) + { + dimx_ = (maxx_-minx_)/cellSize_ + 1; + dimy_ = (maxy_-miny_)/cellSize_ + 1; + vals_ = std::make_unique>(); + vals_->resize(dimx_*dimy_); + // counts_ = std::make_unique>(); + // counts_->resize(dimx_*dimy_); + } + Raster::Raster(const Raster& r) + { + cellSize_ = r.cellSize_; + maxx_ = r.maxx_; + minx_ = r.minx_; + maxy_ = r.maxy_; + miny_ = r.miny_; + noDataVal_ = r.noDataVal_; + dimx_ = (maxx_-minx_)/cellSize_ + 1; + dimy_ = (maxy_-miny_)/cellSize_ + 1; + vals_ = std::make_unique>(*r.vals_); + // counts_ = std::make_unique>(*r.counts_); + } + void Raster::operator=(const Raster& r) + { + cellSize_ = r.cellSize_; + maxx_ = r.maxx_; + minx_ = r.minx_; + maxy_ = r.maxy_; + miny_ = r.miny_; + noDataVal_ = r.noDataVal_; + dimx_ = (maxx_-minx_)/cellSize_ + 1; + dimy_ = (maxy_-miny_)/cellSize_ + 1; + vals_ = std::make_unique>(*r.vals_); + // counts_ = std::make_unique>(*r.counts_); + } - void Raster::prefill_arrays(alg a){ - if (a==MIN) - noDataVal_ = std::numeric_limits::max(); - else if (a==MAX) - noDataVal_ = -std::numeric_limits::max(); - else { - noDataVal_ = 0; - } - - std::fill(vals_->begin(), vals_->end(), noDataVal_); - // std::fill(counts_->begin(), counts_->end(), 0); - } + void Raster::prefill_arrays(alg a){ + if (a==MIN) + noDataVal_ = std::numeric_limits::max(); + else if (a==MAX) + noDataVal_ = -std::numeric_limits::max(); + else { + noDataVal_ = 0; + } + + std::fill(vals_->begin(), vals_->end(), noDataVal_); + // std::fill(counts_->begin(), counts_->end(), 0); + } - bool Raster::add_point(double x, double y, double z, alg a) - { - bool first = (*vals_)[getLinearCoord(x,y)]==noDataVal_; - if (a==MIN) { - min(x,y,z); - } else if (a==MAX) { - max(x,y,z); + bool Raster::add_point(double x, double y, double z, alg a) + { + bool first = (*vals_)[getLinearCoord(x,y)]==noDataVal_; + if (a==MIN) { + min(x,y,z); + } else if (a==MAX) { + max(x,y,z); + } + return first; } - return first; - } - bool Raster::add_value(double x, double y, double val) - { - bool first = (*vals_)[getLinearCoord(x,y)]==noDataVal_; - add(x,y,val); - return first; - } - bool Raster::check_point(double x, double y) - { - auto col = getCol(x,y); - if (col >= dimx_ || col < 0) return false; - auto row = getRow(x,y); - if (row >= dimy_ || row < 0) return false; - - return true; - } + bool Raster::add_value(double x, double y, double val) + { + bool first = (*vals_)[getLinearCoord(x,y)]==noDataVal_; + add(x,y,val); + return first; + } + bool Raster::check_point(double x, double y) + { + auto col = getCol(x,y); + if (col >= dimx_ || col < 0) return false; + auto row = getRow(x,y); + if (row >= dimy_ || row < 0) return false; + + return true; + } - // inline void Raster::avg(double &x, double &y, double &val) - // { - // size_t c = getLinearCoord(x,y); - // (*vals_)[c]= ((*vals_)[c]*(*counts_)[c]+val)/((*counts_)[c]+1); - // ++(*counts_)[c]; - // } + // inline void Raster::avg(double &x, double &y, double &val) + // { + // size_t c = getLinearCoord(x,y); + // (*vals_)[c]= ((*vals_)[c]*(*counts_)[c]+val)/((*counts_)[c]+1); + // ++(*counts_)[c]; + // } - inline void Raster::min(double &x, double &y, double &val) - { - size_t c = getLinearCoord(x,y); - if ((*vals_)[c]>val) (*vals_)[c] = val; - } + inline void Raster::min(double &x, double &y, double &val) + { + size_t c = getLinearCoord(x,y); + if ((*vals_)[c]>val) (*vals_)[c] = val; + } - inline void Raster::max(double &x, double &y, double &val) - { - size_t c = getLinearCoord(x,y); - if ((*vals_)[c] Raster::getColRowCoord(double x, double y) const - { - double r = (y-miny_) / cellSize_; - double c = (x-minx_) / cellSize_; - - return {c,r}; - } + std::array Raster::getColRowCoord(double x, double y) const + { + double r = (y-miny_) / cellSize_; + double c = (x-minx_) / cellSize_; + + return {c,r}; + } - size_t Raster::getRow(double x, double y) const - { - return static_cast( floor((y-miny_) / cellSize_) ); - } - size_t Raster::getCol(double x, double y) const - { - return static_cast( floor((x-minx_) / cellSize_) ); - } + size_t Raster::getRow(double x, double y) const + { + return static_cast( floor((y-miny_) / cellSize_) ); + } + size_t Raster::getCol(double x, double y) const + { + return static_cast( floor((x-minx_) / cellSize_) ); + } - size_t Raster::getLinearCoord(double x, double y) const - { - size_t r = static_cast( floor((y-miny_) / cellSize_) ); - size_t c = static_cast( floor((x-minx_) / cellSize_) ); - - return r * dimx_ + c; - } + size_t Raster::getLinearCoord(double x, double y) const + { + size_t r = static_cast( floor((y-miny_) / cellSize_) ); + size_t c = static_cast( floor((x-minx_) / cellSize_) ); + + return r * dimx_ + c; + } - size_t Raster::getLinearCoord(size_t r, size_t c) const - { - return r * dimx_ + c; - } + size_t Raster::getLinearCoord(size_t r, size_t c) const + { + return r * dimx_ + c; + } - std::array Raster::getPointFromRasterCoords(size_t col, size_t row) const - { - std::array p; - p[0] = minx_ + col*cellSize_ + cellSize_/2; - p[1] = miny_ + row*cellSize_ + cellSize_/2; - p[2] = (*vals_)[col+row*dimx_]; - return p; - } + std::array Raster::getPointFromRasterCoords(size_t col, size_t row) const + { + std::array p; + p[0] = minx_ + col*cellSize_ + cellSize_/2; + p[1] = miny_ + row*cellSize_ + cellSize_/2; + p[2] = (*vals_)[col+row*dimx_]; + return p; + } - double Raster::sample(double &x, double &y) - { - return (*vals_)[getLinearCoord(x,y)]; - } + double Raster::sample(double &x, double &y) + { + return (*vals_)[getLinearCoord(x,y)]; + } - void Raster::set_val(size_t col, size_t row, double val) { - (*vals_)[col+row*dimx_] = val; - } - - double Raster::get_val(size_t col, size_t row) { - return (*vals_)[col+row*dimx_]; - } + void Raster::set_val(size_t col, size_t row, double val) { + (*vals_)[col+row*dimx_] = val; + } + + double Raster::get_val(size_t col, size_t row) { + return (*vals_)[col+row*dimx_]; + } - bool Raster::isNoData(size_t col, size_t row) { - return get_val(col, row) == noDataVal_; - } - bool Raster::isNoData(double &x, double &y) { - return (*vals_)[getLinearCoord(x,y)] == noDataVal_; - } + bool Raster::isNoData(size_t col, size_t row) { + return get_val(col, row) == noDataVal_; + } + bool Raster::isNoData(double &x, double &y) { + return (*vals_)[getLinearCoord(x,y)] == noDataVal_; + } - void Raster::set_nodata(double new_nodata_val) { - for (size_t i=0; i new_vals(dimx_*dimy_); - - set_nodata(std::numeric_limits::max()); - // iterate though raster pixels - for(size_t col=0; col < dimx_; ++col) { - for(size_t row=0; row < dimy_; ++row) { - // if there is nodata here - if (get_val(col, row) == noDataVal_) { - // look in window of size radius around this pixel and collect the minimal value - size_t left = std::max(int(0), int(col)-int(window_size)); - size_t right = std::min(int(dimx_), int(col)+int(window_size)); - size_t bottom = std::max(int(0), int(row)-int(window_size)); - size_t top = std::min(int(dimy_), int(row)+int(window_size)); - double min_val = noDataVal_; - for (size_t wc = left; wc < right; ++wc ) { - for (size_t wr = bottom; wr < top; ++wr ) { - min_val = std::min(min_val, get_val(wc, wr)); + void Raster::fill_nn(size_t window_size) { + // set nodata to max float + std::vector new_vals(dimx_*dimy_); + + set_nodata(std::numeric_limits::max()); + // iterate though raster pixels + for(size_t col=0; col < dimx_; ++col) { + for(size_t row=0; row < dimy_; ++row) { + // if there is nodata here + if (get_val(col, row) == noDataVal_) { + // look in window of size radius around this pixel and collect the minimal value + size_t left = std::max(int(0), int(col)-int(window_size)); + size_t right = std::min(int(dimx_), int(col)+int(window_size)); + size_t bottom = std::max(int(0), int(row)-int(window_size)); + size_t top = std::min(int(dimy_), int(row)+int(window_size)); + double min_val = noDataVal_; + for (size_t wc = left; wc < right; ++wc ) { + for (size_t wr = bottom; wr < top; ++wr ) { + min_val = std::min(min_val, get_val(wc, wr)); + } } + new_vals[col+row*dimx_] = min_val; + } else { + new_vals[col+row*dimx_] = get_val(col, row); } - new_vals[col+row*dimx_] = min_val; - } else { - new_vals[col+row*dimx_] = get_val(col, row); } } + (*vals_) = new_vals; } - (*vals_) = new_vals; - } - // void Raster::write(const char* WKGCS, alg a, void * dataPtr, const char* outFile) - // { - // if( EQUALN(WKGCS, "EPSG:",5) ) { - // oSRS.importFromEPSG( atoi(WKGCS+5) ); - // } else if (EQUALN(WKGCS, "EPSGA:",6)) { - // oSRS.importFromEPSGA( atoi(WKGCS+6) ); - // } - // GDALAllRegister(); - // GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); - // GDALDataset *poDstDS; - // GDALDataType dataType; + // void Raster::write(const char* WKGCS, alg a, void * dataPtr, const char* outFile) + // { + // if( EQUALN(WKGCS, "EPSG:",5) ) { + // oSRS.importFromEPSG( atoi(WKGCS+5) ); + // } else if (EQUALN(WKGCS, "EPSGA:",6)) { + // oSRS.importFromEPSGA( atoi(WKGCS+6) ); + // } + // GDALAllRegister(); + // GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); + // GDALDataset *poDstDS; + // GDALDataType dataType; - // if (a == CNT) - // dataType = GDT_UInt16; - // else - // dataType = GDT_Float64; - - // char **papszOptions = NULL; - // poDstDS = poDriver->Create( outFile, dimx_, dimy_, 1, dataType, - // papszOptions ); - // double adfGeoTransform[6] = { minx_, cellSize_, 0, miny_, 0, cellSize_ }; - // GDALRasterBand *poBand; - - // poDstDS->SetGeoTransform( adfGeoTransform ); - - // // std::cout << oSRS.SetWellKnownGeogCS( WKGCS ); - // // std::cout << pszSRS_WKT <SetProjection( pszSRS_WKT ); - // CPLFree( pszSRS_WKT ); - - // poBand = poDstDS->GetRasterBand(1); - // poBand->RasterIO( GF_Write, 0, 0, dimx_, dimy_, - // dataPtr, dimx_, dimy_, dataType, 0, 0 ); - // poBand->SetNoDataValue(noDataVal); - // /* Once we're done, close properly the dataset */ - // GDALClose( (GDALDatasetH) poDstDS ); - // } + // if (a == CNT) + // dataType = GDT_UInt16; + // else + // dataType = GDT_Float64; + + // char **papszOptions = NULL; + // poDstDS = poDriver->Create( outFile, dimx_, dimy_, 1, dataType, + // papszOptions ); + // double adfGeoTransform[6] = { minx_, cellSize_, 0, miny_, 0, cellSize_ }; + // GDALRasterBand *poBand; + + // poDstDS->SetGeoTransform( adfGeoTransform ); + + // // std::cout << oSRS.SetWellKnownGeogCS( WKGCS ); + // // std::cout << pszSRS_WKT <SetProjection( pszSRS_WKT ); + // CPLFree( pszSRS_WKT ); + + // poBand = poDstDS->GetRasterBand(1); + // poBand->RasterIO( GF_Write, 0, 0, dimx_, dimy_, + // dataPtr, dimx_, dimy_, dataType, 0, 0 ); + // poBand->SetNoDataValue(noDataVal); + // /* Once we're done, close properly the dataset */ + // GDALClose( (GDALDatasetH) poDstDS ); + // } + } } \ No newline at end of file diff --git a/src/core/common/pip_util.cpp b/src/core/common/pip_util.cpp index 2df4582c..deca421a 100644 --- a/src/core/common/pip_util.cpp +++ b/src/core/common/pip_util.cpp @@ -15,19 +15,21 @@ // along with this program. If not, see . #include -pGridSet build_grid(const roofer::vec3f& ring) { - int Grid_Resolution = 20; +namespace roofer { + pGridSet build_grid(const roofer::vec3f& ring) { + int Grid_Resolution = 20; - int size = ring.size(); - std::vector pgon; - for (auto& p : ring) { - pgon.push_back(new Pipoint{ p[0],p[1] }); + int size = ring.size(); + std::vector pgon; + for (auto& p : ring) { + pgon.push_back(new Pipoint{ p[0],p[1] }); + } + pGridSet grid_set = new GridSet(); + // skip last point in the ring, ie the repetition of the first vertex + GridSetup(&pgon[0], pgon.size(), Grid_Resolution, grid_set); + for (int i = 0; i < size; i++) { + delete pgon[i]; + } + return grid_set; } - pGridSet grid_set = new GridSet(); - // skip last point in the ring, ie the repetition of the first vertex - GridSetup(&pgon[0], pgon.size(), Grid_Resolution, grid_set); - for (int i = 0; i < size; i++) { - delete pgon[i]; - } - return grid_set; } \ No newline at end of file diff --git a/src/core/logger/logger.cpp b/src/core/logger/logger.cpp index 124707df..73e25cfc 100644 --- a/src/core/logger/logger.cpp +++ b/src/core/logger/logger.cpp @@ -20,7 +20,7 @@ #include #include -namespace { +namespace roofer::logger { /** @brief Convert the log level into string */ std::string string_from_log_level(roofer::logger::LogLevel level) { std::array names = {"OFF", "DEBUG", "INFO", @@ -35,9 +35,7 @@ namespace { auto now = system_clock::now(); return fmt::format("{:%F %T}", now); } -} // namespace -namespace roofer::logger { struct Logger::logger_impl { LogLevel level = LogLevel::default_level; diff --git a/src/core/reconstruction/AlphaShaper.cpp b/src/core/reconstruction/AlphaShaper.cpp index 3408b15e..562097f8 100644 --- a/src/core/reconstruction/AlphaShaper.cpp +++ b/src/core/reconstruction/AlphaShaper.cpp @@ -8,7 +8,7 @@ #include #include -namespace roofer::detection { +namespace roofer::reconstruction { static const int EXTERIOR=-1, NEVER_VISITED=-2, HOLE=-3; typedef CGAL::Exact_predicates_inexact_constructions_kernel K; diff --git a/src/core/reconstruction/ArrangementBase.cpp b/src/core/reconstruction/ArrangementBase.cpp index 4acfe1e2..9ca9d39e 100644 --- a/src/core/reconstruction/ArrangementBase.cpp +++ b/src/core/reconstruction/ArrangementBase.cpp @@ -16,6 +16,8 @@ #include #include +namespace roofer::reconstruction { + template bool ccb_to_polygon_3(E he, P& polygon, double h=0) { auto first = he; @@ -347,4 +349,6 @@ void arr_label_buildingparts(Arrangement_2& arr) { ++part_counter; } } -} \ No newline at end of file +} + +} // namespace roofer::detection \ No newline at end of file diff --git a/src/core/reconstruction/ArrangementBuilder.cpp b/src/core/reconstruction/ArrangementBuilder.cpp index c23c3e0e..48061348 100644 --- a/src/core/reconstruction/ArrangementBuilder.cpp +++ b/src/core/reconstruction/ArrangementBuilder.cpp @@ -4,7 +4,7 @@ #include #include -namespace roofer::detection { +namespace roofer::reconstruction { class ArrangementBuilder : public ArrangementBuilderInterface{ diff --git a/src/core/reconstruction/ArrangementDissolver.cpp b/src/core/reconstruction/ArrangementDissolver.cpp index 5da6d94e..73e35604 100644 --- a/src/core/reconstruction/ArrangementDissolver.cpp +++ b/src/core/reconstruction/ArrangementDissolver.cpp @@ -1,7 +1,7 @@ #include #include -namespace roofer::detection { +namespace roofer::reconstruction { class ArrangementDissolver : public ArrangementDissolverInterface{ diff --git a/src/core/reconstruction/ArrangementExtruder.cpp b/src/core/reconstruction/ArrangementExtruder.cpp index b06feee6..d2ba3af8 100644 --- a/src/core/reconstruction/ArrangementExtruder.cpp +++ b/src/core/reconstruction/ArrangementExtruder.cpp @@ -1,7 +1,7 @@ #include #include -namespace roofer::detection { +namespace roofer::reconstruction { // typedef CGAL::Cartesian AK; @@ -89,19 +89,18 @@ namespace roofer::detection { public: void compute( - Arrangement_2& arr, - const float floor_elevation, - ArrangementExtruderConfig cfg + Arrangement_2& arr, + const ElevationProvider& elevation_provider, + ArrangementExtruderConfig cfg ) override { - typedef Arrangement_2::Traits_2 AT; float snap_tolerance = std::pow(10,-cfg.snap_tolerance_exp); // assume we have only one unbounded faces that just has the building footprint as a hole auto unbounded_face = arr.unbounded_face(); - unbounded_face->data().elevation_70p=floor_elevation; - unbounded_face->data().elevation_97p=floor_elevation; + unbounded_face->data().elevation_70p=elevation_provider.get_percentile(0.7); + unbounded_face->data().elevation_97p=elevation_provider.get_percentile(0.97); // floor if (cfg.do_floor) { @@ -112,8 +111,10 @@ namespace roofer::detection { auto he = *floorpart_; auto first = he; do { - if(CGAL::squared_distance(he->source()->point(), he->target()->point()) > snap_tolerance) - floor.push_back(v2p(he->source(), floor_elevation)); + if(CGAL::squared_distance(he->source()->point(), he->target()->point()) > snap_tolerance) { + float pt_elevation = elevation_provider.get(he->source()->point()); + floor.push_back(v2p(he->source(), pt_elevation)); + } he = he->next(); } while(he!=first); @@ -133,8 +134,10 @@ namespace roofer::detection { auto he = face->outer_ccb(); auto first = he; do { - if(CGAL::squared_distance(he->source()->point(), he->target()->point()) > snap_tolerance) - hole.push_back(v2p(he->source(), floor_elevation)); + if(CGAL::squared_distance(he->source()->point(), he->target()->point()) > snap_tolerance) { + float pt_elevation = elevation_provider.get(he->source()->point()); + hole.push_back(v2p(he->source(), pt_elevation)); + } he = he->next(); } while(he!=first); @@ -157,7 +160,7 @@ namespace roofer::detection { return; } } - + // compute all heights for each vertex std::unordered_map> vertex_columns; @@ -176,13 +179,13 @@ namespace roofer::detection { } else { if (cfg.lod1_extrude_to_max_) h = f->data().elevation_97p; - else + else h = f->data().elevation_70p; } } else if (f->data().in_footprint) { h = cfg.nodata_elevation; } else { - h = floor_elevation; + h = elevation_provider.get(p); } heights.push_back(std::make_pair(h, f)); } while (++he!=first); @@ -240,10 +243,12 @@ namespace roofer::detection { // // set base (ground) elevation to vertices adjacent to a face oustide the building fp int part_id; if (fp_a && !fp_b) { - h1b=h2b=floor_elevation; + h1b = elevation_provider.get(p1); + h2b = elevation_provider.get(p2); part_id = f_a->data().part_id; } else if (!fp_a && fp_b) { - h1a=h2a=floor_elevation; + h1a = elevation_provider.get(p1); + h2a = elevation_provider.get(p2); part_id = f_b->data().part_id; } else{ // both sides have the same part_id part_id = f_b->data().part_id; @@ -296,7 +301,7 @@ namespace roofer::detection { // EPECK::Point_2 px_2d(px->x(),px->y()); // arr.split_edge(edge, AT::Segment_2(p1,px_2d), AT::Segment_2(px_2d,p2)); // if (result) { - // auto px = ) + // auto px = ) // } wall_face_1.push_back(v2p(v1,h1b)); @@ -320,7 +325,7 @@ namespace roofer::detection { labels.push_back(wall_label); mesh.push_polygon(wall_face_2, wall_label); // mesh.push_attribute("surface_type", wall_label); - } else + } else if ((h1a>h1b) and (h2ah2a) and (h1a==h1b)) { wall_face_1.push_back(v2p(v2,h2a)); // v2_other asc @@ -441,6 +446,19 @@ namespace roofer::detection { } } + + /* + * Convenience overload when base_elevation is passed + */ + void compute( + Arrangement_2& arr, + float base_elevation, + ArrangementExtruderConfig cfg + ) override { + auto const_elevation_provider_ptr = createElevationProvider(base_elevation); + compute(arr, *const_elevation_provider_ptr, cfg); + } + }; std::unique_ptr createArrangementExtruder() { diff --git a/src/core/reconstruction/ArrangementOptimiser.cpp b/src/core/reconstruction/ArrangementOptimiser.cpp index 3e2af687..a413c9b9 100644 --- a/src/core/reconstruction/ArrangementOptimiser.cpp +++ b/src/core/reconstruction/ArrangementOptimiser.cpp @@ -11,6 +11,8 @@ #include +namespace roofer::reconstruction { + class FootprintGraph { public: typedef typename Arrangement_2::Face_handle vertex_descriptor; @@ -48,18 +50,6 @@ }; }; - namespace boost { - template<> struct graph_traits { - typedef typename Arrangement_2::Face_handle vertex_descriptor; - typedef typename Arrangement_2::Halfedge_handle edge_descriptor; - typedef boost::disallow_parallel_edge_tag edge_parallel_category; - typedef boost::edge_list_graph_tag traversal_category; - typedef boost::directed_tag directed_category; - typedef FootprintGraph::vertex_container::size_type vertices_size_type; - typedef FootprintGraph::edge_container::size_type edges_size_type; - }; - } - // A property map that reads/writes the information to/from the extended // face. class Vertex_label_cost_property_map { @@ -78,7 +68,7 @@ key_type key, value_type val) { key->data().vertex_label_cost=val; } }; - // A property map that reads/writes the information to/from the extended + // A property map that reads/writes the information to/from the extended // face. class Vertex_label_property_map { public: @@ -96,7 +86,7 @@ key_type key, value_type val) { key->data().label=val; } }; - // A property map that reads/writes the information to/from the extended + // A property map that reads/writes the information to/from the extended // face. class Vertex_index_map { public: @@ -110,7 +100,7 @@ friend reference get(const Vertex_index_map&, key_type key) { return key->data().v_index; } }; - // A property map that reads/writes the information to/from the extended + // A property map that reads/writes the information to/from the extended // edge. class Edge_weight_property_map { public: @@ -129,8 +119,21 @@ { key->data().edge_weight = val; } }; +} // namespace roofer + +namespace boost { + template<> struct graph_traits { + typedef typename roofer::Arrangement_2::Face_handle vertex_descriptor; + typedef typename roofer::Arrangement_2::Halfedge_handle edge_descriptor; + typedef boost::disallow_parallel_edge_tag edge_parallel_category; + typedef boost::edge_list_graph_tag traversal_category; + typedef boost::directed_tag directed_category; + typedef roofer::reconstruction::FootprintGraph::vertex_container::size_type vertices_size_type; + typedef roofer::reconstruction::FootprintGraph::edge_container::size_type edges_size_type; + }; +} -namespace roofer::detection { +namespace roofer::reconstruction { inline double edge_length(const Arrangement_2::Halfedge_handle& e) { diff --git a/src/core/reconstruction/ArrangementSnapper.cpp b/src/core/reconstruction/ArrangementSnapper.cpp index 6b658922..e5a15790 100644 --- a/src/core/reconstruction/ArrangementSnapper.cpp +++ b/src/core/reconstruction/ArrangementSnapper.cpp @@ -26,7 +26,9 @@ #include -namespace roofer::detection { +namespace roofer::reconstruction { + +namespace arragementsnapper { typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Exact_predicates_inexact_constructions_kernel Epeck; @@ -517,8 +519,10 @@ namespace roofer::detection { } }; +} // namespace arragementsnapper + std::unique_ptr createArrangementSnapper() { - return std::make_unique(); + return std::make_unique(); } -} \ No newline at end of file +} // namespace roofer::detection \ No newline at end of file diff --git a/src/core/reconstruction/CMakeLists.txt b/src/core/reconstruction/CMakeLists.txt index 19d9d50a..2d2fdf49 100644 --- a/src/core/reconstruction/CMakeLists.txt +++ b/src/core/reconstruction/CMakeLists.txt @@ -6,6 +6,7 @@ set(LIBRARY_SOURCES "ArrangementExtruder.cpp" "ArrangementOptimiser.cpp" "ArrangementSnapper.cpp" + "ElevationProvider.cpp" "cdt_util.cpp" "LineDetector.cpp" "LineDetectorBase.cpp" @@ -24,6 +25,7 @@ set(LIBRARY_HEADERS "${ROOFER_INCLUDE_DIR}/roofer/reconstruction/ArrangementExtruder.hpp" "${ROOFER_INCLUDE_DIR}/roofer/reconstruction/ArrangementOptimiser.hpp" "${ROOFER_INCLUDE_DIR}/roofer/reconstruction/ArrangementSnapper.hpp" + "${ROOFER_INCLUDE_DIR}/roofer/reconstruction/ElevationProvider.hpp" "${ROOFER_INCLUDE_DIR}/roofer/reconstruction/cdt_util.hpp" "${ROOFER_INCLUDE_DIR}/roofer/reconstruction/cgal_shared_definitions.hpp" "${ROOFER_INCLUDE_DIR}/roofer/reconstruction/LineDetector.hpp" diff --git a/src/core/reconstruction/ElevationProvider.cpp b/src/core/reconstruction/ElevationProvider.cpp new file mode 100644 index 00000000..d1047012 --- /dev/null +++ b/src/core/reconstruction/ElevationProvider.cpp @@ -0,0 +1,82 @@ +// This file is part of gfp-building-reconstruction +// Copyright (C) 2018-2022 Ravi Peters + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +namespace roofer::reconstruction { + + struct ConstantElevationProvider : public ElevationProvider { + const float floor_elevation_; + + ConstantElevationProvider(const float floor_elevation) + : floor_elevation_(floor_elevation) {}; + + virtual float get(const Point_2 /* pt */) const override { + return floor_elevation_; + } + + virtual float get_percentile(float /* percentile */) const override { + return floor_elevation_; + } + + }; + + struct InterpolatedElevationProvider : public ElevationProvider { + std::shared_ptr base_cdt_ptr_; + + InterpolatedElevationProvider(const proj_tri_util::DT& base_cdt) + : base_cdt_ptr_(std::make_shared(base_cdt)) {}; + + virtual float get(const Point_2 pt) const override { + return proj_tri_util::interpolate_from_cdt(pt, *base_cdt_ptr_); + } + + virtual float get_percentile(float percentile) const override { + std::vector elevations; + // insert vertex elevation into the sorted vector + auto insertSorted = [&elevations](float elevation) { + auto position = + std::lower_bound(elevations.begin(), elevations.end(), elevation); + elevations.insert(position, elevation); + }; + // iterate over all vertices and insert elevation + for (auto& pt : base_cdt_ptr_->points()) + insertSorted(pt.z()); + // return percentile + return compute_percentile(elevations, percentile); + } + + private: + float compute_percentile(std::vector& z_vec, float percentile) const { + assert(percentile<=1.); + assert(percentile>=0.); + size_t n = (z_vec.size()-1) * percentile; + std::nth_element(z_vec.begin(), z_vec.begin()+n, z_vec.end()); + return z_vec[n]; + } + + }; + + std::unique_ptr createElevationProvider(const float floor_elevation) { + return std::make_unique(floor_elevation); + } + + std::unique_ptr createElevationProvider(const proj_tri_util::DT& base_cdt) { + return std::make_unique(base_cdt); + } + +} // namespace roofer::detection diff --git a/src/core/reconstruction/LineDetector.cpp b/src/core/reconstruction/LineDetector.cpp index fb2ee09f..880a1825 100644 --- a/src/core/reconstruction/LineDetector.cpp +++ b/src/core/reconstruction/LineDetector.cpp @@ -3,7 +3,7 @@ #include #include -namespace roofer::detection { +namespace roofer::reconstruction { typedef std::pair IDPair; struct Cmp { @@ -13,7 +13,7 @@ namespace roofer::detection { }; // typedef std::map RingSegMap; - inline size_t detect_lines_ring(linedect::LineDetector& LD, const Plane& plane, SegmentCollection& segments_out, roofer::detection::LineDetectorConfig& cfg) { + inline size_t detect_lines_ring(linedect::LineDetector& LD, const Plane& plane, SegmentCollection& segments_out, roofer::reconstruction::LineDetectorConfig& cfg) { LD.dist_thres = cfg.dist_thres * cfg.dist_thres; LD.N = cfg.k; auto& c_upper = cfg.min_cnt_range.second; @@ -94,7 +94,7 @@ namespace roofer::detection { } } if (cfg.perform_chaining) { - std::vector prechain_segments; + std::vector prechain_segments; std::vector idx; size_t idcnt=0; for (auto& [i0,i1] : sorted_segments) { // segments_out.push_back( LD.project(i0, i1) ); @@ -103,7 +103,7 @@ namespace roofer::detection { } // TODO: chain the ring? for better regularisation results SegmentCollection new_ring; - auto chained_ring_pts = linereg::chain_ring(idx, SCK::Plane_3(plane.a(), plane.b(), plane.c(), plane.d()), prechain_segments, cfg.snap_threshold, cfg.line_extend); + auto chained_ring_pts = linereg::chain_ring(idx, linedect::SCK::Plane_3(plane.a(), plane.b(), plane.c(), plane.d()), prechain_segments, cfg.snap_threshold, cfg.line_extend); if (chained_ring_pts.size() > 2) { auto first = chained_ring_pts.begin(); diff --git a/src/core/reconstruction/LineDetectorBase.cpp b/src/core/reconstruction/LineDetectorBase.cpp index 6f6a4c26..4075bb74 100644 --- a/src/core/reconstruction/LineDetectorBase.cpp +++ b/src/core/reconstruction/LineDetectorBase.cpp @@ -18,221 +18,222 @@ #include #include -using namespace std; -using namespace linedect; - -LineDetector::LineDetector(vector &points) { - auto size = points.size(); - indexed_points.reserve(size); - size_t i=0; - for(auto p: points) - indexed_points.push_back(std::make_pair(p,i++)); - point_segment_idx.resize(size, 0); - // point_seed_flags.resize(size, true); - Tree tree; - tree.insert(indexed_points.begin(), indexed_points.end()); - neighbours.resize(size); - for(auto pi : indexed_points){ - auto p = pi.first; - neighbours[pi.second].reserve(N); - Neighbor_search search(tree, p, N); - for (auto neighbour : search) { - neighbours[pi.second].push_back(neighbour.first.second); +namespace roofer::linedect { + using namespace std; + + LineDetector::LineDetector(vector &points) { + auto size = points.size(); + indexed_points.reserve(size); + size_t i=0; + for(auto p: points) + indexed_points.push_back(std::make_pair(p,i++)); + point_segment_idx.resize(size, 0); + // point_seed_flags.resize(size, true); + Tree tree; + tree.insert(indexed_points.begin(), indexed_points.end()); + neighbours.resize(size); + for(auto pi : indexed_points){ + auto p = pi.first; + neighbours[pi.second].reserve(N); + Neighbor_search search(tree, p, N); + for (auto neighbour : search) { + neighbours[pi.second].push_back(neighbour.first.second); + } } } -} -LineDetector::LineDetector(vector &points, vector> neighbours):neighbours(neighbours) { - auto size = points.size(); - indexed_points.reserve(size); - size_t i=0; - for(auto p: points) - indexed_points.push_back(std::make_pair(p,i++)); - point_segment_idx.resize(size, 0); - // point_seed_flags.resize(size, true); -} + LineDetector::LineDetector(vector &points, vector> neighbours):neighbours(neighbours) { + auto size = points.size(); + indexed_points.reserve(size); + size_t i=0; + for(auto p: points) + indexed_points.push_back(std::make_pair(p,i++)); + point_segment_idx.resize(size, 0); + // point_seed_flags.resize(size, true); + } -vector LineDetector::get_point_indices(size_t shape_id) { - vector result; - for (auto pi:indexed_points){ - auto idx = pi.second; - if (point_segment_idx[idx] == shape_id) - result.push_back(idx); + vector LineDetector::get_point_indices(size_t shape_id) { + vector result; + for (auto pi:indexed_points){ + auto idx = pi.second; + if (point_segment_idx[idx] == shape_id) + result.push_back(idx); + } + return result; } - return result; -} -roofer::Segment LineDetector::project(const size_t i1, const size_t i2) { - const auto& l = segment_shapes[point_segment_idx[i1]]; - const auto& p1 = indexed_points[i1].first; - const auto& p2 = indexed_points[i2].first; - auto p1n = l.projection(p1); - auto p2n = l.projection(p2); - return roofer::Segment( - roofer::arr3f{float(p1n.x()), float(p1n.y()), float(p1n.z())}, - roofer::arr3f{float(p2n.x()), float(p2n.y()), float(p2n.z())} - ); -} -SCK::Segment_3 LineDetector::project_cgal(const size_t i1, const size_t i2, float extension) { - const auto& l = segment_shapes[point_segment_idx[i1]]; - const auto& p1 = indexed_points[i1].first; - const auto& p2 = indexed_points[i2].first; - auto p1n = l.projection(p1); - auto p2n = l.projection(p2); - // extend the linesegment a bit in both directions - auto v = (p2n-p1n); - v = v/CGAL::sqrt(v.squared_length()); - p1n = p1n - v*extension; - p2n = p2n + v*extension; - return SCK::Segment_3( - SCK::Point_3(CGAL::to_double(p1n.x()), CGAL::to_double(p1n.y()), CGAL::to_double(p1n.z())), - SCK::Point_3(CGAL::to_double(p2n.x()), CGAL::to_double(p2n.y()), CGAL::to_double(p2n.z())) - ); -} + roofer::Segment LineDetector::project(const size_t i1, const size_t i2) { + const auto& l = segment_shapes[point_segment_idx[i1]]; + const auto& p1 = indexed_points[i1].first; + const auto& p2 = indexed_points[i2].first; + auto p1n = l.projection(p1); + auto p2n = l.projection(p2); + return roofer::Segment( + roofer::arr3f{float(p1n.x()), float(p1n.y()), float(p1n.z())}, + roofer::arr3f{float(p2n.x()), float(p2n.y()), float(p2n.z())} + ); + } + SCK::Segment_3 LineDetector::project_cgal(const size_t i1, const size_t i2, float extension) { + const auto& l = segment_shapes[point_segment_idx[i1]]; + const auto& p1 = indexed_points[i1].first; + const auto& p2 = indexed_points[i2].first; + auto p1n = l.projection(p1); + auto p2n = l.projection(p2); + // extend the linesegment a bit in both directions + auto v = (p2n-p1n); + v = v/CGAL::sqrt(v.squared_length()); + p1n = p1n - v*extension; + p2n = p2n + v*extension; + return SCK::Segment_3( + SCK::Point_3(CGAL::to_double(p1n.x()), CGAL::to_double(p1n.y()), CGAL::to_double(p1n.z())), + SCK::Point_3(CGAL::to_double(p2n.x()), CGAL::to_double(p2n.y()), CGAL::to_double(p2n.z())) + ); + } -size_t LineDetector::get_bounded_edges(roofer::SegmentCollection& edges) { - std::vector id_mins; - std::map ordered_segments; - for(auto seg: segment_shapes){ - auto l = seg.second; - auto l_idx = get_point_indices(seg.first); - // std::cout << l.direction() << ", #Pts: " << l_idx.size() < maxpl) { - maxpl=pl; - maxpl_id = id; + size_t LineDetector::get_bounded_edges(roofer::SegmentCollection& edges) { + std::vector id_mins; + std::map ordered_segments; + for(auto seg: segment_shapes){ + auto l = seg.second; + auto l_idx = get_point_indices(seg.first); + // std::cout << l.direction() << ", #Pts: " << l_idx.size() < maxpl) { + maxpl=pl; + maxpl_id = id; + } } + // keep track of lowest point id + id_min = std::min(id_min, id); } - // keep track of lowest point id - id_min = std::min(id_min, id); + Point p0,p1; + if (minpl_id < maxpl_id) { + p0 = (point_on_line + minpl*l_normal); + p1 = (point_on_line + maxpl*l_normal); + } else { + p1 = (point_on_line + minpl*l_normal); + p0 = (point_on_line + maxpl*l_normal); + } + ordered_segments[id_min] = roofer::Segment(); + ordered_segments[id_min][0] = { + float(p0.x()), + float(p0.y()), + float(p0.z()) + }; + ordered_segments[id_min][1] = { + float(p1.x()), + float(p1.y()), + float(p1.z()) + }; } - Point p0,p1; - if (minpl_id < maxpl_id) { - p0 = (point_on_line + minpl*l_normal); - p1 = (point_on_line + maxpl*l_normal); - } else { - p1 = (point_on_line + minpl*l_normal); - p0 = (point_on_line + maxpl*l_normal); + // deliver the edges in order + for (auto& kv : ordered_segments) { + edges.push_back(kv.second); } - ordered_segments[id_min] = roofer::Segment(); - ordered_segments[id_min][0] = { - float(p0.x()), - float(p0.y()), - float(p0.z()) - }; - ordered_segments[id_min][1] = { - float(p1.x()), - float(p1.y()), - float(p1.z()) - }; - } - // deliver the edges in order - for (auto& kv : ordered_segments) { - edges.push_back(kv.second); + return ordered_segments.size(); } - return ordered_segments.size(); -} -inline Line LineDetector::fit_line(vector& neighbour_idx){ - vector neighbor_points; - for (auto neighbor_id: neighbour_idx){ - neighbor_points.push_back(indexed_points[neighbor_id].first); + inline Line LineDetector::fit_line(vector& neighbour_idx){ + vector neighbor_points; + for (auto neighbor_id: neighbour_idx){ + neighbor_points.push_back(indexed_points[neighbor_id].first); + } + Line line; + linear_least_squares_fitting_3(neighbor_points.begin(),neighbor_points.end(),line,CGAL::Dimension_tag<0>()); + return line; } - Line line; - linear_least_squares_fitting_3(neighbor_points.begin(),neighbor_points.end(),line,CGAL::Dimension_tag<0>()); - return line; -} - -std::vector LineDetector::detect(){ - // seed generation - typedef pair index_dist_pair; - auto cmp = [](index_dist_pair left, index_dist_pair right) {return left.second < right.second;}; - priority_queue, decltype(cmp)> pq(cmp); - // size_t i=0; - for(auto pi : indexed_points){ - if (point_segment_idx[pi.second]==0) { - auto p = pi.first; - auto line = fit_line(neighbours[pi.second]); - auto line_dist = CGAL::squared_distance(line, p); - pq.push(index_dist_pair(pi.second, line_dist)); + std::vector LineDetector::detect(){ + // seed generation + typedef pair index_dist_pair; + auto cmp = [](index_dist_pair left, index_dist_pair right) {return left.second < right.second;}; + priority_queue, decltype(cmp)> pq(cmp); + + // size_t i=0; + for(auto pi : indexed_points){ + if (point_segment_idx[pi.second]==0) { + auto p = pi.first; + auto line = fit_line(neighbours[pi.second]); + auto line_dist = CGAL::squared_distance(line, p); + pq.push(index_dist_pair(pi.second, line_dist)); + } } - } - std::vector new_regions; + std::vector new_regions; - // region growing from seed points - while(pq.size()>0) { - auto idx = pq.top().first; pq.pop(); - // if (point_seed_flags[idx]){ - if (point_segment_idx[idx]==0){ - if (grow_region(idx)) - new_regions.push_back(region_counter); - region_counter++; + // region growing from seed points + while(pq.size()>0) { + auto idx = pq.top().first; pq.pop(); + // if (point_seed_flags[idx]){ + if (point_segment_idx[idx]==0){ + if (grow_region(idx)) + new_regions.push_back(region_counter); + region_counter++; + } } + return new_regions; } - return new_regions; -} -inline bool LineDetector::valid_candidate(Line &line, Point &p) { - return CGAL::squared_distance(line, p) < dist_thres; -} + inline bool LineDetector::valid_candidate(Line &line, Point &p) { + return CGAL::squared_distance(line, p) < dist_thres; + } -bool LineDetector::grow_region(size_t seed_idx) { - auto p = indexed_points[seed_idx]; - auto line = fit_line(neighbours[seed_idx]); - segment_shapes[region_counter] = line; - - vector points_in_region; - vector idx_in_region; - stack candidates; - candidates.push(seed_idx); - point_segment_idx[seed_idx] = region_counter; - points_in_region.push_back(p.first); - idx_in_region.push_back(p.second); - - while (candidates.size()>0){ - auto candidate_id = candidates.top(); candidates.pop(); - auto cp = indexed_points[candidate_id].first; - for (auto n_id: neighbours[candidate_id]){ - if (point_segment_idx[n_id]!=0) - continue; - // point_seed_flags[n_id] = false; // this point can no longer be used as seed - if (valid_candidate(segment_shapes[region_counter], indexed_points[n_id].first)){ - point_segment_idx[n_id] = region_counter; - candidates.push(n_id); - points_in_region.push_back(indexed_points[n_id].first); - idx_in_region.push_back(n_id); - Line line; - linear_least_squares_fitting_3(points_in_region.begin(),points_in_region.end(),line,CGAL::Dimension_tag<0>()); - segment_shapes[region_counter] = line; - } + bool LineDetector::grow_region(size_t seed_idx) { + auto p = indexed_points[seed_idx]; + auto line = fit_line(neighbours[seed_idx]); + segment_shapes[region_counter] = line; + + vector points_in_region; + vector idx_in_region; + stack candidates; + candidates.push(seed_idx); + point_segment_idx[seed_idx] = region_counter; + points_in_region.push_back(p.first); + idx_in_region.push_back(p.second); + + while (candidates.size()>0){ + auto candidate_id = candidates.top(); candidates.pop(); + auto cp = indexed_points[candidate_id].first; + for (auto n_id: neighbours[candidate_id]){ + if (point_segment_idx[n_id]!=0) + continue; + // point_seed_flags[n_id] = false; // this point can no longer be used as seed + if (valid_candidate(segment_shapes[region_counter], indexed_points[n_id].first)){ + point_segment_idx[n_id] = region_counter; + candidates.push(n_id); + points_in_region.push_back(indexed_points[n_id].first); + idx_in_region.push_back(n_id); + Line line; + linear_least_squares_fitting_3(points_in_region.begin(),points_in_region.end(),line,CGAL::Dimension_tag<0>()); + segment_shapes[region_counter] = line; + } + } } + // undo region if it doesn't satisfy quality criteria + if (points_in_region.size() #include -namespace roofer::detection { +namespace roofer::reconstruction { class LineRegulariser : public LineRegulariserInterface { diff --git a/src/core/reconstruction/LineRegulariserBase.cpp b/src/core/reconstruction/LineRegulariserBase.cpp index f1ed43f0..c9cbd8dd 100644 --- a/src/core/reconstruction/LineRegulariserBase.cpp +++ b/src/core/reconstruction/LineRegulariserBase.cpp @@ -16,7 +16,7 @@ #include #include -namespace linereg { +namespace roofer::linereg { double calc_mean_angle(const std::vector& lines) { // length-weighted mean angle diff --git a/src/core/reconstruction/MeshTriangulatorLegacy.cpp b/src/core/reconstruction/MeshTriangulatorLegacy.cpp index a6a2b6ee..9ab2c41f 100644 --- a/src/core/reconstruction/MeshTriangulatorLegacy.cpp +++ b/src/core/reconstruction/MeshTriangulatorLegacy.cpp @@ -3,12 +3,12 @@ #include #include -namespace roofer::detection { - +namespace roofer::reconstruction { + namespace tri = tri_util; - + typedef CGAL::Cartesian AK; - typedef CGAL::Polygon_2 Polygon_2; + typedef CGAL::Polygon_2 iPolygon_2; typedef CGAL::Plane_3 Plane_3; AK::Vector_3 calculate_normal(const LinearRing& ring) @@ -36,8 +36,8 @@ namespace roofer::detection { return sum/6; } - Polygon_2 project(roofer::vec3f& ring, Plane_3& plane) { - Polygon_2 poly_2d; + iPolygon_2 project(roofer::vec3f& ring, Plane_3& plane) { + iPolygon_2 poly_2d; for (auto& p : ring) { poly_2d.push_back(plane.to_2d(tri::K::Point_3(p[0], p[1], p[2]))); } @@ -63,10 +63,10 @@ namespace roofer::detection { class MeshTriangulatorLegacy : public MeshTriangulatorInterface{ void triangulate_polygon( - const LinearRing& poly_, - vec3f& normals, - TriangleCollection& triangles, - size_t& ring_id, + const LinearRing& poly_, + vec3f& normals, + TriangleCollection& triangles, + size_t& ring_id, vec1i& ring_ids, const MeshTriangulatorConfig& cfg ) { @@ -89,7 +89,7 @@ namespace roofer::detection { } auto& p0 = poly[0]; Plane_3 plane(tri::K::Point_3(p0[0], p0[1], p0[2]), tri::K::Vector_3(normal.x(), normal.y(), normal.z())); - + // project and triangulate tri::CDT triangulation; // Polygon_2 poly_2d = project(poly, plane); @@ -128,8 +128,8 @@ namespace roofer::detection { Triangle triangle; triangle = { - fit->vertex(0)->info().point, - fit->vertex(1)->info().point, + fit->vertex(0)->info().point, + fit->vertex(1)->info().point, fit->vertex(2)->info().point }; for (size_t j = 0; j < 3; ++j) @@ -146,13 +146,13 @@ namespace roofer::detection { public: void compute( - const std::vector& meshes, + const std::vector& meshes, MeshTriangulatorConfig cfg ) override { typedef uint32_t N; roofer::MultiTriangleCollection multitranglecol; - + for (size_t mi = 0; mi < meshes.size(); ++mi) { auto mesh = meshes[mi]; TriangleCollection mesh_triangles; @@ -176,7 +176,7 @@ namespace roofer::detection { } void compute( - const std::vector& polygons, + const std::vector& polygons, MeshTriangulatorConfig cfg ) override { // const auto &values_in = input("valuesf").get(); @@ -193,7 +193,7 @@ namespace roofer::detection { } void compute( - const std::unordered_map& multisolid, + const std::unordered_map& multisolid, MeshTriangulatorConfig cfg ) override { // const auto &values_in = input("valuesf").get(); @@ -241,7 +241,7 @@ namespace roofer::detection { // lr.push_back(triangle[2]); // mesh.push_polygon( lr, std::get( attrmap[i]["labels"][j++] ) ); // } - + // meshmap[mtc.building_part_ids_[i++]] = mesh; // } // output("meshmap").set(meshmap); @@ -252,4 +252,5 @@ namespace roofer::detection { std::unique_ptr createMeshTriangulatorLegacy() { return std::make_unique(); } -} // namespace roofer::nodes::stepedge \ No newline at end of file + +} // namespace roofer::detection \ No newline at end of file diff --git a/src/core/reconstruction/PlaneDetector.cpp b/src/core/reconstruction/PlaneDetector.cpp index 25586692..fa2be429 100644 --- a/src/core/reconstruction/PlaneDetector.cpp +++ b/src/core/reconstruction/PlaneDetector.cpp @@ -43,6 +43,8 @@ #include #include +namespace roofer { + // Point with normal vector stored in a std::pair. typedef boost::tuple PNL; typedef CGAL::Nth_of_tuple_property_map<0, PNL> Point_map; @@ -112,7 +114,7 @@ float compute_percentile(std::vector& z_vec, float percentile) { return z_vec[n]; } -namespace roofer::detection { +namespace reconstruction { // Concurrency #ifdef CGAL_LINKED_WITH_TBB @@ -488,4 +490,6 @@ std::unique_ptr createPlaneDetector() { return std::make_unique(); }; -} \ No newline at end of file +} // namespace detection + +} // namespace roofer \ No newline at end of file diff --git a/src/core/reconstruction/PlaneDetectorRANSAC.cpp b/src/core/reconstruction/PlaneDetectorRANSAC.cpp index a2e6d260..9d61e48e 100644 --- a/src/core/reconstruction/PlaneDetectorRANSAC.cpp +++ b/src/core/reconstruction/PlaneDetectorRANSAC.cpp @@ -13,7 +13,7 @@ #include #include -namespace roofer::detection { +namespace roofer::reconstruction { struct PlaneDetectorRANSAC : public ShapeDetectorInterface { int metrics_normal_k = 5; diff --git a/src/core/reconstruction/PlaneIntersector.cpp b/src/core/reconstruction/PlaneIntersector.cpp index 43fd78b4..5eb0f9d9 100644 --- a/src/core/reconstruction/PlaneIntersector.cpp +++ b/src/core/reconstruction/PlaneIntersector.cpp @@ -2,7 +2,7 @@ #include -namespace roofer::detection { +namespace roofer::reconstruction { class PlaneIntersector : public PlaneIntersectorInterface { diff --git a/src/core/reconstruction/SegmentRasteriser.cpp b/src/core/reconstruction/SegmentRasteriser.cpp index ffa312b0..c0d210c8 100644 --- a/src/core/reconstruction/SegmentRasteriser.cpp +++ b/src/core/reconstruction/SegmentRasteriser.cpp @@ -1,7 +1,7 @@ #include // #include "spdlog/spdlog.h" -namespace roofer::detection { +namespace roofer::reconstruction { class SegmentRasteriser : public SegmentRasteriserInterface { diff --git a/src/core/reconstruction/SimplePolygonExtruder.cpp b/src/core/reconstruction/SimplePolygonExtruder.cpp index de6a3b20..e6689e04 100644 --- a/src/core/reconstruction/SimplePolygonExtruder.cpp +++ b/src/core/reconstruction/SimplePolygonExtruder.cpp @@ -2,7 +2,7 @@ #include -namespace roofer::detection { +namespace roofer::reconstruction { class SimplePolygonExtruder : public SimplePolygonExtruderInterface{ diff --git a/src/core/reconstruction/cdt_util.cpp b/src/core/reconstruction/cdt_util.cpp index 9213e69a..0e9c6bc9 100644 --- a/src/core/reconstruction/cdt_util.cpp +++ b/src/core/reconstruction/cdt_util.cpp @@ -15,6 +15,14 @@ // along with this program. If not, see . #include +#include +#include +//todo temp for testing +#include + + +namespace roofer { + namespace tri_util { void mark_domains(CDT& ct, @@ -99,4 +107,92 @@ namespace tri_util { return triangulation; } -} \ No newline at end of file + +} // namespace tri_util + +namespace proj_tri_util { + DT cdt_from_linearing(const roofer::LinearRing& poly) { + // store roofer's LinearRing as CGAL Polygon_2 with proj traits + typedef CGAL::Polygon_2 Polygon_3; + typedef Projection_traits::Point_2 Point_3; + DT cdt; + for (auto& p : poly) + cdt.insert(Point_3(p[0], p[1], p[2])); + for (auto& ring : poly.interior_rings()) + for (auto& p : ring) cdt.insert(Point_3(p[0], p[1], p[2])); + + return cdt; + } + + float interpolate_from_cdt(const Point_2& p, const DT& cdt) { + DT::Face_handle fh = nullptr; + DT::Point pt(CGAL::to_double(p.x()), CGAL::to_double(p.y()), 0); + + DT::Locate_type lt; + int li; + fh = cdt.locate(pt, lt, li, fh); + if (lt == DT::OUTSIDE_CONVEX_HULL) { + // borderline case when point is on the edge of the convex hull + std::vector interp_edge; + // the point landed on infinite face on the other side of the edge + if (!cdt.is_infinite(fh->vertex(0))) interp_edge.push_back(fh->vertex(0)->point()); + if (!cdt.is_infinite(fh->vertex(1))) interp_edge.push_back(fh->vertex(1)->point()); + if (!cdt.is_infinite(fh->vertex(2))) interp_edge.push_back(fh->vertex(2)->point()); + assert(interp_edge.size() == 2); + + EPICK::Point_2 pt1(interp_edge[0].x(), interp_edge[0].y()); + EPICK::Point_2 pt2(interp_edge[1].x(), interp_edge[1].y()); + EPICK::Point_2 pt_int(pt.x(), pt.y()); + + // approximate with 1D linear interpolation along the neighbouring edge + double g1 = CGAL::approximate_sqrt(CGAL::squared_distance(pt1, pt_int)) + / CGAL::approximate_sqrt(CGAL::squared_distance(pt1, pt2)); + + float h_int = interp_edge[0].z() + g1 * (interp_edge[1].z() - interp_edge[0].z()); + + return h_int; + } + + std::vector coords; + CGAL::Barycentric_coordinates::triangle_coordinates_2( + EPICK::Point_2(fh->vertex(0)->point().x(), fh->vertex(0)->point().y()), + EPICK::Point_2(fh->vertex(1)->point().x(), fh->vertex(1)->point().y()), + EPICK::Point_2(fh->vertex(2)->point().x(), fh->vertex(2)->point().y()), + EPICK::Point_2(pt.x(), pt.y()), + std::back_inserter(coords) + ); + + float h = 0; + for (int i = 0; i < 3; ++i) { + + h += fh->vertex(i)->point().z() * coords[i]; + } + return h; + } + + //todo temp function for testing + void write_cdt_to_obj(const DT& cdt, const std::string& filename) { + typedef CGAL::Surface_mesh Mesh; + std::map indices; + std::vector mesh_vertex; + std::vector face_index; + mesh_vertex.reserve(cdt.number_of_vertices()); + int counter = 0; + Mesh mesh; + for (const auto& it : cdt.finite_vertex_handles()) { + mesh_vertex.emplace_back(mesh.add_vertex(it->point())); + // outstream << it->point() << std::endl; + indices.insert(std::pair(it, counter++)); + } + for (const auto& it : cdt.finite_face_handles()) { + int v1 = indices[it->vertex(0)]; + int v2 = indices[it->vertex(1)]; + int v3 = indices[it->vertex(2)]; + mesh.add_face(mesh_vertex[v1], mesh_vertex[v2], mesh_vertex[v3]); + } + CGAL::IO::write_OBJ(filename, mesh); + } + +} // namespace proj_tri_util + +} //namespace roofer \ No newline at end of file diff --git a/src/extra/io/CityJsonWriter.cpp b/src/extra/io/CityJsonWriter.cpp index 4111b3c7..666b4cf3 100644 --- a/src/extra/io/CityJsonWriter.cpp +++ b/src/extra/io/CityJsonWriter.cpp @@ -5,10 +5,10 @@ #include #include -namespace fs = std::filesystem; - namespace roofer::io { + namespace fs = std::filesystem; + class CityJsonWriter : public CityJsonWriterInterface { template void add_vertices_ring(std::map& vertex_map, std::vector& vertex_vec, std::set& vertex_set, const T& ring, Box& bbox) { size_t v_cntr = vertex_vec.size(); @@ -400,7 +400,7 @@ namespace roofer::io { } }; - std::unique_ptr createCityJsonWriter(projHelperInterface& pjh) { + std::unique_ptr createCityJsonWriter(roofer::misc::projHelperInterface& pjh) { return std::make_unique(pjh); }; } \ No newline at end of file diff --git a/src/extra/io/PointCloudReaderLASlib.cpp b/src/extra/io/PointCloudReaderLASlib.cpp index 3de451f2..cc96bc60 100644 --- a/src/extra/io/PointCloudReaderLASlib.cpp +++ b/src/extra/io/PointCloudReaderLASlib.cpp @@ -5,7 +5,7 @@ #include #include -namespace roofer { +namespace roofer::io { class PointCloudReaderLASlib : public PointCloudReaderInterface { @@ -120,7 +120,7 @@ class PointCloudReaderLASlib : public PointCloudReaderInterface { } }; -std::unique_ptr createPointCloudReaderLASlib(projHelperInterface& pjh) { +std::unique_ptr createPointCloudReaderLASlib(roofer::misc::projHelperInterface& pjh) { return std::make_unique(pjh); }; diff --git a/src/extra/io/PointCloudWriterLASlib.cpp b/src/extra/io/PointCloudWriterLASlib.cpp index da1b17bd..5bb72027 100644 --- a/src/extra/io/PointCloudWriterLASlib.cpp +++ b/src/extra/io/PointCloudWriterLASlib.cpp @@ -6,9 +6,10 @@ #include #include -namespace fs = std::filesystem; +namespace roofer::io { + + namespace fs = std::filesystem; -namespace roofer { struct LASWriter : public LASWriterInterface { using LASWriterInterface::LASWriterInterface; @@ -115,7 +116,7 @@ namespace roofer { } }; - std::unique_ptr createLASWriter(projHelperInterface& pjh) { + std::unique_ptr createLASWriter(roofer::misc::projHelperInterface& pjh) { return std::make_unique(pjh); }; } \ No newline at end of file diff --git a/src/extra/io/RasterWriterGDAL.cpp b/src/extra/io/RasterWriterGDAL.cpp index e8993cba..1f408e0c 100644 --- a/src/extra/io/RasterWriterGDAL.cpp +++ b/src/extra/io/RasterWriterGDAL.cpp @@ -25,9 +25,9 @@ #include #include -namespace fs = std::filesystem; +namespace roofer::io { -namespace roofer { +namespace fs = std::filesystem; class RasterWriterGDAL : public RasterWriterInterface { @@ -96,7 +96,7 @@ class RasterWriterGDAL : public RasterWriterInterface { } }; -std::unique_ptr createRasterWriterGDAL(projHelperInterface& pjh) { +std::unique_ptr createRasterWriterGDAL(roofer::misc::projHelperInterface& pjh) { return std::make_unique(pjh); }; diff --git a/src/extra/io/StreamCropper.cpp b/src/extra/io/StreamCropper.cpp index 5ecf6e93..c9fc0fd4 100644 --- a/src/extra/io/StreamCropper.cpp +++ b/src/extra/io/StreamCropper.cpp @@ -9,9 +9,9 @@ #include #include -namespace fs = std::filesystem; +namespace roofer::io { -namespace roofer { +namespace fs = std::filesystem; class PointsInPolygonsCollector { std::vector& polygons; @@ -610,7 +610,7 @@ struct PointCloudCropper : public PointCloudCropperInterface { } }; -std::unique_ptr createPointCloudCropper(projHelperInterface& pjh) { +std::unique_ptr createPointCloudCropper(roofer::misc::projHelperInterface& pjh) { return std::make_unique(pjh); }; diff --git a/src/extra/io/VectorReaderOGR.cpp b/src/extra/io/VectorReaderOGR.cpp index a377dcde..f140dddc 100644 --- a/src/extra/io/VectorReaderOGR.cpp +++ b/src/extra/io/VectorReaderOGR.cpp @@ -27,9 +27,9 @@ #include #include -namespace fs = std::filesystem; +namespace roofer::io { -namespace roofer { +namespace fs = std::filesystem; class VectorReaderOGR : public VectorReaderInterface { GDALDatasetUniquePtr poDS; @@ -346,7 +346,7 @@ class VectorReaderOGR : public VectorReaderInterface { } }; -std::unique_ptr createVectorReaderOGR(projHelperInterface& pjh) { +std::unique_ptr createVectorReaderOGR(roofer::misc::projHelperInterface& pjh) { return std::make_unique(pjh); }; diff --git a/src/extra/io/VectorWriterOGR.cpp b/src/extra/io/VectorWriterOGR.cpp index 03d50147..c2cfe8fe 100644 --- a/src/extra/io/VectorWriterOGR.cpp +++ b/src/extra/io/VectorWriterOGR.cpp @@ -25,9 +25,9 @@ #include -namespace fs = std::filesystem; +namespace roofer::io { -namespace roofer { +namespace fs = std::filesystem; class VectorWriterOGR : public VectorWriterInterface { GDALDatasetUniquePtr poDS; @@ -344,7 +344,7 @@ class VectorWriterOGR : public VectorWriterInterface { } }; -std::unique_ptr createVectorWriterOGR(projHelperInterface& pjh) { +std::unique_ptr createVectorWriterOGR(roofer::misc::projHelperInterface& pjh) { return std::make_unique(pjh); }; diff --git a/src/extra/misc/NodataCircleComputer.cpp b/src/extra/misc/NodataCircleComputer.cpp index 04a65acd..f7805a42 100644 --- a/src/extra/misc/NodataCircleComputer.cpp +++ b/src/extra/misc/NodataCircleComputer.cpp @@ -15,7 +15,7 @@ static const double PI = 3.141592653589793238462643383279502884; -namespace roofer { +namespace roofer::misc { typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Delaunay_triangulation_2 Triangulation; typedef Triangulation::Edge_iterator Edge_iterator; diff --git a/src/extra/misc/PC2MeshDistCalculator.cpp b/src/extra/misc/PC2MeshDistCalculator.cpp index 0031c208..cc3c9d5c 100644 --- a/src/extra/misc/PC2MeshDistCalculator.cpp +++ b/src/extra/misc/PC2MeshDistCalculator.cpp @@ -1,14 +1,13 @@ #include #include #include - #include #include #include #include -namespace roofer::detection { +namespace roofer::misc { typedef CGAL::Simple_cartesian SCK; diff --git a/src/extra/misc/PointcloudRasteriser.cpp b/src/extra/misc/PointcloudRasteriser.cpp index 652cc14e..d86d22ad 100644 --- a/src/extra/misc/PointcloudRasteriser.cpp +++ b/src/extra/misc/PointcloudRasteriser.cpp @@ -7,7 +7,7 @@ #include #include -namespace roofer { +namespace roofer::misc { void RasterisePointcloud( PointCollection& pointcloud, diff --git a/src/extra/misc/Val3dator.cpp b/src/extra/misc/Val3dator.cpp index 4914f2ec..79dcb094 100644 --- a/src/extra/misc/Val3dator.cpp +++ b/src/extra/misc/Val3dator.cpp @@ -6,7 +6,7 @@ #include -namespace roofer::detection { +namespace roofer::misc { class Val3dator : public Val3datorInterface{ diff --git a/src/extra/misc/Vector2DOpsGEOS.cpp b/src/extra/misc/Vector2DOpsGEOS.cpp index b4143da2..da27a70a 100644 --- a/src/extra/misc/Vector2DOpsGEOS.cpp +++ b/src/extra/misc/Vector2DOpsGEOS.cpp @@ -18,7 +18,7 @@ #include #include -namespace roofer { +namespace roofer::misc { GEOSContextHandle_t gc; diff --git a/src/extra/misc/projHelper.cpp b/src/extra/misc/projHelper.cpp index f3a855ca..1d1a5e69 100644 --- a/src/extra/misc/projHelper.cpp +++ b/src/extra/misc/projHelper.cpp @@ -4,7 +4,7 @@ #include -namespace roofer { +namespace roofer::misc { static const char *proj_wkt_options[] = {"MULTILINE=NO", NULL}; struct projHelper : public projHelperInterface { diff --git a/src/extra/misc/select_pointcloud.cpp b/src/extra/misc/select_pointcloud.cpp index df1a7f0d..76073286 100644 --- a/src/extra/misc/select_pointcloud.cpp +++ b/src/extra/misc/select_pointcloud.cpp @@ -5,7 +5,7 @@ #include #include -namespace roofer { +namespace roofer::misc { // put the one with lowest quality value (meaning highest quality) on top bool compareByQuality(const CandidatePointCloud* a, @@ -46,7 +46,7 @@ namespace roofer { candidates_date.push_back(&cand); } std::sort(candidates_date.begin(), candidates_date.end(), - roofer::compareByDate); + compareByDate); return candidates_date[0]; } @@ -64,18 +64,18 @@ namespace roofer { candidates_coverage.push_back(&cand); } std::sort(candidates_date.begin(), candidates_date.end(), - roofer::compareByDate); + compareByDate); std::sort(candidates_quality.begin(), candidates_quality.end(), - roofer::compareByQuality); + compareByQuality); std::sort(candidates_coverage.begin(), candidates_coverage.end(), - roofer::compareByNoDataFraction); + compareByNoDataFraction); // get the highest quality candidate with sufficient coverage const CandidatePointCloud* best_suffcient = nullptr; // int candidates_quality_idx(-1); for (unsigned i = 0; i < candidates_quality.size(); ++i) { // spdlog::debug("quality {}={}", candidates_quality[i]->name, candidates_quality[i]->quality); - if (roofer::hasEnoughPointCoverage( + if (hasEnoughPointCoverage( candidates_quality[i], cfg.threshold_nodata, cfg.threshold_maxcircle)) { best_suffcient = candidates_quality[i]; // candidates_quality_idx = i; @@ -89,7 +89,7 @@ namespace roofer { // spdlog::debug("best_suffcient=nullptr"); result.explanation = PointCloudSelectExplanation::_HIGHEST_YET_INSUFFICIENT_COVERAGE; for (unsigned i = 0; i < candidates_coverage.size(); ++i) { - if (!roofer::isMutated( + if (!isMutated( candidates_coverage[i]->image_bundle, candidates_date[0]->image_bundle, cfg.threshold_mutation_fraction, @@ -110,7 +110,7 @@ namespace roofer { const CandidatePointCloud* latest_suffcient = nullptr; // int candidates_latest_idx(-1); for (unsigned i = 0; i < candidates_date.size(); ++i) { - if (roofer::hasEnoughPointCoverage( + if (hasEnoughPointCoverage( candidates_date[i], cfg.threshold_nodata, cfg.threshold_maxcircle)) { latest_suffcient = candidates_date[i]; // candidates_latest_idx = i; @@ -126,7 +126,7 @@ namespace roofer { return result; // else check for mutations } else { - if (roofer::isMutated( + if (isMutated( best_suffcient->image_bundle, latest_suffcient->image_bundle, cfg.threshold_mutation_fraction,