Program Listing for File LargeScaleReconstruction.hpp

Return to documentation for file (include/lvr2/reconstruction/LargeScaleReconstruction.hpp)

#ifndef LAS_VEGAS_LARGESCALERECONSTRUCTION_HPP
#define LAS_VEGAS_LARGESCALERECONSTRUCTION_HPP

#include "lvr2/types/ScanTypes.hpp"
#include "lvr2/algorithm/ChunkHashGrid.hpp"
#include "lvr2/algorithm/HLODTree.hpp"
#include "lvr2/reconstruction/BigGrid.hpp"
#include "lvr2/reconstruction/FastBox.hpp"
#include "lvr2/reconstruction/PointsetGrid.hpp"


#if defined CUDA_FOUND

#define GPU_FOUND
#include "lvr2/reconstruction/cuda/CudaSurface.hpp"
typedef lvr2::CudaSurface GpuSurface;

#elif defined OPENCL_FOUND

#define GPU_FOUND
#include "lvr2/reconstruction/opencl/ClSurface.hpp"
typedef lvr2::ClSurface GpuSurface;

#endif


namespace lvr2
{

enum class LSROutput
{
    BigMesh,
    ChunksPly,
    ChunksHdf5,

#ifdef LVR2_USE_3DTILES
    Tiles3d,
#endif
};

struct LSROptions
{
    std::unordered_set<LSROutput> output{LSROutput::BigMesh};
    bool hasOutput(LSROutput o) const
    {
        return output.find(o) != output.end();
    }

    fs::path outputDir;

    fs::path tempDir;

    bool useGPU = false;

    bool useGPUDistances = false;

    std::vector<float> voxelSizes{0.1};

    float bgVoxelSize = 10;

    float scale = 1;

    uint nodeSize = 1000000;

    uint partMethod = 1;

    uint ki = 20;

    uint kd = 20;

    uint kn = 20;

    bool useRansac = false;

    std::vector<float> flipPoint{10000000, 10000000, 10000000};

    bool extrude = true;

    uint removeDanglingArtifacts = 0;

    uint cleanContours = 0;

    uint fillHoles = 0;

    bool optimizePlanes = false;

    float planeNormalThreshold = 0.85;

    uint planeIterations = 3;

    uint minPlaneSize = 7;

    uint smallRegionThreshold = 0;

    bool retesselate = false;

    float lineFusionThreshold = 0.01;

    bool mergeChunkBorders = true;

    bool tiles3dCompress = false;

    AllowedMemoryUsage tiles3dMemUsage = AllowedMemoryUsage::Moderate;

    void ensureCorrectness()
    {
        LSROptions defaultOptions;

#define CHECK_OPTION(option, condition, message) \
                if (condition) \
                { \
                    std::cout << timestamp << "Warning: " << message << " Reverting to default value." << std::endl; \
                    option = defaultOptions.option; \
                }

        if (partMethod != 1)
        {
            if (hasOutput(LSROutput::ChunksPly))
            {
                std::cout << timestamp << "Warning: Output ChunksPly requires partMethod == 1." << std::endl;
                output.erase(LSROutput::ChunksPly);
            }
            if (hasOutput(LSROutput::ChunksHdf5))
            {
                std::cout << timestamp << "Warning: Output ChunksHdf5 requires partMethod == 1." << std::endl;
                output.erase(LSROutput::ChunksHdf5);
            }
#ifdef LVR2_USE_3DTILES
            if (hasOutput(LSROutput::Tiles3d))
            {
                std::cout << timestamp << "Warning: Output Tiles3d requires partMethod == 1." << std::endl;
                output.erase(LSROutput::Tiles3d);
            }
#endif
        }

        CHECK_OPTION(output, output.empty(), "No output specified.");

        if (outputDir.empty())
        {
            std::stringstream ss;
            time_t now = time(0);
            ss << "./" << std::put_time(std::localtime(&now), "%Y-%m-%d_%H-%M-%S") << "/";
            outputDir = ss.str();
            std::cout << timestamp << "LargeScaleReconstruction: Output directory set to " << outputDir << std::endl;
        }
        fs::create_directories(outputDir);
        if (tempDir.empty())
        {
            tempDir = outputDir / "temp/";
        }
        fs::create_directories(tempDir);

#ifndef GPU_FOUND
        if (useGPU || useGPUDistances)
        {
            std::cout << timestamp << "Warning: No GPU found. Falling back to CPU." << std::endl;
            useGPU = useGPUDistances = false;
        }
#endif

        CHECK_OPTION(voxelSizes, voxelSizes.empty(), "No voxel sizes specified.");
        if (voxelSizes[0] <= 0)
        {
            throw std::invalid_argument("voxelSizes must be positive.");
        }

        CHECK_OPTION(bgVoxelSize, bgVoxelSize <= 0, "bgVoxelSize has to be greater than 0.");

        auto correctedVoxelSize = std::ceil(bgVoxelSize / voxelSizes[0]) * voxelSizes[0];
        if (correctedVoxelSize != bgVoxelSize)
        {
            std::cout << timestamp << "Warning: bgVoxelSize is not a multiple of voxelSizes[0]. Correcting to " << correctedVoxelSize << std::endl;
            bgVoxelSize = correctedVoxelSize;
        }
        auto it = voxelSizes.begin() + 1;
        while (it != voxelSizes.end())
        {
            if (*it <= 0)
            {
                std::cout << timestamp << "Warning: voxelSizes cannot be negative. Ignoring " << *it << std::endl;
                it = voxelSizes.erase(it);
            }
            else if (std::abs(bgVoxelSize - std::ceil(bgVoxelSize / *it) * *it) > std::numeric_limits<float>::epsilon())
            {
                std::cout << timestamp << "Warning: all voxelSizes have to divide bgVoxelSize. Ignoring " << *it << std::endl;
                it = voxelSizes.erase(it);
            }
            else
            {
                ++it;
            }
        }
        CHECK_OPTION(voxelSizes, voxelSizes.empty(), "No voxel sizes specified.");

        CHECK_OPTION(partMethod, partMethod > 1, "partMethod has to be 0 or 1.");

        CHECK_OPTION(kd, kd <= 0, "kd has to be greater than 0.");
        CHECK_OPTION(kn, kn <= 0, "kn has to be greater than 0.");

        CHECK_OPTION(flipPoint, flipPoint.size() != 3, "flipPoint has to be of size 3.");

        if (retesselate)
        {
            optimizePlanes = true;
        }

#ifdef LVR2_USE_3DTILES
        if (tiles3dCompress && !hasOutput(LSROutput::Tiles3d))
        {
            std::cout << timestamp << "Warning: tiles3dCompress is only supported for LSROutput::Tiles3d." << std::endl;
            tiles3dCompress = false;
        }
#else
        if (tiles3dCompress)
        {
            std::cout << timestamp << "Warning: tiles3dCompress is only supported when compiling with 3D Tiles support." << std::endl;
            tiles3dCompress = false;
        }
#endif
    }
};

template <typename BaseVecT>
class LargeScaleReconstruction
{
public:
    using BoxT = FastBox<BaseVecT>;

    LargeScaleReconstruction(LSROptions options = LSROptions());

    void chunkAndReconstruct(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB, std::shared_ptr<ChunkHashGrid> chunkManager = nullptr)
    {
        m_options.ensureCorrectness();
        if (m_options.partMethod == 0)
        {
            chunkAndReconstructKDTree(project, newChunksBB);
        }
        else
        {
            if (!chunkManager)
            {
                throw std::invalid_argument("chunkManager is required for VGrid partition method.");
            }
            chunkAndReconstructVGrid(project, newChunksBB, chunkManager);
        }
    }

    int trueMpiAndReconstructMaster(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB, std::shared_ptr<ChunkHashGrid> chunkManager, int size);

    int trueMpiAndReconstructSlave();

    HalfEdgeMesh<BaseVecT> getPartialReconstruct(BoundingBox<BaseVecT> newChunksBB, std::shared_ptr<ChunkHashGrid> chunkHashGrid,  float voxelSize);





private:

    void chunkAndReconstructKDTree(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB);
    void chunkAndReconstructVGrid(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB, std::shared_ptr<ChunkHashGrid> chunkManager);

    using GridPtr = std::shared_ptr<HashGrid<BaseVecT, BoxT>>;

    GridPtr createChunk(const BigGrid<BaseVecT>& bg,
                        const BoundingBox<BaseVecT>& bb,
                        float voxelSize,
                        size_t minPointsPerChunk, size_t& maxPointsPerChunk,
                        bool& retry);

    void processChunk(GridPtr ps_grid,
                      const Vector3i& coord,
                      const fs::path& chunkDirPly,
                      std::shared_ptr<HighFive::File> chunkFileHdf5,
                      std::shared_ptr<HighFive::File> chunkFile3dTiles,
                      typename HLODTree<BaseVecT>::ChunkMap& chunkMap);

    void createAndSaveBigMesh(GridPtr hg, size_t voxelSizeIndex);

    uint* mpiScheduler(const std::vector<BoundingBox<BaseVecT>>& partitionBoxes, BigGrid<BaseVecT>& bg, BoundingBox<BaseVecT>& cbb, std::shared_ptr<ChunkHashGrid> chunkManager);

    void mpiCollector(const std::vector<BoundingBox<BaseVecT>>& partitionBoxes, BoundingBox<BaseVecT>& cbb, std::shared_ptr<ChunkHashGrid> chunkManager, uint* partitionBoxesSkipped);


    LSROptions m_options;
};

} // namespace lvr2

#include "LargeScaleReconstruction.tcc"

#endif // LAS_VEGAS_LARGESCALERECONSTRUCTION_HPP