From dad8aafa5d59b1b3e0c43fa4c3395a25061b8e68 Mon Sep 17 00:00:00 2001 From: rauts Date: Tue, 7 Jun 2022 15:27:20 +0200 Subject: [PATCH 01/47] fixed build with probe plugin --- externals/CMakeExternals.cmake | 4 ++-- plugins/probe/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/externals/CMakeExternals.cmake b/externals/CMakeExternals.cmake index 1587529f39..6e0e02c504 100644 --- a/externals/CMakeExternals.cmake +++ b/externals/CMakeExternals.cmake @@ -743,9 +743,9 @@ function(require_external NAME) endif () if (WIN32) - set(QHULL_LIB "lib/qhull.lib") + set(QHULL_LIB "lib/qhull.lib") else () - set(QUHULL_LIB "lib/libqhull.a") + set(QUHULL_LIB "lib/libqhull.a") endif () add_external_project(qhull STATIC diff --git a/plugins/probe/CMakeLists.txt b/plugins/probe/CMakeLists.txt index 25dbb8f484..458573fc88 100644 --- a/plugins/probe/CMakeLists.txt +++ b/plugins/probe/CMakeLists.txt @@ -30,7 +30,7 @@ if (probe_PLUGIN_ENABLED) find_package(CGAL 5.3 CONFIG REQUIRED) target_link_libraries(probe PUBLIC CGAL::CGAL) if(WIN32) - install(FILES "${CGAL_DIR}/../../bin/gmp.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") + install(FILES "${CGAL_DIR}/../../bin/gmp-10.dll" "${CGAL_DIR}/../../bin/gmpxx-4.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") endif() if (BUILD_MMOSPRAY_PLUGIN_PLUGIN) target_sources(probe PRIVATE ${ospray_sources} ${ospray_headers} ${ospray_public_headers}) From 28681cac62aa4364b3f64b0b9d39d598e941b964 Mon Sep 17 00:00:00 2001 From: rauts Date: Tue, 7 Jun 2022 15:28:39 +0200 Subject: [PATCH 02/47] added glyph summing prototype --- plugins/probe/src/SumGlyphs.cpp | 247 ++++++++++++++++++++++++++++++++ plugins/probe/src/SumGlyphs.h | 82 +++++++++++ plugins/probe/src/probe.cpp | 2 + 3 files changed, 331 insertions(+) create mode 100644 plugins/probe/src/SumGlyphs.cpp create mode 100644 plugins/probe/src/SumGlyphs.h diff --git a/plugins/probe/src/SumGlyphs.cpp b/plugins/probe/src/SumGlyphs.cpp new file mode 100644 index 0000000000..e872282c6b --- /dev/null +++ b/plugins/probe/src/SumGlyphs.cpp @@ -0,0 +1,247 @@ +/* + * SumGlyphs.cpp + * Copyright (C) 2021 by MegaMol Team + * Alle Rechte vorbehalten. + */ + +#include "SumGlyphs.h" +#include "glm/glm.hpp" +#include "mmadios/CallADIOSData.h" +#include "mmcore/param/ColorParam.h" +#include "mmcore/param/EnumParam.h" +#include "probe/CallKDTree.h" +#include "probe/ProbeCalls.h" + + +namespace megamol { +namespace probe { + +SumGlyphs::SumGlyphs() + : Module() + , _version(0) + , _probe_rhs_slot("getProbes", "") + , _probe_lhs_slot("deployMesh", "") { + + this->_probe_rhs_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->_probe_rhs_slot); + + + this->_probe_lhs_slot.SetCallback( + CallProbes::ClassName(), CallProbes::FunctionName(0), &SumGlyphs::getData); + this->_probe_lhs_slot.SetCallback( + CallProbes::ClassName(), CallProbes::FunctionName(1), &SumGlyphs::getMetaData); + this->MakeSlotAvailable(&this->_probe_lhs_slot); + this->_probe_lhs_slot.SetNecessity(core::AbstractCallSlotPresentation::SLOT_REQUIRED); +} + +SumGlyphs::~SumGlyphs() { + this->Release(); +} + +bool SumGlyphs::create() { + return true; +} + +void SumGlyphs::release() {} + +bool SumGlyphs::getData(core::Call& call) { + + CallProbes* lhsProbesCall = dynamic_cast(&call); + if (lhsProbesCall == nullptr) + return false; + + if (!(*lhsProbesCall)(0)) + return false; + const bool lhs_dirty = lhsProbesCall->hasUpdate(); + + auto rhsProbesCall = this->_probe_rhs_slot.CallAs(); + if (rhsProbesCall != nullptr) { + auto meta_data = rhsProbesCall->getMetaData(); + if (!(*rhsProbesCall)(0)) + return false; + const bool rhs_dirty = rhsProbesCall->hasUpdate(); + if (rhs_dirty || lhs_dirty) { + ++_version; + _sum_probe_collection = std::make_shared(); + + auto const probe_count = rhsProbesCall->getData()->getProbeCount(); + auto const probes = rhsProbesCall->getData(); + std::vector> probe_positions(probe_count); + std::map> probes_with_this_clusterid; + for (auto i = 0; i < probe_count; i++) { + auto generic_probe = rhsProbesCall->getData()->getGenericProbe(i); + + int cluster_id; + std::array pos; + + auto visitor = [&cluster_id, &pos](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else { + // unknown probe type, throw error? do nothing? + } + }; + + std::visit(visitor, generic_probe); + + probe_positions[i] = pos; + probes_with_this_clusterid[cluster_id].emplace_back(i); + } + //using current_probe_type = std::decay_tgetGenericProbe(0))>; + + + + // calculate middle probe distance + auto avg_dist = calculateAverageDistance(probe_positions, 2); + + // check if cluster is connected region + // generate one summed glyph for each region + for (auto& cluster : probes_with_this_clusterid) { + if (cluster.second.size() > 1) { + std::vector> cluster_positions; + cluster_positions.reserve(cluster.second.size()); + std::vector id_translator; + id_translator.reserve(cluster.second.size()); + for (auto probe_id : cluster.second) { + cluster_positions.emplace_back(probe_positions[probe_id]); + id_translator.emplace_back(probe_id); + } + + std::mt19937 rnd; + rnd.seed(std::random_device()()); + std::uniform_int_distribution dist(0, cluster.second.size()); + auto start_index = dist(rnd); + + + std::map> to_check_map; + to_check_map[start_index] = cluster_positions[start_index]; + + // store region + std::vector>> region; + + while (!cluster_positions.empty()) { + region.emplace_back(std::map>()); + while (!to_check_map.empty()) { + + auto old_to_check_map = to_check_map; + + auto kd_tree = my_kd_tree_t( + 3 /*dim*/, cluster_positions, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + kd_tree.buildIndex(); + + + for (auto sample_point : to_check_map) { + std::vector> res; + auto num_results = kd_tree.radiusSearch( + &sample_point.second[0], 2 * avg_dist, res, nanoflann::SearchParams(10, 0.01f, true)); + + for (auto entry: res) { + to_check_map[std::get<0>(entry)] = cluster_positions[std::get<0>(entry)]; + region.back()[std::get<0>(entry)] = cluster_positions[std::get<0>(entry)]; + } + } + + // erase already checked points + for (auto old_id : old_to_check_map) { + to_check_map.erase(old_id.first); + cluster_positions.erase(std::find(cluster_positions.begin(), cluster_positions.end(), old_id.second)); + } + } + } + + + //current_probe_type sum_probe; + + + } else { + _sum_probe_collection->addProbe(probes->getProbe(cluster.second[0])); + } + } + + + + } + } + + lhsProbesCall->setData(_sum_probe_collection, _version); + + return true; +} + +bool SumGlyphs::getMetaData(core::Call& call) { + + CallProbes* lhsProbesCall = dynamic_cast(&call); + if (lhsProbesCall == nullptr) + return false; + + auto rhsProbesCall = this->_probe_rhs_slot.CallAs(); + if (rhsProbesCall != nullptr) + return false; + + + auto rhs_meta_data = rhsProbesCall->getMetaData(); + auto lhs_meta_data = lhsProbesCall->getMetaData(); + + rhs_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; + + rhsProbesCall->setMetaData(rhs_meta_data); + if (!(*rhsProbesCall)(1)) + return false; + rhs_meta_data = rhsProbesCall->getMetaData(); + + lhs_meta_data.m_frame_cnt = rhs_meta_data.m_frame_cnt; + lhs_meta_data.m_bboxs = rhs_meta_data.m_bboxs; + + // put metadata in mesh call + lhsProbesCall->setMetaData(lhs_meta_data); + + return true; +} + +bool SumGlyphs::parameterChanged(core::param::ParamSlot& p) { + _recalc = true; + return true; +} + +float SumGlyphs::calculateAverageDistance(std::vector> const& input_data, int const num_neighbors) { + auto kd_tree = my_kd_tree_t(3 /*dim*/, input_data, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + kd_tree.buildIndex(); + int const num_results = num_neighbors + 1; + float distance = 0.0f; + for (auto& pos : input_data) { + std::vector ret_index(num_results); + std::vector sqr_dist(num_results); + nanoflann::KNNResultSet resultSet(num_results); + resultSet.init(ret_index.data(), sqr_dist.data()); + + + kd_tree.findNeighbors(resultSet, &pos[0], nanoflann::SearchParams(10)); + for (int i = 1; i < num_results; ++i) { + distance += std::sqrtf(sqr_dist[i]); + } + } + + return distance / static_cast(input_data.size()*num_neighbors); +} + +float SumGlyphs::getDistance(std::arrayconst& point1, std::array const& point2) { + return std::sqrtf( + std::powf(point2[0] - point1[0], 2) + std::powf(point2[0] - point1[0], 2) + std::powf(point2[0] - point1[0], 2)); +} + +} // namespace probe +} // namespace megamol diff --git a/plugins/probe/src/SumGlyphs.h b/plugins/probe/src/SumGlyphs.h new file mode 100644 index 0000000000..dbef783fb4 --- /dev/null +++ b/plugins/probe/src/SumGlyphs.h @@ -0,0 +1,82 @@ +/* + * SumGlyphs.h + * Copyright (C) 2021 by MegaMol Team + * Alle Rechte vorbehalten. + */ + + +#pragma once + +#include "glm/glm.hpp" + +#include "mmcore/CalleeSlot.h" +#include "mmcore/CallerSlot.h" +#include "mmcore/Module.h" + +#include "mesh/MeshCalls.h" +#include "mmcore/param/ParamSlot.h" +#include "probe/ProbeCollection.h" +#include "ConstructHull.h" + + +namespace megamol { +namespace probe { + +class SumGlyphs : public core::Module { +public: + /** + * Answer the name of this module. + * + * @return The name of this module. + */ + static const char* ClassName() { + return "SumGlyphs"; + } + + /** + * Answer a human readable description of this module. + * + * @return A human readable description of this module. + */ + static const char* Description() { + return "..."; + } + + /** + * Answers whether this module is available on the current system. + * + * @return 'true' if the module is available, 'false' otherwise. + */ + static bool IsAvailable(void) { + return true; + } + + SumGlyphs(); + virtual ~SumGlyphs(); + +protected: + virtual bool create(); + virtual void release(); + + uint32_t _version; + + core::CallerSlot _probe_rhs_slot; + core::CalleeSlot _probe_lhs_slot; + +private: + typedef kd_adaptor>> data2KD; + typedef nanoflann::KDTreeSingleIndexAdaptor, data2KD, 3> my_kd_tree_t; + + bool getData(core::Call& call); + bool getMetaData(core::Call& call); + bool parameterChanged(core::param::ParamSlot& p); + float calculateAverageDistance(std::vector> const& input_data, int const num_neighbors); + float getDistance(std::array const& point1, std::array const& point2); + + std::shared_ptr _sum_probe_collection; + + bool _recalc; +}; + +} // namespace probe +} // namespace megamol diff --git a/plugins/probe/src/probe.cpp b/plugins/probe/src/probe.cpp index 1a54cfa63d..8971e9fcb4 100644 --- a/plugins/probe/src/probe.cpp +++ b/plugins/probe/src/probe.cpp @@ -32,6 +32,7 @@ #include "ReconstructSurface.h" #include "TableToProbes.h" #include "TessellateBoundingBox.h" +#include "SumGlyphs.h" namespace megamol::probe { class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { @@ -71,6 +72,7 @@ class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPlug this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); // register calls From 93edac7a3066c511ae3bcc82c37c08f0d3d5dae0 Mon Sep 17 00:00:00 2001 From: rauts Date: Tue, 7 Jun 2022 16:06:00 +0200 Subject: [PATCH 03/47] make install dlls dependent on cgal version --- plugins/probe/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/probe/CMakeLists.txt b/plugins/probe/CMakeLists.txt index 458573fc88..56c3f49582 100644 --- a/plugins/probe/CMakeLists.txt +++ b/plugins/probe/CMakeLists.txt @@ -30,7 +30,11 @@ if (probe_PLUGIN_ENABLED) find_package(CGAL 5.3 CONFIG REQUIRED) target_link_libraries(probe PUBLIC CGAL::CGAL) if(WIN32) - install(FILES "${CGAL_DIR}/../../bin/gmp-10.dll" "${CGAL_DIR}/../../bin/gmpxx-4.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") + if(CGAL_VERSION VERSION_EQUAL "5.4") + install(FILES "${CGAL_DIR}/../../bin/gmp-10.dll" "${CGAL_DIR}/../../bin/gmpxx-4.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") + else() + install(FILES "${CGAL_DIR}/../../bin/gmp.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") + endif() endif() if (BUILD_MMOSPRAY_PLUGIN_PLUGIN) target_sources(probe PRIVATE ${ospray_sources} ${ospray_headers} ${ospray_public_headers}) From aec7277c8b48e0ccbe86ea6d39ffafcf23426ec9 Mon Sep 17 00:00:00 2001 From: rauts Date: Tue, 7 Jun 2022 16:20:51 +0200 Subject: [PATCH 04/47] fixed dll install for probes --- externals/CMakeExternals.cmake | 8 +++++--- plugins/probe/CMakeLists.txt | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/externals/CMakeExternals.cmake b/externals/CMakeExternals.cmake index 6e0e02c504..92ee7c0652 100644 --- a/externals/CMakeExternals.cmake +++ b/externals/CMakeExternals.cmake @@ -229,7 +229,8 @@ function(require_external NAME) endif () if (WIN32) - set(BLEND2D_LIB "lib/blend2d.lib") + set(BLEND2D_LIB "bin/blend2d.dll") + set(BLEND2D_IMPORT_LIB "lib/blend2d.lib") else () set(BLEND2D_LIB "lib/libblend2d.a") endif () @@ -237,7 +238,7 @@ function(require_external NAME) require_external(asmjit) external_get_property(asmjit SOURCE_DIR) - add_external_project(blend2d STATIC + add_external_project(blend2d SHARED GIT_REPOSITORY https://github.com/blend2d/blend2d.git GIT_TAG "8aeac6cb34b00898ae725bd76eb3bb2c7cffcf86" BUILD_BYPRODUCTS "/${BLEND2D_IMPORT_LIB}" "/${BLEND2D_LIB}" @@ -247,7 +248,8 @@ function(require_external NAME) add_external_library(blend2d DEPENDS asmjit INCLUDE_DIR "include" - LIBRARY ${BLEND2D_LIB}) + LIBRARY ${BLEND2D_LIB} + IMPORT_LIBRARY ${BLEND2D_IMPORT_LIB}) # chemfiles elseif(NAME STREQUAL "chemfiles") diff --git a/plugins/probe/CMakeLists.txt b/plugins/probe/CMakeLists.txt index 56c3f49582..977511e6af 100644 --- a/plugins/probe/CMakeLists.txt +++ b/plugins/probe/CMakeLists.txt @@ -33,7 +33,7 @@ if (probe_PLUGIN_ENABLED) if(CGAL_VERSION VERSION_EQUAL "5.4") install(FILES "${CGAL_DIR}/../../bin/gmp-10.dll" "${CGAL_DIR}/../../bin/gmpxx-4.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") else() - install(FILES "${CGAL_DIR}/../../bin/gmp.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") + install(FILES "${CGAL_DIR}/../../bin/gmp.dll" "${CGAL_DIR}/../../debug/bin/gmpd.dll" "${CGAL_DIR}/../../bin/mpfr-6.dll" DESTINATION "bin") endif() endif() if (BUILD_MMOSPRAY_PLUGIN_PLUGIN) From 325f45126fadff39538db4927fae917b0eb6f097 Mon Sep 17 00:00:00 2001 From: rauts Date: Tue, 7 Jun 2022 17:32:32 +0200 Subject: [PATCH 05/47] removed pcl and 3rd party code --- plugins/probe/3rd/centroid.h | 1426 ------ plugins/probe/3rd/common.h | 696 --- plugins/probe/3rd/concave_hull.h | 722 --- plugins/probe/3rd/eigen.h | 1540 ------- plugins/probe/3rd/feature.h | 496 --- plugins/probe/3rd/feature.hpp | 312 -- plugins/probe/3rd/kdtree.h | 805 ---- plugins/probe/3rd/normal_3d.h | 394 -- plugins/probe/3rd/normal_3d.hpp | 100 - plugins/probe/3rd/normal_3d_omp.h | 104 - plugins/probe/3rd/normal_3d_omp.hpp | 127 - plugins/probe/3rd/poisson.h | 393 -- plugins/probe/3rd/poisson4/allocator.h | 168 - plugins/probe/3rd/poisson4/binary_node.h | 88 - plugins/probe/3rd/poisson4/bspline_data.h | 148 - plugins/probe/3rd/poisson4/bspline_data.hpp | 534 --- plugins/probe/3rd/poisson4/factor.cpp | 273 -- plugins/probe/3rd/poisson4/factor.h | 58 - plugins/probe/3rd/poisson4/function_data.h | 123 - plugins/probe/3rd/poisson4/function_data.hpp | 423 -- plugins/probe/3rd/poisson4/geometry.cpp | 127 - plugins/probe/3rd/poisson4/geometry.h | 795 ---- plugins/probe/3rd/poisson4/geometry.hpp | 430 -- .../3rd/poisson4/marching_cubes_poisson.cpp | 996 ----- .../3rd/poisson4/marching_cubes_poisson.h | 143 - plugins/probe/3rd/poisson4/mat.h | 59 - plugins/probe/3rd/poisson4/mat.hpp | 223 - .../3rd/poisson4/multi_grid_octree_data.h | 406 -- .../3rd/poisson4/multi_grid_octree_data.hpp | 3898 ----------------- plugins/probe/3rd/poisson4/octree_poisson.h | 287 -- plugins/probe/3rd/poisson4/octree_poisson.hpp | 1916 -------- .../probe/3rd/poisson4/poisson_exceptions.h | 141 - plugins/probe/3rd/poisson4/polynomial.h | 102 - plugins/probe/3rd/poisson4/polynomial.hpp | 324 -- plugins/probe/3rd/poisson4/ppolynomial.h | 128 - plugins/probe/3rd/poisson4/ppolynomial.hpp | 440 -- plugins/probe/3rd/poisson4/sparse_matrix.h | 188 - plugins/probe/3rd/poisson4/sparse_matrix.hpp | 973 ---- plugins/probe/3rd/poisson4/vector.h | 155 - plugins/probe/3rd/poisson4/vector.hpp | 492 --- plugins/probe/3rd/reconstruction.h | 255 -- plugins/probe/3rd/transforms.h | 815 ---- plugins/probe/CMakeLists.txt | 3 - plugins/probe/include/probe/CallKDTree.h | 54 +- plugins/probe/src/ConstructHull.h | 46 +- plugins/probe/src/ConstructKDTree.cpp | 38 +- plugins/probe/src/ConstructKDTree.h | 10 +- plugins/probe/src/ElementColoring.cpp | 1 + plugins/probe/src/ExtractCenterline.cpp | 1 - plugins/probe/src/ExtractCenterline.h | 2 - plugins/probe/src/ExtractMesh.cpp | 925 ---- plugins/probe/src/ExtractMesh.h | 139 - plugins/probe/src/ExtractSkeleton.h | 2 - plugins/probe/src/SampleAlongProbes.h | 142 +- plugins/probe/src/SumGlyphs.cpp | 3 +- plugins/probe/src/SumGlyphs.h | 2 +- plugins/probe/src/SurfaceNets.h | 2 - plugins/probe/src/probe.cpp | 2 - plugins/probe_gl/src/FilterByProbe.cpp | 62 +- 59 files changed, 200 insertions(+), 23457 deletions(-) delete mode 100644 plugins/probe/3rd/centroid.h delete mode 100644 plugins/probe/3rd/common.h delete mode 100644 plugins/probe/3rd/concave_hull.h delete mode 100644 plugins/probe/3rd/eigen.h delete mode 100644 plugins/probe/3rd/feature.h delete mode 100644 plugins/probe/3rd/feature.hpp delete mode 100644 plugins/probe/3rd/kdtree.h delete mode 100644 plugins/probe/3rd/normal_3d.h delete mode 100644 plugins/probe/3rd/normal_3d.hpp delete mode 100644 plugins/probe/3rd/normal_3d_omp.h delete mode 100644 plugins/probe/3rd/normal_3d_omp.hpp delete mode 100644 plugins/probe/3rd/poisson.h delete mode 100644 plugins/probe/3rd/poisson4/allocator.h delete mode 100644 plugins/probe/3rd/poisson4/binary_node.h delete mode 100644 plugins/probe/3rd/poisson4/bspline_data.h delete mode 100644 plugins/probe/3rd/poisson4/bspline_data.hpp delete mode 100644 plugins/probe/3rd/poisson4/factor.cpp delete mode 100644 plugins/probe/3rd/poisson4/factor.h delete mode 100644 plugins/probe/3rd/poisson4/function_data.h delete mode 100644 plugins/probe/3rd/poisson4/function_data.hpp delete mode 100644 plugins/probe/3rd/poisson4/geometry.cpp delete mode 100644 plugins/probe/3rd/poisson4/geometry.h delete mode 100644 plugins/probe/3rd/poisson4/geometry.hpp delete mode 100644 plugins/probe/3rd/poisson4/marching_cubes_poisson.cpp delete mode 100644 plugins/probe/3rd/poisson4/marching_cubes_poisson.h delete mode 100644 plugins/probe/3rd/poisson4/mat.h delete mode 100644 plugins/probe/3rd/poisson4/mat.hpp delete mode 100644 plugins/probe/3rd/poisson4/multi_grid_octree_data.h delete mode 100644 plugins/probe/3rd/poisson4/multi_grid_octree_data.hpp delete mode 100644 plugins/probe/3rd/poisson4/octree_poisson.h delete mode 100644 plugins/probe/3rd/poisson4/octree_poisson.hpp delete mode 100644 plugins/probe/3rd/poisson4/poisson_exceptions.h delete mode 100644 plugins/probe/3rd/poisson4/polynomial.h delete mode 100644 plugins/probe/3rd/poisson4/polynomial.hpp delete mode 100644 plugins/probe/3rd/poisson4/ppolynomial.h delete mode 100644 plugins/probe/3rd/poisson4/ppolynomial.hpp delete mode 100644 plugins/probe/3rd/poisson4/sparse_matrix.h delete mode 100644 plugins/probe/3rd/poisson4/sparse_matrix.hpp delete mode 100644 plugins/probe/3rd/poisson4/vector.h delete mode 100644 plugins/probe/3rd/poisson4/vector.hpp delete mode 100644 plugins/probe/3rd/reconstruction.h delete mode 100644 plugins/probe/3rd/transforms.h delete mode 100644 plugins/probe/src/ExtractMesh.cpp delete mode 100644 plugins/probe/src/ExtractMesh.h diff --git a/plugins/probe/3rd/centroid.h b/plugins/probe/3rd/centroid.h deleted file mode 100644 index de21bfbf6a..0000000000 --- a/plugins/probe/3rd/centroid.h +++ /dev/null @@ -1,1426 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#pragma once - -#include "common.h" - -/** - * \file pcl/common/centroid.h - * Define methods for centroid estimation and covariance matrix calculus - * \ingroup common - */ - -/*@{*/ -namespace pcl -{ - - /** \brief Compute the 3D (X-Y-Z) centroid of a set of points and return it as a 3D vector. - * \param[in] cloud the input point cloud - * \param[out] centroid the output centroid - * \return number of valid points used to determine the centroid. In case of dense point clouds, this is the same as the size of input cloud. - * \note if return value is 0, the centroid is not changed, thus not valid. - * The last component of the vector is set to 1, this allows to transform the centroid vector with 4x4 matrices. - * \ingroup common - */ - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - Eigen::Matrix ¢roid); - - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - Eigen::Vector4f ¢roid) - { - return (compute3DCentroid (cloud, centroid)); - } - - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - Eigen::Vector4d ¢roid) - { - return (compute3DCentroid (cloud, centroid)); - } - - /** \brief Compute the 3D (X-Y-Z) centroid of a set of points using their indices and - * return it as a 3D vector. - * \param[in] cloud the input point cloud - * \param[in] indices the point cloud indices that need to be used - * \param[out] centroid the output centroid - * \return number of valid points used to determine the centroid. In case of dense point clouds, this is the same as the size of input indices. - * \note if return value is 0, the centroid is not changed, thus not valid. - * The last component of the vector is set to 1, this allows to transform the centroid vector with 4x4 matrices. - * \ingroup common - */ - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix ¢roid); - - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Vector4f ¢roid) - { - return (compute3DCentroid (cloud, indices, centroid)); - } - - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Vector4d ¢roid) - { - return (compute3DCentroid (cloud, indices, centroid)); - } - - /** \brief Compute the 3D (X-Y-Z) centroid of a set of points using their indices and - * return it as a 3D vector. - * \param[in] cloud the input point cloud - * \param[in] indices the point cloud indices that need to be used - * \param[out] centroid the output centroid - * \return number of valid points used to determine the centroid. In case of dense point clouds, this is the same as the size of input indices. - * \note if return value is 0, the centroid is not changed, thus not valid. - * The last component of the vector is set to 1, this allows to transform the centroid vector with 4x4 matrices. - * \ingroup common - */ - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix ¢roid); - - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Vector4f ¢roid) - { - return (compute3DCentroid (cloud, indices, centroid)); - } - - template inline unsigned int - compute3DCentroid (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Vector4d ¢roid) - { - return (compute3DCentroid (cloud, indices, centroid)); - } - - /** \brief Compute the 3x3 covariance matrix of a given set of points. - * The result is returned as a Eigen::Matrix3f. - * Note: the covariance matrix is not normalized with the number of - * points. For a normalized covariance, please use - * computeCovarianceMatrixNormalized. - * \param[in] cloud the input point cloud - * \param[in] centroid the centroid of the set of points in the cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input cloud. - * \note if return value is 0, the covariance matrix is not changed, thus not valid. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const Eigen::Matrix ¢roid, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const Eigen::Vector4f ¢roid, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, centroid, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const Eigen::Vector4d ¢roid, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, centroid, covariance_matrix)); - } - - /** \brief Compute normalized the 3x3 covariance matrix of a given set of points. - * The result is returned as a Eigen::Matrix3f. - * Normalized means that every entry has been divided by the number of points in the point cloud. - * For small number of points, or if you want explicitly the sample-variance, use computeCovarianceMatrix - * and scale the covariance matrix with 1 / (n-1), where n is the number of points used to calculate - * the covariance matrix and is returned by the computeCovarianceMatrix function. - * \param[in] cloud the input point cloud - * \param[in] centroid the centroid of the set of points in the cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input cloud. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const Eigen::Matrix ¢roid, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const Eigen::Vector4f ¢roid, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrixNormalized (cloud, centroid, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const Eigen::Vector4d ¢roid, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrixNormalized (cloud, centroid, covariance_matrix)); - } - - /** \brief Compute the 3x3 covariance matrix of a given set of points using their indices. - * The result is returned as a Eigen::Matrix3f. - * Note: the covariance matrix is not normalized with the number of - * points. For a normalized covariance, please use - * computeCovarianceMatrixNormalized. - * \param[in] cloud the input point cloud - * \param[in] indices the point cloud indices that need to be used - * \param[in] centroid the centroid of the set of points in the cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - const Eigen::Matrix ¢roid, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - const Eigen::Vector4f ¢roid, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, centroid, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - const Eigen::Vector4d ¢roid, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, centroid, covariance_matrix)); - } - - /** \brief Compute the 3x3 covariance matrix of a given set of points using their indices. - * The result is returned as a Eigen::Matrix3f. - * Note: the covariance matrix is not normalized with the number of - * points. For a normalized covariance, please use - * computeCovarianceMatrixNormalized. - * \param[in] cloud the input point cloud - * \param[in] indices the point cloud indices that need to be used - * \param[in] centroid the centroid of the set of points in the cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - const Eigen::Matrix ¢roid, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - const Eigen::Vector4f ¢roid, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, centroid, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - const Eigen::Vector4d ¢roid, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, centroid, covariance_matrix)); - } - - /** \brief Compute the normalized 3x3 covariance matrix of a given set of points using - * their indices. - * The result is returned as a Eigen::Matrix3f. - * Normalized means that every entry has been divided by the number of entries in indices. - * For small number of points, or if you want explicitly the sample-variance, use computeCovarianceMatrix - * and scale the covariance matrix with 1 / (n-1), where n is the number of points used to calculate - * the covariance matrix and is returned by the computeCovarianceMatrix function. - * \param[in] cloud the input point cloud - * \param[in] indices the point cloud indices that need to be used - * \param[in] centroid the centroid of the set of points in the cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const std::vector &indices, - const Eigen::Matrix ¢roid, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const std::vector &indices, - const Eigen::Vector4f ¢roid, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrixNormalized (cloud, indices, centroid, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const std::vector &indices, - const Eigen::Vector4d ¢roid, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrixNormalized (cloud, indices, centroid, covariance_matrix)); - } - - /** \brief Compute the normalized 3x3 covariance matrix of a given set of points using - * their indices. The result is returned as a Eigen::Matrix3f. - * Normalized means that every entry has been divided by the number of entries in indices. - * For small number of points, or if you want explicitly the sample-variance, use computeCovarianceMatrix - * and scale the covariance matrix with 1 / (n-1), where n is the number of points used to calculate - * the covariance matrix and is returned by the computeCovarianceMatrix function. - * \param[in] cloud the input point cloud - * \param[in] indices the point cloud indices that need to be used - * \param[in] centroid the centroid of the set of points in the cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - const Eigen::Matrix ¢roid, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - const Eigen::Vector4f ¢roid, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrixNormalized (cloud, indices, centroid, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrixNormalized (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - const Eigen::Vector4d ¢roid, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrixNormalized (cloud, indices, centroid, covariance_matrix)); - } - - /** \brief Compute the normalized 3x3 covariance matrix and the centroid of a given set of points in a single loop. - * Normalized means that every entry has been divided by the number of valid entries in the point cloud. - * For small number of points, or if you want explicitly the sample-variance, scale the covariance matrix - * with n / (n-1), where n is the number of points used to calculate the covariance matrix and is returned by this function. - * \note This method is theoretically exact. However using float for internal calculations reduces the accuracy but increases the efficiency. - * \param[in] cloud the input point cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \param[out] centroid the centroid of the set of points in the cloud - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input cloud. - * \ingroup common - */ - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - Eigen::Matrix &covariance_matrix, - Eigen::Matrix ¢roid); - - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - Eigen::Matrix3f &covariance_matrix, - Eigen::Vector4f ¢roid) - { - return (computeMeanAndCovarianceMatrix (cloud, covariance_matrix, centroid)); - } - - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - Eigen::Matrix3d &covariance_matrix, - Eigen::Vector4d ¢roid) - { - return (computeMeanAndCovarianceMatrix (cloud, covariance_matrix, centroid)); - } - - /** \brief Compute the normalized 3x3 covariance matrix and the centroid of a given set of points in a single loop. - * Normalized means that every entry has been divided by the number of entries in indices. - * For small number of points, or if you want explicitly the sample-variance, scale the covariance matrix - * with n / (n-1), where n is the number of points used to calculate the covariance matrix and is returned by this function. - * \note This method is theoretically exact. However using float for internal calculations reduces the accuracy but increases the efficiency. - * \param[in] cloud the input point cloud - * \param[in] indices subset of points given by their indices - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \param[out] centroid the centroid of the set of points in the cloud - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix &covariance_matrix, - Eigen::Matrix ¢roid); - - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix3f &covariance_matrix, - Eigen::Vector4f ¢roid) - { - return (computeMeanAndCovarianceMatrix (cloud, indices, covariance_matrix, centroid)); - } - - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix3d &covariance_matrix, - Eigen::Vector4d ¢roid) - { - return (computeMeanAndCovarianceMatrix (cloud, indices, covariance_matrix, centroid)); - } - - /** \brief Compute the normalized 3x3 covariance matrix and the centroid of a given set of points in a single loop. - * Normalized means that every entry has been divided by the number of entries in indices. - * For small number of points, or if you want explicitly the sample-variance, scale the covariance matrix - * with n / (n-1), where n is the number of points used to calculate the covariance matrix and is returned by this function. - * \note This method is theoretically exact. However using float for internal calculations reduces the accuracy but increases the efficiency. - * \param[in] cloud the input point cloud - * \param[in] indices subset of points given by their indices - * \param[out] centroid the centroid of the set of points in the cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix &covariance_matrix, - Eigen::Matrix ¢roid); - - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix3f &covariance_matrix, - Eigen::Vector4f ¢roid) - { - return (computeMeanAndCovarianceMatrix (cloud, indices, covariance_matrix, centroid)); - } - - template inline unsigned int - computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix3d &covariance_matrix, - Eigen::Vector4d ¢roid) - { - return (computeMeanAndCovarianceMatrix (cloud, indices, covariance_matrix, centroid)); - } - - /** \brief Compute the normalized 3x3 covariance matrix for a already demeaned point cloud. - * Normalized means that every entry has been divided by the number of entries in the input point cloud. - * For small number of points, or if you want explicitly the sample-variance, scale the covariance matrix - * with n / (n-1), where n is the number of points used to calculate the covariance matrix and is returned by this function. - * \note This method is theoretically exact. However using float for internal calculations reduces the accuracy but increases the efficiency. - * \param[in] cloud the input point cloud - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input cloud. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, covariance_matrix)); - } - - /** \brief Compute the normalized 3x3 covariance matrix for a already demeaned point cloud. - * Normalized means that every entry has been divided by the number of entries in indices. - * For small number of points, or if you want explicitly the sample-variance, scale the covariance matrix - * with n / (n-1), where n is the number of points used to calculate the covariance matrix and is returned by this function. - * \note This method is theoretically exact. However using float for internal calculations reduces the accuracy but increases the efficiency. - * \param[in] cloud the input point cloud - * \param[in] indices subset of points given by their indices - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, covariance_matrix)); - } - - /** \brief Compute the normalized 3x3 covariance matrix for a already demeaned point cloud. - * Normalized means that every entry has been divided by the number of entries in indices. - * For small number of points, or if you want explicitly the sample-variance, scale the covariance matrix - * with n / (n-1), where n is the number of points used to calculate the covariance matrix and is returned by this function. - * \note This method is theoretically exact. However using float for internal calculations reduces the accuracy but increases the efficiency. - * \param[in] cloud the input point cloud - * \param[in] indices subset of points given by their indices - * \param[out] covariance_matrix the resultant 3x3 covariance matrix - * \return number of valid points used to determine the covariance matrix. - * In case of dense point clouds, this is the same as the size of input indices. - * \ingroup common - */ - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix &covariance_matrix); - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix3f &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, covariance_matrix)); - } - - template inline unsigned int - computeCovarianceMatrix (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix3d &covariance_matrix) - { - return (computeCovarianceMatrix (cloud, indices, covariance_matrix)); - } - - /** \brief Subtract a centroid from a point cloud and return the de-meaned representation - * \param[in] cloud_in the input point cloud - * \param[in] centroid the centroid of the point cloud - * \param[out] cloud_out the resultant output point cloud - * \ingroup common - */ - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const Eigen::Matrix ¢roid, - pcl::PointCloud &cloud_out); - - /** \brief Subtract a centroid from a point cloud and return the de-meaned representation - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] centroid the centroid of the point cloud - * \param cloud_out the resultant output point cloud - * \ingroup common - */ - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - const Eigen::Matrix ¢roid, - pcl::PointCloud &cloud_out); - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - const Eigen::Vector4f ¢roid, - pcl::PointCloud &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - const Eigen::Vector4d ¢roid, - pcl::PointCloud &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - /** \brief Subtract a centroid from a point cloud and return the de-meaned representation - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] centroid the centroid of the point cloud - * \param cloud_out the resultant output point cloud - * \ingroup common - */ - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices& indices, - const Eigen::Matrix ¢roid, - pcl::PointCloud &cloud_out); - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices& indices, - const Eigen::Vector4f ¢roid, - pcl::PointCloud &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices& indices, - const Eigen::Vector4d ¢roid, - pcl::PointCloud &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - - /** \brief Subtract a centroid from a point cloud and return the de-meaned - * representation as an Eigen matrix - * \param[in] cloud_in the input point cloud - * \param[in] centroid the centroid of the point cloud - * \param[out] cloud_out the resultant output XYZ0 dimensions of \a cloud_in as - * an Eigen matrix (4 rows, N pts columns) - * \ingroup common - */ - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const Eigen::Matrix ¢roid, - Eigen::Matrix &cloud_out); - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const Eigen::Vector4f ¢roid, - Eigen::MatrixXf &cloud_out) - { - return (demeanPointCloud (cloud_in, centroid, cloud_out)); - } - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const Eigen::Vector4d ¢roid, - Eigen::MatrixXd &cloud_out) - { - return (demeanPointCloud (cloud_in, centroid, cloud_out)); - } - - /** \brief Subtract a centroid from a point cloud and return the de-meaned - * representation as an Eigen matrix - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[in] centroid the centroid of the point cloud - * \param[out] cloud_out the resultant output XYZ0 dimensions of \a cloud_in as - * an Eigen matrix (4 rows, N pts columns) - * \ingroup common - */ - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - const Eigen::Matrix ¢roid, - Eigen::Matrix &cloud_out); - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - const Eigen::Vector4f ¢roid, - Eigen::MatrixXf &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - const Eigen::Vector4d ¢roid, - Eigen::MatrixXd &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - /** \brief Subtract a centroid from a point cloud and return the de-meaned - * representation as an Eigen matrix - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[in] centroid the centroid of the point cloud - * \param[out] cloud_out the resultant output XYZ0 dimensions of \a cloud_in as - * an Eigen matrix (4 rows, N pts columns) - * \ingroup common - */ - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices& indices, - const Eigen::Matrix ¢roid, - Eigen::Matrix &cloud_out); - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices& indices, - const Eigen::Vector4f ¢roid, - Eigen::MatrixXf &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - template void - demeanPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices& indices, - const Eigen::Vector4d ¢roid, - Eigen::MatrixXd &cloud_out) - { - return (demeanPointCloud (cloud_in, indices, centroid, cloud_out)); - } - - /** \brief General, all purpose nD centroid estimation for a set of points using their - * indices. - * \param cloud the input point cloud - * \param centroid the output centroid - * \ingroup common - */ - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - Eigen::Matrix ¢roid); - - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - Eigen::VectorXf ¢roid) - { - return (computeNDCentroid (cloud, centroid)); - } - - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - Eigen::VectorXd ¢roid) - { - return (computeNDCentroid (cloud, centroid)); - } - - /** \brief General, all purpose nD centroid estimation for a set of points using their - * indices. - * \param cloud the input point cloud - * \param indices the point cloud indices that need to be used - * \param centroid the output centroid - * \ingroup common - */ - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::Matrix ¢roid); - - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::VectorXf ¢roid) - { - return (computeNDCentroid (cloud, indices, centroid)); - } - - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - const std::vector &indices, - Eigen::VectorXd ¢roid) - { - return (computeNDCentroid (cloud, indices, centroid)); - } - - /** \brief General, all purpose nD centroid estimation for a set of points using their - * indices. - * \param cloud the input point cloud - * \param indices the point cloud indices that need to be used - * \param centroid the output centroid - * \ingroup common - */ - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::Matrix ¢roid); - - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::VectorXf ¢roid) - { - return (computeNDCentroid (cloud, indices, centroid)); - } - - template inline void - computeNDCentroid (const pcl::PointCloud &cloud, - const pcl::PointIndices &indices, - Eigen::VectorXd ¢roid) - { - return (computeNDCentroid (cloud, indices, centroid)); - } - - - /** Compute the centroid of a set of points and return it as a point. - * - * Implementation leverages \ref CentroidPoint class and therefore behaves - * differently from \ref compute3DCentroid() and \ref computeNDCentroid(). - * See \ref CentroidPoint documentation for explanation. - * - * \param[in] cloud input point cloud - * \param[out] centroid output centroid - * - * \return number of valid points used to determine the centroid (will be the - * same as the size of the cloud if it is dense) - * - * \note If return value is \c 0, then the centroid is not changed, thus is - * not valid. - * - * \ingroup common */ - template size_t - computeCentroid (const pcl::PointCloud& cloud, - PointOutT& centroid); - - /** Compute the centroid of a set of points and return it as a point. - * \param[in] cloud - * \param[in] indices point cloud indices that need to be used - * \param[out] centroid - * This is an overloaded function provided for convenience. See the - * documentation for computeCentroid(). - * - * \ingroup common */ - template size_t - computeCentroid (const pcl::PointCloud& cloud, - const std::vector& indices, - PointOutT& centroid); - -} - - -// #include "centroid.hpp" - - - - -/////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::compute3DCentroid( - const pcl::PointCloud& cloud, Eigen::Matrix& centroid) { - if (cloud.empty()) return (0); - - // Initialize to 0 - centroid.setZero(); - // For each point in the cloud - // If the data is dense, we don't need to check for NaN - if (cloud.is_dense) { - for (size_t i = 0; i < cloud.size(); ++i) { - centroid[0] += cloud[i].x; - centroid[1] += cloud[i].y; - centroid[2] += cloud[i].z; - } - centroid /= static_cast(cloud.size()); - centroid[3] = 1; - - return (static_cast(cloud.size())); - } - // NaN or Inf values could exist => check for them - unsigned cp = 0; - for (size_t i = 0; i < cloud.size(); ++i) { - // Check if the point is invalid - if (!isFinite(cloud[i])) continue; - - centroid[0] += cloud[i].x; - centroid[1] += cloud[i].y; - centroid[2] += cloud[i].z; - ++cp; - } - centroid /= static_cast(cp); - centroid[3] = 1; - - return (cp); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::compute3DCentroid( - const pcl::PointCloud& cloud, const std::vector& indices, Eigen::Matrix& centroid) { - if (indices.empty()) return (0); - - // Initialize to 0 - centroid.setZero(); - // If the data is dense, we don't need to check for NaN - if (cloud.is_dense) { - for (const int& index : indices) { - centroid[0] += cloud.points[index].x; - centroid[1] += cloud.points[index].y; - centroid[2] += cloud.points[index].z; - } - centroid /= static_cast(indices.size()); - centroid[3] = 1; - return (static_cast(indices.size())); - } - // NaN or Inf values could exist => check for them - unsigned cp = 0; - for (const int& index : indices) { - // Check if the point is invalid - if (!std::isfinite(cloud.points[index].x) || - !std::isfinite(cloud.points[index].y) || - !std::isfinite(cloud.points[index].z)) - continue; - - centroid[0] += cloud.points[index].x; - centroid[1] += cloud.points[index].y; - centroid[2] += cloud.points[index].z; - ++cp; - } - centroid /= static_cast(cp); - centroid[3] = 1; - return (cp); -} - -///////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::compute3DCentroid( - const pcl::PointCloud& cloud, const pcl::PointIndices& indices, Eigen::Matrix& centroid) { - return (pcl::compute3DCentroid(cloud, indices.indices, centroid)); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned pcl::computeCovarianceMatrix(const pcl::PointCloud& cloud, - const Eigen::Matrix& centroid, Eigen::Matrix& covariance_matrix) { - if (cloud.empty()) return (0); - - // Initialize to 0 - covariance_matrix.setZero(); - - unsigned point_count; - // If the data is dense, we don't need to check for NaN - if (cloud.is_dense) { - point_count = static_cast(cloud.size()); - // For each point in the cloud - for (size_t i = 0; i < point_count; ++i) { - Eigen::Matrix pt; - pt[0] = cloud[i].x - centroid[0]; - pt[1] = cloud[i].y - centroid[1]; - pt[2] = cloud[i].z - centroid[2]; - - covariance_matrix(1, 1) += pt.y() * pt.y(); - covariance_matrix(1, 2) += pt.y() * pt.z(); - - covariance_matrix(2, 2) += pt.z() * pt.z(); - - pt *= pt.x(); - covariance_matrix(0, 0) += pt.x(); - covariance_matrix(0, 1) += pt.y(); - covariance_matrix(0, 2) += pt.z(); - } - } - // NaN or Inf values could exist => check for them - else { - point_count = 0; - // For each point in the cloud - for (size_t i = 0; i < cloud.size(); ++i) { - // Check if the point is invalid - if (!isFinite(cloud[i])) continue; - - Eigen::Matrix pt; - pt[0] = cloud[i].x - centroid[0]; - pt[1] = cloud[i].y - centroid[1]; - pt[2] = cloud[i].z - centroid[2]; - - covariance_matrix(1, 1) += pt.y() * pt.y(); - covariance_matrix(1, 2) += pt.y() * pt.z(); - - covariance_matrix(2, 2) += pt.z() * pt.z(); - - pt *= pt.x(); - covariance_matrix(0, 0) += pt.x(); - covariance_matrix(0, 1) += pt.y(); - covariance_matrix(0, 2) += pt.z(); - ++point_count; - } - } - covariance_matrix(1, 0) = covariance_matrix(0, 1); - covariance_matrix(2, 0) = covariance_matrix(0, 2); - covariance_matrix(2, 1) = covariance_matrix(1, 2); - - return (point_count); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrixNormalized(const pcl::PointCloud& cloud, - const Eigen::Matrix& centroid, Eigen::Matrix& covariance_matrix) { - unsigned point_count = pcl::computeCovarianceMatrix(cloud, centroid, covariance_matrix); - if (point_count != 0) covariance_matrix /= static_cast(point_count); - return (point_count); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrix(const pcl::PointCloud& cloud, const std::vector& indices, - const Eigen::Matrix& centroid, Eigen::Matrix& covariance_matrix) { - if (indices.empty()) return (0); - - // Initialize to 0 - covariance_matrix.setZero(); - - size_t point_count; - // If the data is dense, we don't need to check for NaN - if (cloud.is_dense) { - point_count = indices.size(); - // For each point in the cloud - for (size_t i = 0; i < point_count; ++i) { - Eigen::Matrix pt; - pt[0] = cloud.points[indices[i]].x - centroid[0]; - pt[1] = cloud.points[indices[i]].y - centroid[1]; - pt[2] = cloud.points[indices[i]].z - centroid[2]; - - covariance_matrix(1, 1) += pt.y() * pt.y(); - covariance_matrix(1, 2) += pt.y() * pt.z(); - - covariance_matrix(2, 2) += pt.z() * pt.z(); - - pt *= pt.x(); - covariance_matrix(0, 0) += pt.x(); - covariance_matrix(0, 1) += pt.y(); - covariance_matrix(0, 2) += pt.z(); - } - } - // NaN or Inf values could exist => check for them - else { - point_count = 0; - // For each point in the cloud - for (const int& index : indices) { - // Check if the point is invalid - if (!std::isfinite(cloud.points[index].x) || !std::isfinite(cloud.points[index].y) || - !std::isfinite(cloud.points[index].z)) - continue; - - Eigen::Matrix pt; - pt[0] = cloud.points[index].x - centroid[0]; - pt[1] = cloud.points[index].y - centroid[1]; - pt[2] = cloud.points[index].z - centroid[2]; - - covariance_matrix(1, 1) += pt.y() * pt.y(); - covariance_matrix(1, 2) += pt.y() * pt.z(); - - covariance_matrix(2, 2) += pt.z() * pt.z(); - - pt *= pt.x(); - covariance_matrix(0, 0) += pt.x(); - covariance_matrix(0, 1) += pt.y(); - covariance_matrix(0, 2) += pt.z(); - ++point_count; - } - } - covariance_matrix(1, 0) = covariance_matrix(0, 1); - covariance_matrix(2, 0) = covariance_matrix(0, 2); - covariance_matrix(2, 1) = covariance_matrix(1, 2); - return (static_cast(point_count)); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrix(const pcl::PointCloud& cloud, const pcl::PointIndices& indices, - const Eigen::Matrix& centroid, Eigen::Matrix& covariance_matrix) { - return (pcl::computeCovarianceMatrix(cloud, indices.indices, centroid, covariance_matrix)); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrixNormalized(const pcl::PointCloud& cloud, - const std::vector& indices, const Eigen::Matrix& centroid, - Eigen::Matrix& covariance_matrix) { - unsigned point_count = pcl::computeCovarianceMatrix(cloud, indices, centroid, covariance_matrix); - if (point_count != 0) covariance_matrix /= static_cast(point_count); - - return (point_count); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrixNormalized(const pcl::PointCloud& cloud, - const pcl::PointIndices& indices, const Eigen::Matrix& centroid, - Eigen::Matrix& covariance_matrix) { - unsigned int point_count = pcl::computeCovarianceMatrix(cloud, indices.indices, centroid, covariance_matrix); - if (point_count != 0) covariance_matrix /= static_cast(point_count); - - return point_count; -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrix( - const pcl::PointCloud& cloud, Eigen::Matrix& covariance_matrix) { - // create the buffer on the stack which is much faster than using cloud[indices[i]] and centroid as a buffer - Eigen::Matrix accu = Eigen::Matrix::Zero(); - - unsigned int point_count; - if (cloud.is_dense) { - point_count = static_cast(cloud.size()); - // For each point in the cloud - for (size_t i = 0; i < point_count; ++i) { - accu[0] += cloud[i].x * cloud[i].x; - accu[1] += cloud[i].x * cloud[i].y; - accu[2] += cloud[i].x * cloud[i].z; - accu[3] += cloud[i].y * cloud[i].y; - accu[4] += cloud[i].y * cloud[i].z; - accu[5] += cloud[i].z * cloud[i].z; - } - } else { - point_count = 0; - for (size_t i = 0; i < cloud.size(); ++i) { - if (!isFinite(cloud[i])) continue; - - accu[0] += cloud[i].x * cloud[i].x; - accu[1] += cloud[i].x * cloud[i].y; - accu[2] += cloud[i].x * cloud[i].z; - accu[3] += cloud[i].y * cloud[i].y; - accu[4] += cloud[i].y * cloud[i].z; - accu[5] += cloud[i].z * cloud[i].z; - ++point_count; - } - } - - if (point_count != 0) { - accu /= static_cast(point_count); - covariance_matrix.coeffRef(0) = accu[0]; - covariance_matrix.coeffRef(1) = covariance_matrix.coeffRef(3) = accu[1]; - covariance_matrix.coeffRef(2) = covariance_matrix.coeffRef(6) = accu[2]; - covariance_matrix.coeffRef(4) = accu[3]; - covariance_matrix.coeffRef(5) = covariance_matrix.coeffRef(7) = accu[4]; - covariance_matrix.coeffRef(8) = accu[5]; - } - return (point_count); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrix(const pcl::PointCloud& cloud, const std::vector& indices, - Eigen::Matrix& covariance_matrix) { - // create the buffer on the stack which is much faster than using cloud[indices[i]] and centroid as a buffer - Eigen::Matrix accu = Eigen::Matrix::Zero(); - - unsigned int point_count; - if (cloud.is_dense) { - point_count = static_cast(indices.size()); - for (const int& index : indices) { - // const PointT& point = cloud[*iIt]; - accu[0] += cloud[index].x * cloud[index].x; - accu[1] += cloud[index].x * cloud[index].y; - accu[2] += cloud[index].x * cloud[index].z; - accu[3] += cloud[index].y * cloud[index].y; - accu[4] += cloud[index].y * cloud[index].z; - accu[5] += cloud[index].z * cloud[index].z; - } - } else { - point_count = 0; - for (const int& index : indices) { - if (!isFinite(cloud[index])) continue; - - ++point_count; - accu[0] += cloud[index].x * cloud[index].x; - accu[1] += cloud[index].x * cloud[index].y; - accu[2] += cloud[index].x * cloud[index].z; - accu[3] += cloud[index].y * cloud[index].y; - accu[4] += cloud[index].y * cloud[index].z; - accu[5] += cloud[index].z * cloud[index].z; - } - } - if (point_count != 0) { - accu /= static_cast(point_count); - covariance_matrix.coeffRef(0) = accu[0]; - covariance_matrix.coeffRef(1) = covariance_matrix.coeffRef(3) = accu[1]; - covariance_matrix.coeffRef(2) = covariance_matrix.coeffRef(6) = accu[2]; - covariance_matrix.coeffRef(4) = accu[3]; - covariance_matrix.coeffRef(5) = covariance_matrix.coeffRef(7) = accu[4]; - covariance_matrix.coeffRef(8) = accu[5]; - } - return (point_count); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeCovarianceMatrix(const pcl::PointCloud& cloud, const pcl::PointIndices& indices, - Eigen::Matrix& covariance_matrix) { - return (computeCovarianceMatrix(cloud, indices.indices, covariance_matrix)); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeMeanAndCovarianceMatrix(const pcl::PointCloud& cloud, - Eigen::Matrix& covariance_matrix, Eigen::Matrix& centroid) { - // create the buffer on the stack which is much faster than using cloud[indices[i]] and centroid as a buffer - Eigen::Matrix accu = Eigen::Matrix::Zero(); - size_t point_count; - if (cloud.is_dense) { - point_count = cloud.size(); - // For each point in the cloud - for (size_t i = 0; i < point_count; ++i) { - accu[0] += cloud[i].x * cloud[i].x; - accu[1] += cloud[i].x * cloud[i].y; - accu[2] += cloud[i].x * cloud[i].z; - accu[3] += cloud[i].y * cloud[i].y; // 4 - accu[4] += cloud[i].y * cloud[i].z; // 5 - accu[5] += cloud[i].z * cloud[i].z; // 8 - accu[6] += cloud[i].x; - accu[7] += cloud[i].y; - accu[8] += cloud[i].z; - } - } else { - point_count = 0; - for (size_t i = 0; i < cloud.size(); ++i) { - if (!isFinite(cloud[i])) continue; - - accu[0] += cloud[i].x * cloud[i].x; - accu[1] += cloud[i].x * cloud[i].y; - accu[2] += cloud[i].x * cloud[i].z; - accu[3] += cloud[i].y * cloud[i].y; - accu[4] += cloud[i].y * cloud[i].z; - accu[5] += cloud[i].z * cloud[i].z; - accu[6] += cloud[i].x; - accu[7] += cloud[i].y; - accu[8] += cloud[i].z; - ++point_count; - } - } - accu /= static_cast(point_count); - if (point_count != 0) { - // centroid.head<3> () = accu.tail<3> (); -- does not compile with Clang 3.0 - centroid[0] = accu[6]; - centroid[1] = accu[7]; - centroid[2] = accu[8]; - centroid[3] = 1; - covariance_matrix.coeffRef(0) = accu[0] - accu[6] * accu[6]; - covariance_matrix.coeffRef(1) = accu[1] - accu[6] * accu[7]; - covariance_matrix.coeffRef(2) = accu[2] - accu[6] * accu[8]; - covariance_matrix.coeffRef(4) = accu[3] - accu[7] * accu[7]; - covariance_matrix.coeffRef(5) = accu[4] - accu[7] * accu[8]; - covariance_matrix.coeffRef(8) = accu[5] - accu[8] * accu[8]; - covariance_matrix.coeffRef(3) = covariance_matrix.coeff(1); - covariance_matrix.coeffRef(6) = covariance_matrix.coeff(2); - covariance_matrix.coeffRef(7) = covariance_matrix.coeff(5); - } - return (static_cast(point_count)); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeMeanAndCovarianceMatrix(const pcl::PointCloud& cloud, - const std::vector& indices, Eigen::Matrix& covariance_matrix, - Eigen::Matrix& centroid) { - // create the buffer on the stack which is much faster than using cloud[indices[i]] and centroid as a buffer - Eigen::Matrix accu = Eigen::Matrix::Zero(); - size_t point_count; - if (cloud.is_dense) { - point_count = indices.size(); - for (const int& index : indices) { - // const PointT& point = cloud[*iIt]; - accu[0] += cloud.points[index].x * cloud.points[index].x; - accu[1] += cloud.points[index].x * cloud.points[index].y; - accu[2] += cloud.points[index].x * cloud.points[index].z; - accu[3] += cloud.points[index].y * cloud.points[index].y; - accu[4] += cloud.points[index].y * cloud.points[index].z; - accu[5] += cloud.points[index].z * cloud.points[index].z; - accu[6] += cloud.points[index].x; - accu[7] += cloud.points[index].y; - accu[8] += cloud.points[index].z; - } - } else { - point_count = 0; - for (const int& index : indices) { - if (!(cloud.points[index].isfinite())) continue; - - ++point_count; - accu[0] += cloud.points[index].x * cloud.points[index].x; - accu[1] += cloud.points[index].x * cloud.points[index].y; - accu[2] += cloud.points[index].x * cloud.points[index].z; - accu[3] += cloud.points[index].y * cloud.points[index].y; // 4 - accu[4] += cloud.points[index].y * cloud.points[index].z; // 5 - accu[5] += cloud.points[index].z * cloud.points[index].z; // 8 - accu[6] += cloud.points[index].x; - accu[7] += cloud.points[index].y; - accu[8] += cloud.points[index].z; - } - } - - accu /= static_cast(point_count); - // Eigen::Vector3f vec = accu.tail<3> (); - // centroid.head<3> () = vec;//= accu.tail<3> (); - // centroid.head<3> () = accu.tail<3> (); -- does not compile with Clang 3.0 - centroid[0] = accu[6]; - centroid[1] = accu[7]; - centroid[2] = accu[8]; - centroid[3] = 1; - covariance_matrix.coeffRef(0) = accu[0] - accu[6] * accu[6]; - covariance_matrix.coeffRef(1) = accu[1] - accu[6] * accu[7]; - covariance_matrix.coeffRef(2) = accu[2] - accu[6] * accu[8]; - covariance_matrix.coeffRef(4) = accu[3] - accu[7] * accu[7]; - covariance_matrix.coeffRef(5) = accu[4] - accu[7] * accu[8]; - covariance_matrix.coeffRef(8) = accu[5] - accu[8] * accu[8]; - covariance_matrix.coeffRef(3) = covariance_matrix.coeff(1); - covariance_matrix.coeffRef(6) = covariance_matrix.coeff(2); - covariance_matrix.coeffRef(7) = covariance_matrix.coeff(5); - - return (static_cast(point_count)); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -inline unsigned int pcl::computeMeanAndCovarianceMatrix(const pcl::PointCloud& cloud, - const pcl::PointIndices& indices, Eigen::Matrix& covariance_matrix, - Eigen::Matrix& centroid) { - return (computeMeanAndCovarianceMatrix(cloud, indices.indices, covariance_matrix, centroid)); -} - - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::demeanPointCloud(const pcl::PointCloud& cloud_in, const Eigen::Matrix& centroid, - pcl::PointCloud& cloud_out) { - cloud_out = cloud_in; - - // Subtract the centroid from cloud_in - for (size_t i = 0; i < cloud_in.points.size(); ++i) { - cloud_out.points[i].x -= static_cast(centroid[0]); - cloud_out.points[i].y -= static_cast(centroid[1]); - cloud_out.points[i].z -= static_cast(centroid[2]); - } -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::demeanPointCloud(const pcl::PointCloud& cloud_in, const std::vector& indices, - const Eigen::Matrix& centroid, pcl::PointCloud& cloud_out) { - cloud_out.header = cloud_in.header; - cloud_out.is_dense = cloud_in.is_dense; - if (indices.size() == cloud_in.points.size()) { - cloud_out.width = cloud_in.width; - cloud_out.height = cloud_in.height; - } else { - cloud_out.width = static_cast(indices.size()); - cloud_out.height = 1; - } - cloud_out.points.resize(indices.size()); - - // Subtract the centroid from cloud_in - for (size_t i = 0; i < indices.size(); ++i) { - cloud_out.points[i].x = static_cast(cloud_in.points[indices[i]].x - centroid[0]); - cloud_out.points[i].y = static_cast(cloud_in.points[indices[i]].y - centroid[1]); - cloud_out.points[i].z = static_cast(cloud_in.points[indices[i]].z - centroid[2]); - } -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::demeanPointCloud(const pcl::PointCloud& cloud_in, const pcl::PointIndices& indices, - const Eigen::Matrix& centroid, pcl::PointCloud& cloud_out) { - return (demeanPointCloud(cloud_in, indices.indices, centroid, cloud_out)); -} - - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::demeanPointCloud(const pcl::PointCloud& cloud_in, const Eigen::Matrix& centroid, - Eigen::Matrix& cloud_out) { - size_t npts = cloud_in.size(); - - cloud_out = Eigen::Matrix::Zero(4, npts); // keep the data aligned - - for (size_t i = 0; i < npts; ++i) { - cloud_out(0, i) = cloud_in[i].x - centroid[0]; - cloud_out(1, i) = cloud_in[i].y - centroid[1]; - cloud_out(2, i) = cloud_in[i].z - centroid[2]; - // One column at a time - // cloud_out.block<4, 1> (0, i) = cloud_in.points[i].getVector4fMap () - centroid; - } - - // Make sure we zero the 4th dimension out (1 row, N columns) - // cloud_out.block (3, 0, 1, npts).setZero (); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::demeanPointCloud(const pcl::PointCloud& cloud_in, const std::vector& indices, - const Eigen::Matrix& centroid, Eigen::Matrix& cloud_out) { - size_t npts = indices.size(); - - cloud_out = Eigen::Matrix::Zero(4, npts); // keep the data aligned - - for (size_t i = 0; i < npts; ++i) { - cloud_out(0, i) = cloud_in[indices[i]].x - centroid[0]; - cloud_out(1, i) = cloud_in[indices[i]].y - centroid[1]; - cloud_out(2, i) = cloud_in[indices[i]].z - centroid[2]; - // One column at a time - // cloud_out.block<4, 1> (0, i) = cloud_in.points[indices[i]].getVector4fMap () - centroid; - } - - // Make sure we zero the 4th dimension out (1 row, N columns) - // cloud_out.block (3, 0, 1, npts).setZero (); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::demeanPointCloud(const pcl::PointCloud& cloud_in, const pcl::PointIndices& indices, - const Eigen::Matrix& centroid, Eigen::Matrix& cloud_out) { - return (pcl::demeanPointCloud(cloud_in, indices.indices, centroid, cloud_out)); -} - - -///////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::computeNDCentroid(const pcl::PointCloud& cloud, const pcl::PointIndices& indices, - Eigen::Matrix& centroid) { - return (pcl::computeNDCentroid(cloud, indices.indices, centroid)); -} - diff --git a/plugins/probe/3rd/common.h b/plugins/probe/3rd/common.h deleted file mode 100644 index e640f78a61..0000000000 --- a/plugins/probe/3rd/common.h +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * - */ - -#pragma once - -#include "mmcore/utility/log/Log.h" -#include -#include -#include -#include -#include -#include - -#ifdef _DEBUG -#define PCL_DEBUG megamol::core::utility::log::Log::DefaultLog.WriteWarn -#else -// most hacky solution just to make michael more happy :,( -namespace { -inline auto do_nothing = [](auto... xs) {}; -} -#define PCL_DEBUG do_nothing -#endif - -namespace pcl { - -using Indices = std::vector; -using IndicesPtr = std::shared_ptr; -using IndicesConstPtr = std::shared_ptr; - -struct Vertices { - Vertices() {} - - std::array vertices; - -public: - using Ptr = std::shared_ptr; - using ConstPtr = std::shared_ptr; -}; // struct Vertices - - -struct _PointXYZ { - union EIGEN_ALIGN16 { - float data[4]; - struct { - float x; - float y; - float z; - }; - }; - - // inline pcl::Vector3fMap getVector3fMap() { return (pcl::Vector3fMap(data)); } - // inline pcl::Vector3fMapConst getVector3fMap() const { return (pcl::Vector3fMapConst(data)); } - // inline pcl::Vector4fMap getVector4fMap() { return (pcl::Vector4fMap(data)); } - // inline pcl::Vector4fMapConst getVector4fMap() const { return (pcl::Vector4fMapConst(data)); } - // inline pcl::Array3fMap getArray3fMap() { return (pcl::Array3fMap(data)); } - // inline pcl::Array3fMapConst getArray3fMap() const { return (pcl::Array3fMapConst(data)); } - // inline pcl::Array4fMap getArray4fMap() { return (pcl::Array4fMap(data)); } - // inline pcl::Array4fMapConst getArray4fMap() const { return (pcl::Array4fMapConst(data)); } - - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -}; - -/** \brief A point structure representing Euclidean xyz coordinates. (SSE friendly) - * \ingroup common - */ -struct EIGEN_ALIGN16 PointXYZ : public _PointXYZ { - inline PointXYZ(const _PointXYZ& p) { - x = p.x; - y = p.y; - z = p.z; - data[3] = 1.0f; - } - - inline PointXYZ() { - x = y = z = 0.0f; - data[3] = 1.0f; - } - - inline PointXYZ(float _x, float _y, float _z) { - x = _x; - y = _y; - z = _z; - data[3] = 1.0f; - } - - inline PointXYZ operator-(const PointXYZ& rhs) const { - return PointXYZ(this->x - rhs.x, this->y - rhs.y, this->z - rhs.z); - } - - typedef float value_t; - - inline bool isfinite() const { - return (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)); - } - - friend std::ostream& operator<<(std::ostream& os, const PointXYZ& p); - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -}; - - -struct EIGEN_ALIGN16 _PointNormal { - // This adds the members x,y,z which can also be accessed using the point (which is float[4]) - union EIGEN_ALIGN16 { - float data[4]; - struct { - float x; - float y; - float z; - }; - }; - // This adds the member normal[3] which can also be accessed using the point (which is float[4]) - union EIGEN_ALIGN16 { - float data_n[4]; - float normal[3]; - struct { - float normal_x; - float normal_y; - float normal_z; - }; - }; - union { - struct { - float curvature; - }; - float data_c[4]; - }; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -}; - -/** \brief A point structure representing Euclidean xyz coordinates, together with normal coordinates and the surface - * curvature estimate. (SSE friendly) \ingroup common - */ -struct PointNormal : public _PointNormal { - inline PointNormal(const _PointNormal& p) { - x = p.x; - y = p.y; - z = p.z; - data[3] = 1.0f; - normal_x = p.normal_x; - normal_y = p.normal_y; - normal_z = p.normal_z; - data_n[3] = 0.0f; - curvature = p.curvature; - } - - inline PointNormal() { - x = y = z = 0.0f; - data[3] = 1.0f; - normal_x = normal_y = normal_z = data_n[3] = 0.0f; - curvature = 0.f; - } - - inline bool isfinite() const { - return (std::isfinite(x) && std::isfinite(y) && std::isfinite(z) && std::isfinite(normal_x) && - std::isfinite(normal_y) && std::isfinite(normal_z)); - } - typedef float value_t; -}; - - -struct PCLHeader { - PCLHeader() : seq(0), stamp() {} - - /** \brief Sequence number */ - uint32_t seq; - /** \brief A timestamp associated with the time when the data was acquired - * - * The value represents microseconds since 1970-01-01 00:00:00 (the UNIX epoch). - */ - uint64_t stamp; - /** \brief Coordinate frame ID */ - std::string frame_id; - - using Ptr = std::shared_ptr; - using ConstPtr = std::shared_ptr; -}; // struct PCLHeader - - -struct PointIndices { - PointIndices() = default; - - PCLHeader header; - - std::vector indices; - -public: - using Ptr = std::shared_ptr; - using ConstPtr = std::shared_ptr; -}; // struct PointIndices - - -/////////////////////////////////////////////////////////////////////////////////// -template -class PointCloud { -public: - PointCloud() = default; - ~PointCloud() = default; - /** \brief The point data. */ - std::vector> points; - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - - typedef PointT coord_t; - - /** \brief The point cloud header. It contains information about the acquisition time. */ - PCLHeader header; - /** \brief The point cloud width (if organized as an image-structure). */ - uint32_t width; - /** \brief The point cloud height (if organized as an image-structure). */ - uint32_t height; - /** \brief True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields). */ - bool is_dense; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -/** \brief PCL base class. Implements methods that are used by most PCL algorithms. - * \ingroup common - */ -template -class PCLBase { -public: - using PointCloud = pcl::PointCloud; - using PointCloudPtr = typename PointCloud::Ptr; - using PointCloudConstPtr = typename PointCloud::ConstPtr; - - using PointIndicesPtr = std::shared_ptr; - using PointIndicesConstPtr = std::shared_ptr; - - /** \brief Empty constructor. */ - PCLBase(); - - /** \brief Copy constructor. */ - PCLBase(const PCLBase& base); - -protected: - /** \brief Destructor. */ - ~PCLBase() { - input_.reset(); - indices_.reset(); - } - - /** \brief The input point cloud dataset. */ - PointCloudConstPtr input_; - - /** \brief A pointer to the vector of point indices to use. */ - IndicesPtr indices_; - - /** \brief Set to true if point indices are used. */ - bool use_indices_; - - /** \brief If no set of indices are given, we construct a set of fake indices that mimic the input PointCloud. */ - bool fake_indices_; - - /** \brief This method should get called before starting the actual computation. - * - * Internally, initCompute() does the following: - * - checks if an input dataset is given, and returns false otherwise - * - checks whether a set of input indices has been given. Returns true if yes. - * - if no input indices have been given, a fake set is created, which will be used until: - * - either a new set is given via setIndices(), or - * - a new cloud is given that has a different set of points. This will trigger an update on the set of fake - * indices - */ - bool initCompute(); - - /** \brief This method should get called after finishing the actual computation. - */ - bool deinitCompute(); - - /** \brief Provide a pointer to the input dataset - * \param[in] cloud the const shared pointer to a PointCloud message - */ - virtual void setInputCloud(const PointCloudConstPtr& cloud); - - /** \brief Get a pointer to the input point cloud dataset. */ - inline PointCloudConstPtr const getInputCloud() const { - return (input_); - } - - /** \brief Provide a pointer to the vector of indices that represents the input data. - * \param[in] indices a pointer to the indices that represent the input data. - */ - virtual void setIndices(const IndicesPtr& indices); - - /** \brief Provide a pointer to the vector of indices that represents the input data. - * \param[in] indices a pointer to the indices that represent the input data. - */ - virtual void setIndices(const IndicesConstPtr& indices); - - /** \brief Provide a pointer to the vector of indices that represents the input data. - * \param[in] indices a pointer to the indices that represent the input data. - */ - virtual void setIndices(const PointIndicesConstPtr& indices); - - /** \brief Set the indices for the points laying within an interest region of - * the point cloud. - * \note you shouldn't call this method on unorganized point clouds! - * \param[in] row_start the offset on rows - * \param[in] col_start the offset on columns - * \param[in] nb_rows the number of rows to be considered row_start included - * \param[in] nb_cols the number of columns to be considered col_start included - */ - virtual void setIndices(size_t row_start, size_t col_start, size_t nb_rows, size_t nb_cols); - - /** \brief Get a pointer to the vector of indices used. */ - inline IndicesPtr const getIndices() { - return (indices_); - } - - /** \brief Get a pointer to the vector of indices used. */ - inline IndicesConstPtr const getIndices() const { - return (indices_); - } - - /** \brief Override PointCloud operator[] to shorten code - * \note this method can be called instead of (*input_)[(*indices_)[pos]] - * or input_->points[(*indices_)[pos]] - * \param[in] pos position in indices_ vector - */ - inline const PointT& operator[](size_t pos) const { - return ((*input_)[(*indices_)[pos]]); - } - -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -}; - -////////////////////////////////////////////////////////////////////////////////////////////// -/** \brief Compute the radius of a circumscribed circle for a triangle formed of three points pa, pb, and pc - * \param pa the first point - * \param pb the second point - * \param pc the third point - * \return the radius of the circumscribed circle - * \ingroup common - */ -template -inline double getCircumcircleRadius(const PointT& pa, const PointT& pb, const PointT& pc); - - -template -inline double getCircumcircleRadius(const PointT& pa, const PointT& pb, const PointT& pc) { - Eigen::Vector4f p1(pa.x, pa.y, pa.z, 0); - Eigen::Vector4f p2(pb.x, pb.y, pb.z, 0); - Eigen::Vector4f p3(pc.x, pc.y, pc.z, 0); - - double p2p1 = (p2 - p1).norm(), p3p2 = (p3 - p2).norm(), p1p3 = (p1 - p3).norm(); - // Calculate the area of the triangle using Heron's formula - // (http://en.wikipedia.org/wiki/Heron's_formula) - double semiperimeter = (p2p1 + p3p2 + p1p3) / 2.0; - double area = sqrt(semiperimeter * (semiperimeter - p2p1) * (semiperimeter - p3p2) * (semiperimeter - p1p3)); - // Compute the radius of the circumscribed circle - return ((p2p1 * p3p2 * p1p3) / (4.0 * area)); -} - - -////////////////////////////////////////////////////////////////////////////////////////////// -/** \brief Extract the indices of a given point cloud as a new point cloud - * \param[in] cloud_in the input point cloud dataset - * \param[in] indices the vector of indices representing the points to be copied from \a cloud_in - * \param[out] cloud_out the resultant output point cloud dataset - * \note Assumes unique indices. - * \ingroup common - */ -template -inline void copyPointCloud( - const pcl::PointCloud& cloud_in, const std::vector& indices, pcl::PointCloud& cloud_out); - -template -void copyPointCloud( - const pcl::PointCloud& cloud_in, const std::vector& indices, pcl::PointCloud& cloud_out) { - // Do we want to copy everything? - if (indices.size() == cloud_in.points.size()) { - cloud_out = cloud_in; - return; - } - - // Allocate enough space and copy the basics - cloud_out.points.resize(indices.size()); - cloud_out.header = cloud_in.header; - cloud_out.width = static_cast(indices.size()); - cloud_out.height = 1; - cloud_out.is_dense = cloud_in.is_dense; - // cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_; - // cloud_out.sensor_origin_ = cloud_in.sensor_origin_; - - // Iterate over each point - for (size_t i = 0; i < indices.size(); ++i) - cloud_out.points[i] = cloud_in.points[indices[i]]; -} - -////////////////////////////////////////////////////////////////////////////////////////////// - -/** \brief @b PointRepresentation provides a set of methods for converting a point structs/object into an - * n-dimensional vector. - * \note This is an abstract class. Subclasses must set nr_dimensions_ to the appropriate value in the constructor - * and provide an implementation of the pure virtual copyToFloatArray method. - * \author Michael Dixon - */ -template -class PointRepresentation { -protected: - /** \brief The number of dimensions in this point's vector (i.e. the "k" in "k-D") */ - int nr_dimensions_; - /** \brief A vector containing the rescale factor to apply to each dimension. */ - std::vector alpha_; - /** \brief Indicates whether this point representation is trivial. It is trivial if and only if the following - * conditions hold: - * - the relevant data consists only of float values - * - the vectorize operation directly copies the first nr_dimensions_ elements of PointT to the out array - * - sizeof(PointT) is a multiple of sizeof(float) - * In short, a trivial point representation converts the input point to a float array that is the same as if - * the point was reinterpret_casted to a float array of length nr_dimensions_ . This value says that this - * representation can be trivial; it is only trivial if setRescaleValues() has not been set. - */ - bool trivial_; - -public: - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - - /** \brief Empty constructor */ - PointRepresentation() : nr_dimensions_(0), alpha_(0), trivial_(false) {} - - /** \brief Empty destructor */ - virtual ~PointRepresentation() {} - - /** \brief Copy point data from input point to a float array. This method must be overridden in all subclasses. - * \param[in] p The input point - * \param[out] out A pointer to a float array. - */ - virtual void copyToFloatArray(const PointT& p, float* out) const = 0; - - /** \brief Returns whether this point representation is trivial. It is trivial if and only if the following - * conditions hold: - * - the relevant data consists only of float values - * - the vectorize operation directly copies the first nr_dimensions_ elements of PointT to the out array - * - sizeof(PointT) is a multiple of sizeof(float) - * In short, a trivial point representation converts the input point to a float array that is the same as if - * the point was reinterpret_casted to a float array of length nr_dimensions_ . */ - inline bool isTrivial() const { - return trivial_ && alpha_.empty(); - } - - /** \brief Verify that the input point is valid. - * \param p The point to validate - */ - virtual bool isValid(const PointT& p) const { - bool is_valid = true; - - if (trivial_) { - const float* temp = reinterpret_cast(&p); - - for (int i = 0; i < nr_dimensions_; ++i) { - if (!std::isfinite(temp[i])) { - is_valid = false; - break; - } - } - } else { - float* temp = new float[nr_dimensions_]; - copyToFloatArray(p, temp); - - for (int i = 0; i < nr_dimensions_; ++i) { - if (!std::isfinite(temp[i])) { - is_valid = false; - break; - } - } - delete[] temp; - } - return (is_valid); - } - - /** \brief Convert input point into a vector representation, rescaling by \a alpha. - * \param[in] p the input point - * \param[out] out The output vector. Can be of any type that implements the [] operator. - */ - template - void vectorize(const PointT& p, OutputType& out) const { - float* temp = new float[nr_dimensions_]; - copyToFloatArray(p, temp); - if (alpha_.empty()) { - for (int i = 0; i < nr_dimensions_; ++i) - out[i] = temp[i]; - } else { - for (int i = 0; i < nr_dimensions_; ++i) - out[i] = temp[i] * alpha_[i]; - } - delete[] temp; - } - - /** \brief Set the rescale values to use when vectorizing points - * \param[in] rescale_array The array/vector of rescale values. Can be of any type that implements the [] operator. - */ - void setRescaleValues(const float* rescale_array) { - alpha_.resize(nr_dimensions_); - for (int i = 0; i < nr_dimensions_; ++i) - alpha_[i] = rescale_array[i]; - } - - /** \brief Return the number of dimensions in the point's vector representation. */ - inline int getNumberOfDimensions() const { - return (nr_dimensions_); - } -}; - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/** \brief @b DefaultPointRepresentation extends PointRepresentation to define default behavior for common point types. - */ -template -class DefaultPointRepresentation : public PointRepresentation { - using PointRepresentation::nr_dimensions_; - using PointRepresentation::trivial_; - -public: - // Boost shared pointers - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - - DefaultPointRepresentation() { - // If point type is unknown, assume it's a struct/array of floats, and compute the number of dimensions - nr_dimensions_ = sizeof(PointDefault) / sizeof(float); - // Limit the default representation to the first 3 elements - if (nr_dimensions_ > 3) - nr_dimensions_ = 3; - - trivial_ = true; - } - - ~DefaultPointRepresentation() {} - - inline Ptr makeShared() const { - return (Ptr(new DefaultPointRepresentation(*this))); - } - - void copyToFloatArray(const PointDefault& p, float* out) const override { - // If point type is unknown, treat it as a struct/array of floats - const float* ptr = reinterpret_cast(&p); - for (int i = 0; i < nr_dimensions_; ++i) - out[i] = ptr[i]; - } -}; - - -template -pcl::PCLBase::PCLBase() : input_() - , use_indices_(false) - , fake_indices_(false) {} - -template -pcl::PCLBase::PCLBase(const PCLBase& base) - : input_(base.input_) - , indices_(base.indices_) - , use_indices_(base.use_indices_) - , fake_indices_(base.fake_indices_) {} - -template -void pcl::PCLBase::setInputCloud(const PointCloudConstPtr& cloud) { - input_ = cloud; -} - - -template -void pcl::PCLBase::setIndices(const IndicesPtr& indices) { - indices_ = indices; - fake_indices_ = false; - use_indices_ = true; -} - -template -void pcl::PCLBase::setIndices(const IndicesConstPtr& indices) { - indices_.reset(new std::vector(*indices)); - fake_indices_ = false; - use_indices_ = true; -} - - -template -void pcl::PCLBase::setIndices(const PointIndicesConstPtr& indices) { - indices_.reset(new std::vector(indices->indices)); - fake_indices_ = false; - use_indices_ = true; -} - - -template -void pcl::PCLBase::setIndices(size_t row_start, size_t col_start, size_t nb_rows, size_t nb_cols) { - if ((nb_rows > input_->height) || (row_start > input_->height)) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[PCLBase::setIndices] cloud is only %d height", input_->height); - return; - } - - if ((nb_cols > input_->width) || (col_start > input_->width)) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[PCLBase::setIndices] cloud is only %d width", input_->width); - return; - } - - size_t row_end = row_start + nb_rows; - if (row_end > input_->height) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[PCLBase::setIndices] %d is out of rows range %d", row_end, input_->height); - return; - } - - size_t col_end = col_start + nb_cols; - if (col_end > input_->width) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[PCLBase::setIndices] %d is out of columns range %d", col_end, input_->width); - return; - } - - indices_.reset(new std::vector); - indices_->reserve(nb_cols * nb_rows); - for (size_t i = row_start; i < row_end; i++) - for (size_t j = col_start; j < col_end; j++) - indices_->push_back(static_cast((i * input_->width) + j)); - fake_indices_ = false; - use_indices_ = true; -} - -template -bool pcl::PCLBase::initCompute() { - // Check if input was set - if (!input_) - return (false); - - // If no point indices have been given, construct a set of indices for the entire input point cloud - if (!indices_) { - fake_indices_ = true; - indices_.reset(new std::vector); - } - - // If we have a set of fake indices, but they do not match the number of points in the cloud, update them - if (fake_indices_ && indices_->size() != input_->points.size()) { - size_t indices_size = indices_->size(); - try { - indices_->resize(input_->points.size()); - } catch (const std::bad_alloc&) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[initCompute] Failed to allocate %lu indices.\n", input_->points.size()); - } - for (size_t i = indices_size; i < indices_->size(); ++i) { - (*indices_)[i] = static_cast(i); - } - } - - return (true); -} - -template -bool pcl::PCLBase::deinitCompute() { - return (true); -} - -#define PCL_INSTANTIATE_PCLBase(T) template class PCL_EXPORTS pcl::PCLBase; - - -} // namespace pcl diff --git a/plugins/probe/3rd/concave_hull.h b/plugins/probe/3rd/concave_hull.h deleted file mode 100644 index 4e65feba27..0000000000 --- a/plugins/probe/3rd/concave_hull.h +++ /dev/null @@ -1,722 +0,0 @@ -/* - * Software License Agreement(BSD License) - * - * Point Cloud Library(PCL) - www.pointclouds.org - * Copyright(c) 2009-2012, Willow Garage, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#pragma once - -#include "centroid.h" -#include "common.h" -#include "eigen.h" -#include "kdtree.h" -extern "C" { -#define qh_dllimport -#include "libqhull/geom.h" -#include "libqhull/libqhull.h" -#include "libqhull/merge.h" -} -#include "mmcore/utility/log/Log.h" -#include "transforms.h" - -namespace pcl { - - -//////////////////////////////////////////////////////////////////////////////////////////// -/** \brief @b ConcaveHull(alpha shapes) using libqhull library. - * \author Aitor Aldoma - * \ingroup surface - */ -template -class ConcaveHull : public PCLBase { -protected: - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - -public: - using PointCloud = PointCloud; - using PointCloudPtr = typename PointCloud::Ptr; - using PointCloudConstPtr = typename PointCloud::ConstPtr; - - /** \brief Empty constructor. */ - ConcaveHull() : alpha_(0), keep_information_(false), voronoi_centers_(), dim_(0){}; - - /** \brief Empty destructor */ - virtual ~ConcaveHull() {} - - /** \brief Compute a concave hull for all points given - * - * \param points the resultant points lying on the concave hull - * \param polygons the resultant concave hull polygons, as a set of - * vertices. The Vertices structure contains an array of point indices. - */ - void reconstruct(PointCloud& points, std::vector& polygons); - - - /** \brief Sets data input - * - * \param the input cloud - */ - void setInputCloud(const PointCloudConstPtr& input) override; - - /** \brief Set the alpha value, which limits the size of the resultant - * hull segments(the smaller the more detailed the hull). - * - * \param alpha positive, non-zero value, defining the maximum length - * from a vertex to the facet center(center of the voronoi cell). - */ - inline void setAlpha(double alpha) { - alpha_ = alpha; - } - - /** \brief Returns the alpha parameter, see setAlpha(). */ - inline double getAlpha() { - return (alpha_); - } - - /** \brief If set, the voronoi cells center will be saved in _voronoi_centers_ - * \param voronoi_centers - */ - inline void setVoronoiCenters(PointCloudPtr voronoi_centers) { - voronoi_centers_ = voronoi_centers; - } - - /** \brief If keep_information_is set to true the convex hull - * points keep other information like rgb, normals, ... - * \param value where to keep the information or not, default is false - */ - void setKeepInformation(bool value) { - keep_information_ = value; - } - - /** \brief Additional filtering for less errors in the surface - */ - void setDoFiltering(bool value) { - do_filtering_ = value; - } - - /** \brief Returns the dimensionality(2 or 3) of the calculated hull. */ - inline int getDimension() const { - return (dim_); - } - - /** \brief Sets the dimension on the input data, 2D or 3D. - * \param[in] dimension The dimension of the input data. If not set, this will be determined automatically. - */ - void setDimension(int dimension) { - if ((dimension == 2) || (dimension == 3)) - dim_ = dimension; - else - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::setDimension] Invalid input dimension specified!\n", getClassName().c_str()); - } - - /** \brief Retrieve the indices of the input point cloud that for the convex hull. - * - * \note Should only be called after reconstruction was performed and if the ConcaveHull is - * set to preserve information via setKeepInformation(). - * - * \param[out] hull_point_indices The indices of the points forming the point cloud - */ - void getHullPointIndices(pcl::PointIndices& hull_point_indices) const; - -protected: - /** \brief Class get name method. */ - static std::string getClassName() { - return ("ConcaveHull"); - } - -protected: - /** \brief The actual reconstruction method. - * - * \param alpha_shape the resultant points lying on the concave hull - * \param polygons the resultant concave hull polygons, as a set of - * vertices. The Vertices structure contains an array of point indices. - */ - void performReconstruction(PointCloud& alpha_shape, std::vector& polygons); - - - /** \brief The method accepts facets only if the distance from any vertex to the facet->center - *(center of the voronoi cell) is smaller than alpha - */ - double alpha_; - - /** \brief If set to true, the reconstructed point cloud describing the hull is obtained from - * the original input cloud by performing a nearest neighbor search from Qhull output. - */ - bool keep_information_; - - /** \brief If set to true, the reconstructed point cloud is filtered using the kd tree - */ - bool do_filtering_ = false; - - /** \brief the centers of the voronoi cells */ - PointCloudPtr voronoi_centers_; - - /** \brief the dimensionality of the concave hull */ - int dim_; - - /** \brief vector containing the point cloud indices of the convex hull points. */ - PointIndices hull_indices_; - - ///** \brief The input point cloud dataset. */ - // PointCloudConstPtr this->input_; - - ///** \brief A pointer to the vector of point indices to use. */ - // IndicesPtr this->indices_; -}; - - -//#include "concave_hull.hpp" - - -////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::ConcaveHull::getHullPointIndices(pcl::PointIndices& hull_point_indices) const { - hull_point_indices = hull_indices_; -} - -#define PCL_INSTANTIATE_ConcaveHull(T) template class PCL_EXPORTS pcl::ConcaveHull; - - -////////////////////////////////////////////////////////////////////////// -template -void pcl::ConcaveHull::setInputCloud(const PointCloudConstPtr& input) { - this->input_ = input; -} - -template -void pcl::ConcaveHull::reconstruct(PointCloud& output, std::vector& polygons) { - // output.header = this->input_->header; - if (alpha_ <= 0) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::reconstruct] Alpha parameter must be set to a positive number!\n", getClassName().c_str()); - output.points.clear(); - return; - } - - if (!this->initCompute()) { - output.points.clear(); - return; - } - - // Perform the actual surface reconstruction - performReconstruction(output, polygons); - - output.width = static_cast(output.points.size()); - output.height = 1; - output.is_dense = true; - - this->deinitCompute(); -} - -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wold-style-cast" -#endif -////////////////////////////////////////////////////////////////////////// -template -void pcl::ConcaveHull::performReconstruction(PointCloud& alpha_shape, std::vector& polygons) { - Eigen::Vector4d xyz_centroid; - compute3DCentroid(*this->input_, *this->indices_, xyz_centroid); - EIGEN_ALIGN16 Eigen::Matrix3d covariance_matrix = Eigen::Matrix3d::Zero(); - computeCovarianceMatrixNormalized(*this->input_, *this->indices_, xyz_centroid, covariance_matrix); - - // Check if the covariance matrix is finite or not. - for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) - if (!std::isfinite(covariance_matrix.coeffRef(i, j))) - return; - - EIGEN_ALIGN16 Eigen::Vector3d eigen_values; - EIGEN_ALIGN16 Eigen::Matrix3d eigen_vectors; - pcl::eigen33(covariance_matrix, eigen_vectors, eigen_values); - - Eigen::Affine3d transform1; - transform1.setIdentity(); - - // If no input dimension is specified, determine automatically - if (dim_ == 0) { - PCL_DEBUG("[pcl::%s] WARNING: Input dimension not specified. Automatically determining input dimension.\n", - getClassName().c_str()); - if (std::abs(eigen_values[0]) < std::numeric_limits::epsilon() || - std::abs(eigen_values[0] / eigen_values[2]) < 1.0e-3) - dim_ = 2; - else - dim_ = 3; - } - - if (dim_ == 2) { - // we have points laying on a plane, using 2d convex hull - // compute transformation bring eigen_vectors.col(i) to z-axis - - transform1(2, 0) = eigen_vectors(0, 0); - transform1(2, 1) = eigen_vectors(1, 0); - transform1(2, 2) = eigen_vectors(2, 0); - - transform1(1, 0) = eigen_vectors(0, 1); - transform1(1, 1) = eigen_vectors(1, 1); - transform1(1, 2) = eigen_vectors(2, 1); - transform1(0, 0) = eigen_vectors(0, 2); - transform1(0, 1) = eigen_vectors(1, 2); - transform1(0, 2) = eigen_vectors(2, 2); - } else { - transform1.setIdentity(); - } - - PointCloud cloud_transformed; - pcl::demeanPointCloud(*this->input_, *this->indices_, xyz_centroid, cloud_transformed); - pcl::transformPointCloud(cloud_transformed, cloud_transformed, transform1); - - // True if qhull should free points in qh_freeqhull() or reallocation - boolT ismalloc = True; - // option flags for qhull, see qh_opt.htm - //char flags[] = "qhull d QJ"; - char flags[] = "qhull d Qt"; - // output from qh_produce_output(), use NULL to skip qh_produce_output() - FILE* outfile = nullptr; - // error messages from qhull code - FILE* errfile = stderr; - // 0 if no error from qhull - int exitcode; - - // Array of coordinates for each point - coordT* points = reinterpret_cast(calloc(cloud_transformed.points.size() * dim_, sizeof(coordT))); - - for (size_t i = 0; i < cloud_transformed.points.size(); ++i) { - points[i * dim_ + 0] = static_cast(cloud_transformed.points[i].x); - points[i * dim_ + 1] = static_cast(cloud_transformed.points[i].y); - - if (dim_ > 2) - points[i * dim_ + 2] = static_cast(cloud_transformed.points[i].z); - } - - // Compute concave hull - exitcode = qh_new_qhull( - dim_, static_cast(cloud_transformed.points.size()), points, ismalloc, flags, outfile, errfile); - - if (exitcode != 0) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::performReconstrution] ERROR: qhull was unable to compute a " - "concave hull for the given point cloud(%lu)!\n", - getClassName().c_str(), cloud_transformed.points.size()); - - // check if it fails because of NaN values... - if (!cloud_transformed.is_dense) { - bool NaNvalues = false; - for (size_t i = 0; i < cloud_transformed.points.size(); ++i) { - if (!std::isfinite(cloud_transformed.points[i].x) || !std::isfinite(cloud_transformed.points[i].y) || - !std::isfinite(cloud_transformed.points[i].z)) { - NaNvalues = true; - break; - } - } - - if (NaNvalues) - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::performReconstruction] ERROR: point cloud contains NaN values, consider running " - "pcl::PassThrough filter first to remove NaNs!\n", - getClassName().c_str()); - } - - alpha_shape.points.resize(0); - alpha_shape.width = alpha_shape.height = 0; - polygons.resize(0); - - qh_freeqhull(!qh_ALL); - int curlong, totlong; - qh_memfreeshort(&curlong, &totlong); - - return; - } - - qh_setvoronoi_all(); - - int num_vertices = qh num_vertices; - alpha_shape.points.resize(num_vertices); - - vertexT* vertex; - // Max vertex id - int max_vertex_id = 0; - FORALLvertices { - if (vertex->id + 1 > unsigned(max_vertex_id)) - max_vertex_id = vertex->id + 1; - } - - facetT* facet; // set by FORALLfacets - - ++max_vertex_id; - std::vector qhid_to_pcidx(max_vertex_id); - - int num_facets = qh num_facets; - int dd = 0; - - if (dim_ == 3) { - setT* triangles_set = qh_settemp(4 * num_facets); - if (voronoi_centers_) - voronoi_centers_->points.resize(num_facets); - - int non_upper = 0; - FORALLfacets { - // Facets are tetrahedrons(3d) - if (!facet->upperdelaunay) { - vertexT* anyVertex = static_cast(facet->vertices->e[0].p); - double* center = facet->center; - double r = qh_pointdist(anyVertex->point, center, dim_); - facetT* neighb; - - if (voronoi_centers_) { - voronoi_centers_->points[non_upper].x = static_cast(facet->center[0]); - voronoi_centers_->points[non_upper].y = static_cast(facet->center[1]); - voronoi_centers_->points[non_upper].z = static_cast(facet->center[2]); - } - - non_upper++; - - if (r <= alpha_) { - // all triangles in tetrahedron are good, add them all to the alpha shape(triangles_set) - qh_makeridges(facet); - facet->good = true; - facet->visitid = qh visit_id; - ridgeT *ridge, **ridgep; - FOREACHridge_(facet->ridges) { - neighb = otherfacet_(ridge, facet); - if ((neighb->visitid != qh visit_id)) - qh_setappend(&triangles_set, ridge); - } - } else { - // consider individual triangles from the tetrahedron... - facet->good = false; - facet->visitid = qh visit_id; - qh_makeridges(facet); - ridgeT *ridge, **ridgep; - FOREACHridge_(facet->ridges) { - facetT* neighb; - neighb = otherfacet_(ridge, facet); - if ((neighb->visitid != qh visit_id)) { - // check if individual triangle is good and add it to triangles_set - - PointInT a, b, c; - a.x = static_cast((static_cast(ridge->vertices->e[0].p))->point[0]); - a.y = static_cast((static_cast(ridge->vertices->e[0].p))->point[1]); - a.z = static_cast((static_cast(ridge->vertices->e[0].p))->point[2]); - b.x = static_cast((static_cast(ridge->vertices->e[1].p))->point[0]); - b.y = static_cast((static_cast(ridge->vertices->e[1].p))->point[1]); - b.z = static_cast((static_cast(ridge->vertices->e[1].p))->point[2]); - c.x = static_cast((static_cast(ridge->vertices->e[2].p))->point[0]); - c.y = static_cast((static_cast(ridge->vertices->e[2].p))->point[1]); - c.z = static_cast((static_cast(ridge->vertices->e[2].p))->point[2]); - - double r = pcl::getCircumcircleRadius(a, b, c); - if (r <= alpha_) - qh_setappend(&triangles_set, ridge); - //if (facet->tricoplanar) qh_setappend(&triangles_set, ridge); - } - } - } - } - } - - if (voronoi_centers_) - voronoi_centers_->points.resize(non_upper); - - // filter, add points to alpha_shape and create polygon structure - - int num_good_triangles = 0; - ridgeT *ridge, **ridgep; - FOREACHridge_(triangles_set) { - if (ridge->bottom->upperdelaunay || ridge->top->upperdelaunay || !ridge->top->good || !ridge->bottom->good) - num_good_triangles++; - } - - polygons.resize(num_good_triangles); - - int vertices = 0; - std::vector added_vertices(max_vertex_id, false); - - int triangles = 0; - FOREACHridge_(triangles_set) { - if (ridge->bottom->upperdelaunay || ridge->top->upperdelaunay || !ridge->top->good || - !ridge->bottom->good) { - // polygons[triangles].vertices.resize(3); - int vertex_n, vertex_i; - FOREACHvertex_i_((*ridge).vertices) // 3 vertices per ridge! - { - if (!added_vertices[vertex->id]) { - alpha_shape.points[vertices].x = static_cast(vertex->point[0]); - alpha_shape.points[vertices].y = static_cast(vertex->point[1]); - alpha_shape.points[vertices].z = static_cast(vertex->point[2]); - - qhid_to_pcidx[vertex->id] = vertices; // map the vertex id of qhull to the point cloud index - added_vertices[vertex->id] = true; - vertices++; - } - - polygons[triangles].vertices[vertex_i] = qhid_to_pcidx[vertex->id]; - } - - triangles++; - } - } - - alpha_shape.points.resize(vertices); - alpha_shape.width = static_cast(alpha_shape.points.size()); - alpha_shape.height = 1; - } else { - // Compute the alpha complex for the set of points - // Filters the delaunay triangles - setT* edges_set = qh_settemp(3 * num_facets); - if (voronoi_centers_) - voronoi_centers_->points.resize(num_facets); - - FORALLfacets { - // Facets are the delaunay triangles(2d) - if (!facet->upperdelaunay) { - // Check if the distance from any vertex to the facet->center - //(center of the voronoi cell) is smaller than alpha - vertexT* anyVertex = static_cast(facet->vertices->e[0].p); - double r = (sqrt((anyVertex->point[0] - facet->center[0]) * (anyVertex->point[0] - facet->center[0]) + - (anyVertex->point[1] - facet->center[1]) * (anyVertex->point[1] - facet->center[1]))); - if (r <= alpha_) { - pcl::Vertices facet_vertices; // TODO: is not used!! - qh_makeridges(facet); - facet->good = true; - - ridgeT *ridge, **ridgep; - FOREACHridge_(facet->ridges) qh_setappend(&edges_set, ridge); - - if (voronoi_centers_) { - voronoi_centers_->points[dd].x = static_cast(facet->center[0]); - voronoi_centers_->points[dd].y = static_cast(facet->center[1]); - voronoi_centers_->points[dd].z = 0.0f; - } - - ++dd; - } else - facet->good = false; - } - } - - int vertices = 0; - std::vector added_vertices(max_vertex_id, false); - std::map> edges; - - ridgeT *ridge, **ridgep; - FOREACHridge_(edges_set) { - if (ridge->bottom->upperdelaunay || ridge->top->upperdelaunay || !ridge->top->good || - !ridge->bottom->good) { - int vertex_n, vertex_i; - int vertices_in_ridge = 0; - std::vector pcd_indices; - pcd_indices.resize(2); - - FOREACHvertex_i_((*ridge).vertices) // in 2-dim, 2 vertices per ridge! - { - if (!added_vertices[vertex->id]) { - alpha_shape.points[vertices].x = static_cast(vertex->point[0]); - alpha_shape.points[vertices].y = static_cast(vertex->point[1]); - - if (dim_ > 2) - alpha_shape.points[vertices].z = static_cast(vertex->point[2]); - else - alpha_shape.points[vertices].z = 0; - - qhid_to_pcidx[vertex->id] = vertices; // map the vertex id of qhull to the point cloud index - added_vertices[vertex->id] = true; - pcd_indices[vertices_in_ridge] = vertices; - vertices++; - } else { - pcd_indices[vertices_in_ridge] = qhid_to_pcidx[vertex->id]; - } - - vertices_in_ridge++; - } - - // make edges bidirectional and pointing to alpha_shape pointcloud... - edges[pcd_indices[0]].push_back(pcd_indices[1]); - edges[pcd_indices[1]].push_back(pcd_indices[0]); - } - } - - alpha_shape.points.resize(vertices); - - std::vector> connected; - PointCloud alpha_shape_sorted; - alpha_shape_sorted.points.resize(vertices); - - // iterate over edges until they are empty! - std::map>::iterator curr = edges.begin(); - int next = -1; - std::vector used(vertices, false); // used to decide which direction should we take! - std::vector pcd_idx_start_polygons; - pcd_idx_start_polygons.push_back(0); - - // start following edges and removing elements - int sorted_idx = 0; - while (!edges.empty()) { - alpha_shape_sorted.points[sorted_idx] = alpha_shape.points[(*curr).first]; - // check where we can go from(*curr).first - for (const int& i : (*curr).second) { - if (!used[i]) { - // we can go there - next = i; - break; - } - } - - used[(*curr).first] = true; - edges.erase(curr); // remove edges starting from curr - - sorted_idx++; - - if (edges.empty()) - break; - - // reassign current - curr = edges.find(next); // if next is not found, then we have unconnected polygons. - if (curr == edges.end()) { - // set current to any of the remaining in edge! - curr = edges.begin(); - pcd_idx_start_polygons.push_back(sorted_idx); - } - } - - pcd_idx_start_polygons.push_back(sorted_idx); - - alpha_shape.points = alpha_shape_sorted.points; - - polygons.reserve(pcd_idx_start_polygons.size() - 1); - - for (size_t poly_id = 0; poly_id < pcd_idx_start_polygons.size() - 1; poly_id++) { - // Check if we actually have a polygon, and not some degenerated output from QHull - if (pcd_idx_start_polygons[poly_id + 1] - pcd_idx_start_polygons[poly_id] >= 3) { - pcl::Vertices vert; - // vertices.vertices.resize(pcd_idx_start_polygons[poly_id + 1] - pcd_idx_start_polygons[poly_id]); - assert(3 == pcd_idx_start_polygons[poly_id + 1] - pcd_idx_start_polygons[poly_id]); - // populate points in the corresponding polygon - for (int j = pcd_idx_start_polygons[poly_id]; j < pcd_idx_start_polygons[poly_id + 1]; ++j) - vert.vertices[j - pcd_idx_start_polygons[poly_id]] = static_cast(j); - - polygons.push_back(vert); - } - } - - if (voronoi_centers_) - voronoi_centers_->points.resize(dd); - } - - qh_freeqhull(!qh_ALL); - int curlong, totlong; - qh_memfreeshort(&curlong, &totlong); - - Eigen::Affine3d transInverse = transform1.inverse(); - pcl::transformPointCloud(alpha_shape, alpha_shape, transInverse); - xyz_centroid[0] = -xyz_centroid[0]; - xyz_centroid[1] = -xyz_centroid[1]; - xyz_centroid[2] = -xyz_centroid[2]; - pcl::demeanPointCloud(alpha_shape, xyz_centroid, alpha_shape); - - // also transform voronoi_centers_... - if (voronoi_centers_) { - pcl::transformPointCloud(*voronoi_centers_, *voronoi_centers_, transInverse); - pcl::demeanPointCloud(*voronoi_centers_, xyz_centroid, *voronoi_centers_); - } - - if (do_filtering_) { - // build a tree with the alpha shape points - pcl::KdTreeFLANN tree(true); - PointCloudConstPtr alpha_shape_ptr = std::make_shared(alpha_shape); - IndicesPtr index_ptr = std::make_shared(3 * polygons.size()); - auto poly_data_ptr = reinterpret_cast(polygons.data()); - std::copy(&poly_data_ptr[0], &poly_data_ptr[3 * polygons.size() - 1], index_ptr->begin()); - - - tree.setInputCloud(alpha_shape_ptr, index_ptr); - - int num_neighbors = 10; - - std::vector neighbor(num_neighbors); - std::vector distances(num_neighbors); - - std::vector new_polygons; - new_polygons.reserve(polygons.size()); - - for (auto& polygon : polygons) { - auto start = polygon.vertices[0]; - tree.nearestKSearch(alpha_shape.points[start], num_neighbors, neighbor, distances); - - if (std::find(std::begin(neighbor), std::end(neighbor), polygon.vertices[1]) != std::end(neighbor)) { - // point not found in neighbors - if (std::find(std::begin(neighbor), std::end(neighbor), polygon.vertices[2]) != std::end(neighbor)) { - new_polygons.emplace_back(polygon); - } - } - } - polygons = std::move(new_polygons); - } - - if (keep_information_) { - // build a tree with the original points - pcl::KdTreeFLANN tree(true); - tree.setInputCloud(this->input_, this->indices_); - - std::vector neighbor; - std::vector distances; - neighbor.resize(1); - distances.resize(1); - - // for each point in the concave hull, search for the nearest neighbor in the original point cloud - hull_indices_.header = this->input_->header; - hull_indices_.indices.clear(); - hull_indices_.indices.reserve(alpha_shape.points.size()); - - for (size_t i = 0; i < alpha_shape.points.size(); i++) { - tree.nearestKSearch(alpha_shape.points[i], 1, neighbor, distances); - hull_indices_.indices.push_back(neighbor[0]); - } - - // replace point with the closest neighbor in the original point cloud - pcl::copyPointCloud(*this->input_, hull_indices_.indices, alpha_shape); - } -} - -#ifdef __GNUC__ -#pragma GCC diagnostic warning "-Wold-style-cast" -#endif - -#define PCL_INSTANTIATE_ConcaveHull(T) template class PCL_EXPORTS pcl::ConcaveHull; - - -} // namespace pcl \ No newline at end of file diff --git a/plugins/probe/3rd/eigen.h b/plugins/probe/3rd/eigen.h deleted file mode 100644 index 1cff82d55c..0000000000 --- a/plugins/probe/3rd/eigen.h +++ /dev/null @@ -1,1540 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2012, Willow Garage, Inc. - * Copyright (C) 2010 Gael Guennebaud - * Copyright (C) 2009 Hauke Heibel - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#pragma once - -#include "mmcore/utility/log/Log.h" -#include -#include "common.h" - - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#if defined __GNUC__ -# pragma GCC system_header -#elif defined __SUNPRO_CC -# pragma disable_warn -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace pcl -{ - /** \brief Compute the roots of a quadratic polynom x^2 + b*x + c = 0 - * \param[in] b linear parameter - * \param[in] c constant parameter - * \param[out] roots solutions of x^2 + b*x + c = 0 - */ - template void - computeRoots2 (const Scalar &b, const Scalar &c, Roots &roots); - - /** \brief computes the roots of the characteristic polynomial of the input matrix m, which are the eigenvalues - * \param[in] m input matrix - * \param[out] roots roots of the characteristic polynomial of the input matrix m, which are the eigenvalues - */ - template void - computeRoots (const Matrix &m, Roots &roots); - - /** \brief determine the smallest eigenvalue and its corresponding eigenvector - * \param[in] mat input matrix that needs to be symmetric and positive semi definite - * \param[out] eigenvalue the smallest eigenvalue of the input matrix - * \param[out] eigenvector the corresponding eigenvector to the smallest eigenvalue of the input matrix - * \ingroup common - */ - template void - eigen22 (const Matrix &mat, typename Matrix::Scalar &eigenvalue, Vector &eigenvector); - - /** \brief determine the smallest eigenvalue and its corresponding eigenvector - * \param[in] mat input matrix that needs to be symmetric and positive semi definite - * \param[out] eigenvectors the corresponding eigenvector to the smallest eigenvalue of the input matrix - * \param[out] eigenvalues the smallest eigenvalue of the input matrix - * \ingroup common - */ - template void - eigen22 (const Matrix &mat, Matrix &eigenvectors, Vector &eigenvalues); - - /** \brief determines the corresponding eigenvector to the given eigenvalue of the symmetric positive semi definite input matrix - * \param[in] mat symmetric positive semi definite input matrix - * \param[in] eigenvalue the eigenvalue which corresponding eigenvector is to be computed - * \param[out] eigenvector the corresponding eigenvector for the input eigenvalue - * \ingroup common - */ - template void - computeCorrespondingEigenVector (const Matrix &mat, const typename Matrix::Scalar &eigenvalue, Vector &eigenvector); - - /** \brief determines the eigenvector and eigenvalue of the smallest eigenvalue of the symmetric positive semi definite input matrix - * \param[in] mat symmetric positive semi definite input matrix - * \param[out] eigenvalue smallest eigenvalue of the input matrix - * \param[out] eigenvector the corresponding eigenvector for the input eigenvalue - * \note if the smallest eigenvalue is not unique, this function may return any eigenvector that is consistent to the eigenvalue. - * \ingroup common - */ - template void - eigen33 (const Matrix &mat, typename Matrix::Scalar &eigenvalue, Vector &eigenvector); - - /** \brief determines the eigenvalues of the symmetric positive semi definite input matrix - * \param[in] mat symmetric positive semi definite input matrix - * \param[out] evals resulting eigenvalues in ascending order - * \ingroup common - */ - template void - eigen33 (const Matrix &mat, Vector &evals); - - /** \brief determines the eigenvalues and corresponding eigenvectors of the symmetric positive semi definite input matrix - * \param[in] mat symmetric positive semi definite input matrix - * \param[out] evecs corresponding eigenvectors in correct order according to eigenvalues - * \param[out] evals resulting eigenvalues in ascending order - * \ingroup common - */ - template void - eigen33 (const Matrix &mat, Matrix &evecs, Vector &evals); - - /** \brief Calculate the inverse of a 2x2 matrix - * \param[in] matrix matrix to be inverted - * \param[out] inverse the resultant inverted matrix - * \note only the upper triangular part is taken into account => non symmetric matrices will give wrong results - * \return determinant of the original matrix => if 0 no inverse exists => result is invalid - * \ingroup common - */ - template typename Matrix::Scalar - invert2x2 (const Matrix &matrix, Matrix &inverse); - - /** \brief Calculate the inverse of a 3x3 symmetric matrix. - * \param[in] matrix matrix to be inverted - * \param[out] inverse the resultant inverted matrix - * \note only the upper triangular part is taken into account => non symmetric matrices will give wrong results - * \return determinant of the original matrix => if 0 no inverse exists => result is invalid - * \ingroup common - */ - template typename Matrix::Scalar - invert3x3SymMatrix (const Matrix &matrix, Matrix &inverse); - - /** \brief Calculate the inverse of a general 3x3 matrix. - * \param[in] matrix matrix to be inverted - * \param[out] inverse the resultant inverted matrix - * \return determinant of the original matrix => if 0 no inverse exists => result is invalid - * \ingroup common - */ - template typename Matrix::Scalar - invert3x3Matrix (const Matrix &matrix, Matrix &inverse); - - /** \brief Calculate the determinant of a 3x3 matrix. - * \param[in] matrix matrix - * \return determinant of the matrix - * \ingroup common - */ - template typename Matrix::Scalar - determinant3x3Matrix (const Matrix &matrix); - - /** \brief Get the unique 3D rotation that will rotate \a z_axis into (0,0,1) and \a y_direction into a vector - * with x=0 (or into (0,1,0) should \a y_direction be orthogonal to \a z_axis) - * \param[in] z_axis the z-axis - * \param[in] y_direction the y direction - * \param[out] transformation the resultant 3D rotation - * \ingroup common - */ - inline void - getTransFromUnitVectorsZY (const Eigen::Vector3f& z_axis, - const Eigen::Vector3f& y_direction, - Eigen::Affine3f& transformation); - - /** \brief Get the unique 3D rotation that will rotate \a z_axis into (0,0,1) and \a y_direction into a vector - * with x=0 (or into (0,1,0) should \a y_direction be orthogonal to \a z_axis) - * \param[in] z_axis the z-axis - * \param[in] y_direction the y direction - * \return the resultant 3D rotation - * \ingroup common - */ - inline Eigen::Affine3f - getTransFromUnitVectorsZY (const Eigen::Vector3f& z_axis, - const Eigen::Vector3f& y_direction); - - /** \brief Get the unique 3D rotation that will rotate \a x_axis into (1,0,0) and \a y_direction into a vector - * with z=0 (or into (0,1,0) should \a y_direction be orthogonal to \a z_axis) - * \param[in] x_axis the x-axis - * \param[in] y_direction the y direction - * \param[out] transformation the resultant 3D rotation - * \ingroup common - */ - inline void - getTransFromUnitVectorsXY (const Eigen::Vector3f& x_axis, - const Eigen::Vector3f& y_direction, - Eigen::Affine3f& transformation); - - /** \brief Get the unique 3D rotation that will rotate \a x_axis into (1,0,0) and \a y_direction into a vector - * with z=0 (or into (0,1,0) should \a y_direction be orthogonal to \a z_axis) - * \param[in] x_axis the x-axis - * \param[in] y_direction the y direction - * \return the resulting 3D rotation - * \ingroup common - */ - inline Eigen::Affine3f - getTransFromUnitVectorsXY (const Eigen::Vector3f& x_axis, - const Eigen::Vector3f& y_direction); - - /** \brief Get the unique 3D rotation that will rotate \a z_axis into (0,0,1) and \a y_direction into a vector - * with x=0 (or into (0,1,0) should \a y_direction be orthogonal to \a z_axis) - * \param[in] y_direction the y direction - * \param[in] z_axis the z-axis - * \param[out] transformation the resultant 3D rotation - * \ingroup common - */ - inline void - getTransformationFromTwoUnitVectors (const Eigen::Vector3f& y_direction, - const Eigen::Vector3f& z_axis, - Eigen::Affine3f& transformation); - - /** \brief Get the unique 3D rotation that will rotate \a z_axis into (0,0,1) and \a y_direction into a vector - * with x=0 (or into (0,1,0) should \a y_direction be orthogonal to \a z_axis) - * \param[in] y_direction the y direction - * \param[in] z_axis the z-axis - * \return transformation the resultant 3D rotation - * \ingroup common - */ - inline Eigen::Affine3f - getTransformationFromTwoUnitVectors (const Eigen::Vector3f& y_direction, - const Eigen::Vector3f& z_axis); - - /** \brief Get the transformation that will translate \a origin to (0,0,0) and rotate \a z_axis into (0,0,1) - * and \a y_direction into a vector with x=0 (or into (0,1,0) should \a y_direction be orthogonal to \a z_axis) - * \param[in] y_direction the y direction - * \param[in] z_axis the z-axis - * \param[in] origin the origin - * \param[in] transformation the resultant transformation matrix - * \ingroup common - */ - inline void - getTransformationFromTwoUnitVectorsAndOrigin (const Eigen::Vector3f& y_direction, - const Eigen::Vector3f& z_axis, - const Eigen::Vector3f& origin, - Eigen::Affine3f& transformation); - - /** \brief Extract the Euler angles (XYZ-convention) from the given transformation - * \param[in] t the input transformation matrix - * \param[in] roll the resulting roll angle - * \param[in] pitch the resulting pitch angle - * \param[in] yaw the resulting yaw angle - * \ingroup common - */ - template void - getEulerAngles (const Eigen::Transform &t, Scalar &roll, Scalar &pitch, Scalar &yaw); - - inline void - getEulerAngles (const Eigen::Affine3f &t, float &roll, float &pitch, float &yaw) - { - getEulerAngles (t, roll, pitch, yaw); - } - - inline void - getEulerAngles (const Eigen::Affine3d &t, double &roll, double &pitch, double &yaw) - { - getEulerAngles (t, roll, pitch, yaw); - } - - /** Extract x,y,z and the Euler angles (XYZ-convention) from the given transformation - * \param[in] t the input transformation matrix - * \param[out] x the resulting x translation - * \param[out] y the resulting y translation - * \param[out] z the resulting z translation - * \param[out] roll the resulting roll angle - * \param[out] pitch the resulting pitch angle - * \param[out] yaw the resulting yaw angle - * \ingroup common - */ - template void - getTranslationAndEulerAngles (const Eigen::Transform &t, - Scalar &x, Scalar &y, Scalar &z, - Scalar &roll, Scalar &pitch, Scalar &yaw); - - inline void - getTranslationAndEulerAngles (const Eigen::Affine3f &t, - float &x, float &y, float &z, - float &roll, float &pitch, float &yaw) - { - getTranslationAndEulerAngles (t, x, y, z, roll, pitch, yaw); - } - - inline void - getTranslationAndEulerAngles (const Eigen::Affine3d &t, - double &x, double &y, double &z, - double &roll, double &pitch, double &yaw) - { - getTranslationAndEulerAngles (t, x, y, z, roll, pitch, yaw); - } - - /** \brief Create a transformation from the given translation and Euler angles (XYZ-convention) - * \param[in] x the input x translation - * \param[in] y the input y translation - * \param[in] z the input z translation - * \param[in] roll the input roll angle - * \param[in] pitch the input pitch angle - * \param[in] yaw the input yaw angle - * \param[out] t the resulting transformation matrix - * \ingroup common - */ - template void - getTransformation (Scalar x, Scalar y, Scalar z, Scalar roll, Scalar pitch, Scalar yaw, - Eigen::Transform &t); - - inline void - getTransformation (float x, float y, float z, float roll, float pitch, float yaw, - Eigen::Affine3f &t) - { - return (getTransformation (x, y, z, roll, pitch, yaw, t)); - } - - inline void - getTransformation (double x, double y, double z, double roll, double pitch, double yaw, - Eigen::Affine3d &t) - { - return (getTransformation (x, y, z, roll, pitch, yaw, t)); - } - - /** \brief Create a transformation from the given translation and Euler angles (XYZ-convention) - * \param[in] x the input x translation - * \param[in] y the input y translation - * \param[in] z the input z translation - * \param[in] roll the input roll angle - * \param[in] pitch the input pitch angle - * \param[in] yaw the input yaw angle - * \return the resulting transformation matrix - * \ingroup common - */ - inline Eigen::Affine3f - getTransformation (float x, float y, float z, float roll, float pitch, float yaw) - { - Eigen::Affine3f t; - getTransformation (x, y, z, roll, pitch, yaw, t); - return (t); - } - - /** \brief Write a matrix to an output stream - * \param[in] matrix the matrix to output - * \param[out] file the output stream - * \ingroup common - */ - template void - saveBinary (const Eigen::MatrixBase& matrix, std::ostream& file); - - /** \brief Read a matrix from an input stream - * \param[out] matrix the resulting matrix, read from the input stream - * \param[in,out] file the input stream - * \ingroup common - */ - template void - loadBinary (Eigen::MatrixBase const& matrix, std::istream& file); - -// PCL_EIGEN_SIZE_MIN_PREFER_DYNAMIC gives the min between compile-time sizes. 0 has absolute priority, followed by 1, -// followed by Dynamic, followed by other finite values. The reason for giving Dynamic the priority over -// finite values is that min(3, Dynamic) should be Dynamic, since that could be anything between 0 and 3. -#define PCL_EIGEN_SIZE_MIN_PREFER_DYNAMIC(a,b) ((int (a) == 0 || int (b) == 0) ? 0 \ - : (int (a) == 1 || int (b) == 1) ? 1 \ - : (int (a) == Eigen::Dynamic || int (b) == Eigen::Dynamic) ? Eigen::Dynamic \ - : (int (a) <= int (b)) ? int (a) : int (b)) - - /** \brief Returns the transformation between two point sets. - * The algorithm is based on: - * "Least-squares estimation of transformation parameters between two point patterns", - * Shinji Umeyama, PAMI 1991, DOI: 10.1109/34.88573 - * - * It estimates parameters \f$ c, \mathbf{R}, \f$ and \f$ \mathbf{t} \f$ such that - * \f{align*} - * \frac{1}{n} \sum_{i=1}^n \vert\vert y_i - (c\mathbf{R}x_i + \mathbf{t}) \vert\vert_2^2 - * \f} - * is minimized. - * - * The algorithm is based on the analysis of the covariance matrix - * \f$ \Sigma_{\mathbf{x}\mathbf{y}} \in \mathbb{R}^{d \times d} \f$ - * of the input point sets \f$ \mathbf{x} \f$ and \f$ \mathbf{y} \f$ where - * \f$d\f$ is corresponding to the dimension (which is typically small). - * The analysis is involving the SVD having a complexity of \f$O(d^3)\f$ - * though the actual computational effort lies in the covariance - * matrix computation which has an asymptotic lower bound of \f$O(dm)\f$ when - * the input point sets have dimension \f$d \times m\f$. - * - * \param[in] src Source points \f$ \mathbf{x} = \left( x_1, \hdots, x_n \right) \f$ - * \param[in] dst Destination points \f$ \mathbf{y} = \left( y_1, \hdots, y_n \right) \f$. - * \param[in] with_scaling Sets \f$ c=1 \f$ when false is passed. (default: false) - * \return The homogeneous transformation - * \f{align*} - * T = \begin{bmatrix} c\mathbf{R} & \mathbf{t} \\ \mathbf{0} & 1 \end{bmatrix} - * \f} - * minimizing the resudiual above. This transformation is always returned as an - * Eigen::Matrix. - */ - template - typename Eigen::internal::umeyama_transform_matrix_type::type - umeyama (const Eigen::MatrixBase& src, const Eigen::MatrixBase& dst, bool with_scaling = false); - -/** \brief Transform a point using an affine matrix - * \param[in] point_in the vector to be transformed - * \param[out] point_out the transformed vector - * \param[in] transformation the transformation matrix - * - * \note Can be used with \c point_in = \c point_out - */ - template inline void - transformPoint (const Eigen::Matrix &point_in, - Eigen::Matrix &point_out, - const Eigen::Transform &transformation) - { - Eigen::Matrix point; - point << point_in, 1.0; - point_out = (transformation * point).template head<3> (); - } - - inline void - transformPoint (const Eigen::Vector3f &point_in, - Eigen::Vector3f &point_out, - const Eigen::Affine3f &transformation) - { - transformPoint (point_in, point_out, transformation); - } - - inline void - transformPoint (const Eigen::Vector3d &point_in, - Eigen::Vector3d &point_out, - const Eigen::Affine3d &transformation) - { - transformPoint (point_in, point_out, transformation); - } - -/** \brief Transform a vector using an affine matrix - * \param[in] vector_in the vector to be transformed - * \param[out] vector_out the transformed vector - * \param[in] transformation the transformation matrix - * - * \note Can be used with \c vector_in = \c vector_out - */ - template inline void - transformVector (const Eigen::Matrix &vector_in, - Eigen::Matrix &vector_out, - const Eigen::Transform &transformation) - { - vector_out = transformation.linear () * vector_in; - } - - inline void - transformVector (const Eigen::Vector3f &vector_in, - Eigen::Vector3f &vector_out, - const Eigen::Affine3f &transformation) - { - transformVector (vector_in, vector_out, transformation); - } - - inline void - transformVector (const Eigen::Vector3d &vector_in, - Eigen::Vector3d &vector_out, - const Eigen::Affine3d &transformation) - { - transformVector (vector_in, vector_out, transformation); - } - -/** \brief Transform a line using an affine matrix - * \param[in] line_in the line to be transformed - * \param[out] line_out the transformed line - * \param[in] transformation the transformation matrix - * - * Lines must be filled in this form:\n - * line[0-2] = Origin coordinates of the vector\n - * line[3-5] = Direction vector - * - * \note Can be used with \c line_in = \c line_out - */ - template bool - transformLine (const Eigen::Matrix &line_in, - Eigen::Matrix &line_out, - const Eigen::Transform &transformation); - - inline bool - transformLine (const Eigen::VectorXf &line_in, - Eigen::VectorXf &line_out, - const Eigen::Affine3f &transformation) - { - return (transformLine (line_in, line_out, transformation)); - } - - inline bool - transformLine (const Eigen::VectorXd &line_in, - Eigen::VectorXd &line_out, - const Eigen::Affine3d &transformation) - { - return (transformLine (line_in, line_out, transformation)); - } - -/** \brief Transform plane vectors using an affine matrix - * \param[in] plane_in the plane coefficients to be transformed - * \param[out] plane_out the transformed plane coefficients to fill - * \param[in] transformation the transformation matrix - * - * The plane vectors are filled in the form ax+by+cz+d=0 - * Can be used with non Hessian form planes coefficients - * Can be used with \c plane_in = \c plane_out - */ - template void - transformPlane (const Eigen::Matrix &plane_in, - Eigen::Matrix &plane_out, - const Eigen::Transform &transformation); - - inline void - transformPlane (const Eigen::Matrix &plane_in, - Eigen::Matrix &plane_out, - const Eigen::Transform &transformation) - { - transformPlane (plane_in, plane_out, transformation); - } - - inline void - transformPlane (const Eigen::Matrix &plane_in, - Eigen::Matrix &plane_out, - const Eigen::Transform &transformation) - { - transformPlane (plane_in, plane_out, transformation); - } - -/** \brief Check coordinate system integrity - * \param[in] line_x the first axis - * \param[in] line_y the second axis - * \param[in] norm_limit the limit to ignore norm rounding errors - * \param[in] dot_limit the limit to ignore dot product rounding errors - * \return True if the coordinate system is consistent, false otherwise. - * - * Lines must be filled in this form:\n - * line[0-2] = Origin coordinates of the vector\n - * line[3-5] = Direction vector - * - * Can be used like this :\n - * line_x = X axis and line_y = Y axis\n - * line_x = Z axis and line_y = X axis\n - * line_x = Y axis and line_y = Z axis\n - * Because X^Y = Z, Z^X = Y and Y^Z = X. - * Do NOT invert line order ! - * - * Determine whether a coordinate system is consistent or not by checking :\n - * Line origins: They must be the same for the 2 lines\n - * Norm: The 2 lines must be normalized\n - * Dot products: Must be 0 or perpendicular vectors - */ - template bool - checkCoordinateSystem (const Eigen::Matrix &line_x, - const Eigen::Matrix &line_y, - const Scalar norm_limit = 1e-3, - const Scalar dot_limit = 1e-3); - - inline bool - checkCoordinateSystem (const Eigen::Matrix &line_x, - const Eigen::Matrix &line_y, - const double norm_limit = 1e-3, - const double dot_limit = 1e-3) - { - return (checkCoordinateSystem (line_x, line_y, norm_limit, dot_limit)); - } - - inline bool - checkCoordinateSystem (const Eigen::Matrix &line_x, - const Eigen::Matrix &line_y, - const float norm_limit = 1e-3, - const float dot_limit = 1e-3) - { - return (checkCoordinateSystem (line_x, line_y, norm_limit, dot_limit)); - } - -/** \brief Check coordinate system integrity - * \param[in] origin the origin of the coordinate system - * \param[in] x_direction the first axis - * \param[in] y_direction the second axis - * \param[in] norm_limit the limit to ignore norm rounding errors - * \param[in] dot_limit the limit to ignore dot product rounding errors - * \return True if the coordinate system is consistent, false otherwise. - * - * Read the other variant for more information - */ - template inline bool - checkCoordinateSystem (const Eigen::Matrix &origin, - const Eigen::Matrix &x_direction, - const Eigen::Matrix &y_direction, - const Scalar norm_limit = 1e-3, - const Scalar dot_limit = 1e-3) - { - Eigen::Matrix line_x; - Eigen::Matrix line_y; - line_x << origin, x_direction; - line_y << origin, y_direction; - return (checkCoordinateSystem (line_x, line_y, norm_limit, dot_limit)); - } - - inline bool - checkCoordinateSystem (const Eigen::Matrix &origin, - const Eigen::Matrix &x_direction, - const Eigen::Matrix &y_direction, - const double norm_limit = 1e-3, - const double dot_limit = 1e-3) - { - Eigen::Matrix line_x; - Eigen::Matrix line_y; - line_x.resize (6); - line_y.resize (6); - line_x << origin, x_direction; - line_y << origin, y_direction; - return (checkCoordinateSystem (line_x, line_y, norm_limit, dot_limit)); - } - - inline bool - checkCoordinateSystem (const Eigen::Matrix &origin, - const Eigen::Matrix &x_direction, - const Eigen::Matrix &y_direction, - const float norm_limit = 1e-3, - const float dot_limit = 1e-3) - { - Eigen::Matrix line_x; - Eigen::Matrix line_y; - line_x.resize (6); - line_y.resize (6); - line_x << origin, x_direction; - line_y << origin, y_direction; - return (checkCoordinateSystem (line_x, line_y, norm_limit, dot_limit)); - } - -/** \brief Compute the transformation between two coordinate systems - * \param[in] from_line_x X axis from the origin coordinate system - * \param[in] from_line_y Y axis from the origin coordinate system - * \param[in] to_line_x X axis from the destination coordinate system - * \param[in] to_line_y Y axis from the destination coordinate system - * \param[out] transformation the transformation matrix to fill - * \return true if transformation was filled, false otherwise. - * - * Line must be filled in this form:\n - * line[0-2] = Coordinate system origin coordinates \n - * line[3-5] = Direction vector (norm doesn't matter) - */ - template bool - transformBetween2CoordinateSystems (const Eigen::Matrix from_line_x, - const Eigen::Matrix from_line_y, - const Eigen::Matrix to_line_x, - const Eigen::Matrix to_line_y, - Eigen::Transform &transformation); - - inline bool - transformBetween2CoordinateSystems (const Eigen::Matrix from_line_x, - const Eigen::Matrix from_line_y, - const Eigen::Matrix to_line_x, - const Eigen::Matrix to_line_y, - Eigen::Transform &transformation) - { - return (transformBetween2CoordinateSystems (from_line_x, from_line_y, to_line_x, to_line_y, transformation)); - } - - inline bool - transformBetween2CoordinateSystems (const Eigen::Matrix from_line_x, - const Eigen::Matrix from_line_y, - const Eigen::Matrix to_line_x, - const Eigen::Matrix to_line_y, - Eigen::Transform &transformation) - { - return (transformBetween2CoordinateSystems (from_line_x, from_line_y, to_line_x, to_line_y, transformation)); - } - -} - -// #include - -////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::computeRoots2(const Scalar& b, const Scalar& c, Roots& roots) { - roots(0) = Scalar(0); - Scalar d = Scalar(b * b - 4.0 * c); - if (d < 0.0) // no real roots ! THIS SHOULD NOT HAPPEN! - d = 0.0; - - Scalar sd = ::std::sqrt(d); - - roots(2) = 0.5f * (b + sd); - roots(1) = 0.5f * (b - sd); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template inline void pcl::computeRoots(const Matrix& m, Roots& roots) { - using Scalar = typename Matrix::Scalar; - - // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The - // eigenvalues are the roots to this equation, all guaranteed to be - // real-valued, because the matrix is symmetric. - Scalar c0 = m(0, 0) * m(1, 1) * m(2, 2) + Scalar(2) * m(0, 1) * m(0, 2) * m(1, 2) - m(0, 0) * m(1, 2) * m(1, 2) - - m(1, 1) * m(0, 2) * m(0, 2) - m(2, 2) * m(0, 1) * m(0, 1); - Scalar c1 = m(0, 0) * m(1, 1) - m(0, 1) * m(0, 1) + m(0, 0) * m(2, 2) - m(0, 2) * m(0, 2) + m(1, 1) * m(2, 2) - - m(1, 2) * m(1, 2); - Scalar c2 = m(0, 0) + m(1, 1) + m(2, 2); - - if (std::abs(c0) < Eigen::NumTraits::epsilon()) // one root is 0 -> quadratic equation - computeRoots2(c2, c1, roots); - else { - const Scalar s_inv3 = Scalar(1.0 / 3.0); - const Scalar s_sqrt3 = std::sqrt(Scalar(3.0)); - // Construct the parameters used in classifying the roots of the equation - // and in solving the equation for the roots in closed form. - Scalar c2_over_3 = c2 * s_inv3; - Scalar a_over_3 = (c1 - c2 * c2_over_3) * s_inv3; - if (a_over_3 > Scalar(0)) a_over_3 = Scalar(0); - - Scalar half_b = Scalar(0.5) * (c0 + c2_over_3 * (Scalar(2) * c2_over_3 * c2_over_3 - c1)); - - Scalar q = half_b * half_b + a_over_3 * a_over_3 * a_over_3; - if (q > Scalar(0)) q = Scalar(0); - - // Compute the eigenvalues by solving for the roots of the polynomial. - Scalar rho = std::sqrt(-a_over_3); - Scalar theta = std::atan2(std::sqrt(-q), half_b) * s_inv3; - Scalar cos_theta = std::cos(theta); - Scalar sin_theta = std::sin(theta); - roots(0) = c2_over_3 + Scalar(2) * rho * cos_theta; - roots(1) = c2_over_3 - rho * (cos_theta + s_sqrt3 * sin_theta); - roots(2) = c2_over_3 - rho * (cos_theta - s_sqrt3 * sin_theta); - - // Sort in increasing order. - if (roots(0) >= roots(1)) std::swap(roots(0), roots(1)); - if (roots(1) >= roots(2)) { - std::swap(roots(1), roots(2)); - if (roots(0) >= roots(1)) std::swap(roots(0), roots(1)); - } - - if (roots(0) <= 0) // eigenval for symmetric positive semi-definite matrix can not be negative! Set it to 0 - computeRoots2(c2, c1, roots); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::eigen22(const Matrix& mat, typename Matrix::Scalar& eigenvalue, Vector& eigenvector) { - // if diagonal matrix, the eigenvalues are the diagonal elements - // and the eigenvectors are not unique, thus set to Identity - if (std::abs(mat.coeff(1)) <= std::numeric_limits::min()) { - if (mat.coeff(0) < mat.coeff(2)) { - eigenvalue = mat.coeff(0); - eigenvector[0] = 1.0; - eigenvector[1] = 0.0; - } else { - eigenvalue = mat.coeff(2); - eigenvector[0] = 0.0; - eigenvector[1] = 1.0; - } - return; - } - - // 0.5 to optimize further calculations - typename Matrix::Scalar trace = static_cast(0.5) * (mat.coeff(0) + mat.coeff(3)); - typename Matrix::Scalar determinant = mat.coeff(0) * mat.coeff(3) - mat.coeff(1) * mat.coeff(1); - - typename Matrix::Scalar temp = trace * trace - determinant; - - if (temp < 0) temp = 0; - - eigenvalue = trace - ::std::sqrt(temp); - - eigenvector[0] = -mat.coeff(1); - eigenvector[1] = mat.coeff(0) - eigenvalue; - eigenvector.normalize(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::eigen22(const Matrix& mat, Matrix& eigenvectors, Vector& eigenvalues) { - // if diagonal matrix, the eigenvalues are the diagonal elements - // and the eigenvectors are not unique, thus set to Identity - if (std::abs(mat.coeff(1)) <= std::numeric_limits::min()) { - if (mat.coeff(0) < mat.coeff(3)) { - eigenvalues.coeffRef(0) = mat.coeff(0); - eigenvalues.coeffRef(1) = mat.coeff(3); - eigenvectors.coeffRef(0) = 1.0; - eigenvectors.coeffRef(1) = 0.0; - eigenvectors.coeffRef(2) = 0.0; - eigenvectors.coeffRef(3) = 1.0; - } else { - eigenvalues.coeffRef(0) = mat.coeff(3); - eigenvalues.coeffRef(1) = mat.coeff(0); - eigenvectors.coeffRef(0) = 0.0; - eigenvectors.coeffRef(1) = 1.0; - eigenvectors.coeffRef(2) = 1.0; - eigenvectors.coeffRef(3) = 0.0; - } - return; - } - - // 0.5 to optimize further calculations - typename Matrix::Scalar trace = static_cast(0.5) * (mat.coeff(0) + mat.coeff(3)); - typename Matrix::Scalar determinant = mat.coeff(0) * mat.coeff(3) - mat.coeff(1) * mat.coeff(1); - - typename Matrix::Scalar temp = trace * trace - determinant; - - if (temp < 0) - temp = 0; - else - temp = ::std::sqrt(temp); - - eigenvalues.coeffRef(0) = trace - temp; - eigenvalues.coeffRef(1) = trace + temp; - - // either this is in a row or column depending on RowMajor or ColumnMajor - eigenvectors.coeffRef(0) = -mat.coeff(1); - eigenvectors.coeffRef(2) = mat.coeff(0) - eigenvalues.coeff(0); - typename Matrix::Scalar norm = - static_cast(1.0) / - static_cast(::std::sqrt( - eigenvectors.coeffRef(0) * eigenvectors.coeffRef(0) + eigenvectors.coeffRef(2) * eigenvectors.coeffRef(2))); - eigenvectors.coeffRef(0) *= norm; - eigenvectors.coeffRef(2) *= norm; - eigenvectors.coeffRef(1) = eigenvectors.coeffRef(2); - eigenvectors.coeffRef(3) = -eigenvectors.coeffRef(0); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::computeCorrespondingEigenVector( - const Matrix& mat, const typename Matrix::Scalar& eigenvalue, Vector& eigenvector) { - using Scalar = typename Matrix::Scalar; - // Scale the matrix so its entries are in [-1,1]. The scaling is applied - // only when at least one matrix entry has magnitude larger than 1. - - Scalar scale = mat.cwiseAbs().maxCoeff(); - if (scale <= std::numeric_limits::min()) scale = Scalar(1.0); - - Matrix scaledMat = mat / scale; - - scaledMat.diagonal().array() -= eigenvalue / scale; - - Vector vec1 = scaledMat.row(0).cross(scaledMat.row(1)); - Vector vec2 = scaledMat.row(0).cross(scaledMat.row(2)); - Vector vec3 = scaledMat.row(1).cross(scaledMat.row(2)); - - Scalar len1 = vec1.squaredNorm(); - Scalar len2 = vec2.squaredNorm(); - Scalar len3 = vec3.squaredNorm(); - - if (len1 >= len2 && len1 >= len3) - eigenvector = vec1 / std::sqrt(len1); - else if (len2 >= len1 && len2 >= len3) - eigenvector = vec2 / std::sqrt(len2); - else - eigenvector = vec3 / std::sqrt(len3); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::eigen33(const Matrix& mat, typename Matrix::Scalar& eigenvalue, Vector& eigenvector) { - using Scalar = typename Matrix::Scalar; - // Scale the matrix so its entries are in [-1,1]. The scaling is applied - // only when at least one matrix entry has magnitude larger than 1. - - Scalar scale = mat.cwiseAbs().maxCoeff(); - if (scale <= std::numeric_limits::min()) scale = Scalar(1.0); - - Matrix scaledMat = mat / scale; - - Vector eigenvalues; - computeRoots(scaledMat, eigenvalues); - - eigenvalue = eigenvalues(0) * scale; - - scaledMat.diagonal().array() -= eigenvalues(0); - - Vector vec1 = scaledMat.row(0).cross(scaledMat.row(1)); - Vector vec2 = scaledMat.row(0).cross(scaledMat.row(2)); - Vector vec3 = scaledMat.row(1).cross(scaledMat.row(2)); - - Scalar len1 = vec1.squaredNorm(); - Scalar len2 = vec2.squaredNorm(); - Scalar len3 = vec3.squaredNorm(); - - if (len1 >= len2 && len1 >= len3) - eigenvector = vec1 / std::sqrt(len1); - else if (len2 >= len1 && len2 >= len3) - eigenvector = vec2 / std::sqrt(len2); - else - eigenvector = vec3 / std::sqrt(len3); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template inline void pcl::eigen33(const Matrix& mat, Vector& evals) { - using Scalar = typename Matrix::Scalar; - Scalar scale = mat.cwiseAbs().maxCoeff(); - if (scale <= std::numeric_limits::min()) scale = Scalar(1.0); - - Matrix scaledMat = mat / scale; - computeRoots(scaledMat, evals); - evals *= scale; -} - -////////////////////////////////////////////////////////////////////////////////////////// -template inline void pcl::eigen33(const Matrix& mat, Matrix& evecs, Vector& evals) { - using Scalar = typename Matrix::Scalar; - // Scale the matrix so its entries are in [-1,1]. The scaling is applied - // only when at least one matrix entry has magnitude larger than 1. - - Scalar scale = mat.cwiseAbs().maxCoeff(); - if (scale <= std::numeric_limits::min()) scale = Scalar(1.0); - - Matrix scaledMat = mat / scale; - - // Compute the eigenvalues - computeRoots(scaledMat, evals); - - if ((evals(2) - evals(0)) <= Eigen::NumTraits::epsilon()) { - // all three equal - evecs.setIdentity(); - } else if ((evals(1) - evals(0)) <= Eigen::NumTraits::epsilon()) { - // first and second equal - Matrix tmp; - tmp = scaledMat; - tmp.diagonal().array() -= evals(2); - - Vector vec1 = tmp.row(0).cross(tmp.row(1)); - Vector vec2 = tmp.row(0).cross(tmp.row(2)); - Vector vec3 = tmp.row(1).cross(tmp.row(2)); - - Scalar len1 = vec1.squaredNorm(); - Scalar len2 = vec2.squaredNorm(); - Scalar len3 = vec3.squaredNorm(); - - if (len1 >= len2 && len1 >= len3) - evecs.col(2) = vec1 / std::sqrt(len1); - else if (len2 >= len1 && len2 >= len3) - evecs.col(2) = vec2 / std::sqrt(len2); - else - evecs.col(2) = vec3 / std::sqrt(len3); - - evecs.col(1) = evecs.col(2).unitOrthogonal(); - evecs.col(0) = evecs.col(1).cross(evecs.col(2)); - } else if ((evals(2) - evals(1)) <= Eigen::NumTraits::epsilon()) { - // second and third equal - Matrix tmp; - tmp = scaledMat; - tmp.diagonal().array() -= evals(0); - - Vector vec1 = tmp.row(0).cross(tmp.row(1)); - Vector vec2 = tmp.row(0).cross(tmp.row(2)); - Vector vec3 = tmp.row(1).cross(tmp.row(2)); - - Scalar len1 = vec1.squaredNorm(); - Scalar len2 = vec2.squaredNorm(); - Scalar len3 = vec3.squaredNorm(); - - if (len1 >= len2 && len1 >= len3) - evecs.col(0) = vec1 / std::sqrt(len1); - else if (len2 >= len1 && len2 >= len3) - evecs.col(0) = vec2 / std::sqrt(len2); - else - evecs.col(0) = vec3 / std::sqrt(len3); - - evecs.col(1) = evecs.col(0).unitOrthogonal(); - evecs.col(2) = evecs.col(0).cross(evecs.col(1)); - } else { - Matrix tmp; - tmp = scaledMat; - tmp.diagonal().array() -= evals(2); - - Vector vec1 = tmp.row(0).cross(tmp.row(1)); - Vector vec2 = tmp.row(0).cross(tmp.row(2)); - Vector vec3 = tmp.row(1).cross(tmp.row(2)); - - Scalar len1 = vec1.squaredNorm(); - Scalar len2 = vec2.squaredNorm(); - Scalar len3 = vec3.squaredNorm(); -# ifdef _WIN32 - Scalar* mmax = new Scalar[3]; -# else - Scalar mmax[3]; -# endif - unsigned int min_el = 2; - unsigned int max_el = 2; - if (len1 >= len2 && len1 >= len3) { - mmax[2] = len1; - evecs.col(2) = vec1 / std::sqrt(len1); - } else if (len2 >= len1 && len2 >= len3) { - mmax[2] = len2; - evecs.col(2) = vec2 / std::sqrt(len2); - } else { - mmax[2] = len3; - evecs.col(2) = vec3 / std::sqrt(len3); - } - - tmp = scaledMat; - tmp.diagonal().array() -= evals(1); - - vec1 = tmp.row(0).cross(tmp.row(1)); - vec2 = tmp.row(0).cross(tmp.row(2)); - vec3 = tmp.row(1).cross(tmp.row(2)); - - len1 = vec1.squaredNorm(); - len2 = vec2.squaredNorm(); - len3 = vec3.squaredNorm(); - if (len1 >= len2 && len1 >= len3) { - mmax[1] = len1; - evecs.col(1) = vec1 / std::sqrt(len1); - min_el = len1 <= mmax[min_el] ? 1 : min_el; - max_el = len1 > mmax[max_el] ? 1 : max_el; - } else if (len2 >= len1 && len2 >= len3) { - mmax[1] = len2; - evecs.col(1) = vec2 / std::sqrt(len2); - min_el = len2 <= mmax[min_el] ? 1 : min_el; - max_el = len2 > mmax[max_el] ? 1 : max_el; - } else { - mmax[1] = len3; - evecs.col(1) = vec3 / std::sqrt(len3); - min_el = len3 <= mmax[min_el] ? 1 : min_el; - max_el = len3 > mmax[max_el] ? 1 : max_el; - } - - tmp = scaledMat; - tmp.diagonal().array() -= evals(0); - - vec1 = tmp.row(0).cross(tmp.row(1)); - vec2 = tmp.row(0).cross(tmp.row(2)); - vec3 = tmp.row(1).cross(tmp.row(2)); - - len1 = vec1.squaredNorm(); - len2 = vec2.squaredNorm(); - len3 = vec3.squaredNorm(); - if (len1 >= len2 && len1 >= len3) { - mmax[0] = len1; - evecs.col(0) = vec1 / std::sqrt(len1); - min_el = len3 <= mmax[min_el] ? 0 : min_el; - max_el = len3 > mmax[max_el] ? 0 : max_el; - } else if (len2 >= len1 && len2 >= len3) { - mmax[0] = len2; - evecs.col(0) = vec2 / std::sqrt(len2); - min_el = len3 <= mmax[min_el] ? 0 : min_el; - max_el = len3 > mmax[max_el] ? 0 : max_el; - } else { - mmax[0] = len3; - evecs.col(0) = vec3 / std::sqrt(len3); - min_el = len3 <= mmax[min_el] ? 0 : min_el; - max_el = len3 > mmax[max_el] ? 0 : max_el; - } - - unsigned mid_el = 3 - min_el - max_el; - evecs.col(min_el) = evecs.col((min_el + 1) % 3).cross(evecs.col((min_el + 2) % 3)).normalized(); - evecs.col(mid_el) = evecs.col((mid_el + 1) % 3).cross(evecs.col((mid_el + 2) % 3)).normalized(); -# ifdef _WIN32 - delete[] mmax; -# endif - } - // Rescale back to the original size. - evals *= scale; -} - -////////////////////////////////////////////////////////////////////////////////////////// -template inline typename Matrix::Scalar pcl::invert2x2(const Matrix& matrix, Matrix& inverse) { - using Scalar = typename Matrix::Scalar; - Scalar det = matrix.coeff(0) * matrix.coeff(3) - matrix.coeff(1) * matrix.coeff(2); - - if (det != 0) { - // Scalar inv_det = Scalar (1.0) / det; - inverse.coeffRef(0) = matrix.coeff(3); - inverse.coeffRef(1) = -matrix.coeff(1); - inverse.coeffRef(2) = -matrix.coeff(2); - inverse.coeffRef(3) = matrix.coeff(0); - inverse /= det; - } - return det; -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -inline typename Matrix::Scalar pcl::invert3x3SymMatrix(const Matrix& matrix, Matrix& inverse) { - using Scalar = typename Matrix::Scalar; - // elements - // a b c - // b d e - // c e f - //| a b c |-1 | fd-ee ce-bf be-cd | - //| b d e | = 1/det * | ce-bf af-cc bc-ae | - //| c e f | | be-cd bc-ae ad-bb | - - // det = a(fd-ee) + b(ec-fb) + c(eb-dc) - - Scalar fd_ee = matrix.coeff(4) * matrix.coeff(8) - matrix.coeff(7) * matrix.coeff(5); - Scalar ce_bf = matrix.coeff(2) * matrix.coeff(5) - matrix.coeff(1) * matrix.coeff(8); - Scalar be_cd = matrix.coeff(1) * matrix.coeff(5) - matrix.coeff(2) * matrix.coeff(4); - - Scalar det = matrix.coeff(0) * fd_ee + matrix.coeff(1) * ce_bf + matrix.coeff(2) * be_cd; - - if (det != 0) { - // Scalar inv_det = Scalar (1.0) / det; - inverse.coeffRef(0) = fd_ee; - inverse.coeffRef(1) = inverse.coeffRef(3) = ce_bf; - inverse.coeffRef(2) = inverse.coeffRef(6) = be_cd; - inverse.coeffRef(4) = (matrix.coeff(0) * matrix.coeff(8) - matrix.coeff(2) * matrix.coeff(2)); - inverse.coeffRef(5) = inverse.coeffRef(7) = - (matrix.coeff(1) * matrix.coeff(2) - matrix.coeff(0) * matrix.coeff(5)); - inverse.coeffRef(8) = (matrix.coeff(0) * matrix.coeff(4) - matrix.coeff(1) * matrix.coeff(1)); - inverse /= det; - } - return det; -} - -////////////////////////////////////////////////////////////////////////////////////////// -template inline typename Matrix::Scalar pcl::invert3x3Matrix(const Matrix& matrix, Matrix& inverse) { - using Scalar = typename Matrix::Scalar; - - //| a b c |-1 | ie-hf hc-ib fb-ec | - //| d e f | = 1/det * | gf-id ia-gc dc-fa | - //| g h i | | hd-ge gb-ha ea-db | - // det = a(ie-hf) + d(hc-ib) + g(fb-ec) - - Scalar ie_hf = matrix.coeff(8) * matrix.coeff(4) - matrix.coeff(7) * matrix.coeff(5); - Scalar hc_ib = matrix.coeff(7) * matrix.coeff(2) - matrix.coeff(8) * matrix.coeff(1); - Scalar fb_ec = matrix.coeff(5) * matrix.coeff(1) - matrix.coeff(4) * matrix.coeff(2); - Scalar det = matrix.coeff(0) * (ie_hf) + matrix.coeff(3) * (hc_ib) + matrix.coeff(6) * (fb_ec); - - if (det != 0) { - inverse.coeffRef(0) = ie_hf; - inverse.coeffRef(1) = hc_ib; - inverse.coeffRef(2) = fb_ec; - inverse.coeffRef(3) = matrix.coeff(6) * matrix.coeff(5) - matrix.coeff(8) * matrix.coeff(3); - inverse.coeffRef(4) = matrix.coeff(8) * matrix.coeff(0) - matrix.coeff(6) * matrix.coeff(2); - inverse.coeffRef(5) = matrix.coeff(3) * matrix.coeff(2) - matrix.coeff(5) * matrix.coeff(0); - inverse.coeffRef(6) = matrix.coeff(7) * matrix.coeff(3) - matrix.coeff(6) * matrix.coeff(4); - inverse.coeffRef(7) = matrix.coeff(6) * matrix.coeff(1) - matrix.coeff(7) * matrix.coeff(0); - inverse.coeffRef(8) = matrix.coeff(4) * matrix.coeff(0) - matrix.coeff(3) * matrix.coeff(1); - - inverse /= det; - } - return det; -} - -////////////////////////////////////////////////////////////////////////////////////////// -template inline typename Matrix::Scalar pcl::determinant3x3Matrix(const Matrix& matrix) { - // result is independent of Row/Col Major storage! - return matrix.coeff(0) * (matrix.coeff(4) * matrix.coeff(8) - matrix.coeff(5) * matrix.coeff(7)) + - matrix.coeff(1) * (matrix.coeff(5) * matrix.coeff(6) - matrix.coeff(3) * matrix.coeff(8)) + - matrix.coeff(2) * (matrix.coeff(3) * matrix.coeff(7) - matrix.coeff(4) * matrix.coeff(6)); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void pcl::getTransFromUnitVectorsZY( - const Eigen::Vector3f& z_axis, const Eigen::Vector3f& y_direction, Eigen::Affine3f& transformation) { - Eigen::Vector3f tmp0 = (y_direction.cross(z_axis)).normalized(); - Eigen::Vector3f tmp1 = (z_axis.cross(tmp0)).normalized(); - Eigen::Vector3f tmp2 = z_axis.normalized(); - - transformation(0, 0) = tmp0[0]; - transformation(0, 1) = tmp0[1]; - transformation(0, 2) = tmp0[2]; - transformation(0, 3) = 0.0f; - transformation(1, 0) = tmp1[0]; - transformation(1, 1) = tmp1[1]; - transformation(1, 2) = tmp1[2]; - transformation(1, 3) = 0.0f; - transformation(2, 0) = tmp2[0]; - transformation(2, 1) = tmp2[1]; - transformation(2, 2) = tmp2[2]; - transformation(2, 3) = 0.0f; - transformation(3, 0) = 0.0f; - transformation(3, 1) = 0.0f; - transformation(3, 2) = 0.0f; - transformation(3, 3) = 1.0f; -} - -////////////////////////////////////////////////////////////////////////////////////////// -Eigen::Affine3f pcl::getTransFromUnitVectorsZY(const Eigen::Vector3f& z_axis, const Eigen::Vector3f& y_direction) { - Eigen::Affine3f transformation; - getTransFromUnitVectorsZY(z_axis, y_direction, transformation); - return (transformation); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void pcl::getTransFromUnitVectorsXY( - const Eigen::Vector3f& x_axis, const Eigen::Vector3f& y_direction, Eigen::Affine3f& transformation) { - Eigen::Vector3f tmp2 = (x_axis.cross(y_direction)).normalized(); - Eigen::Vector3f tmp1 = (tmp2.cross(x_axis)).normalized(); - Eigen::Vector3f tmp0 = x_axis.normalized(); - - transformation(0, 0) = tmp0[0]; - transformation(0, 1) = tmp0[1]; - transformation(0, 2) = tmp0[2]; - transformation(0, 3) = 0.0f; - transformation(1, 0) = tmp1[0]; - transformation(1, 1) = tmp1[1]; - transformation(1, 2) = tmp1[2]; - transformation(1, 3) = 0.0f; - transformation(2, 0) = tmp2[0]; - transformation(2, 1) = tmp2[1]; - transformation(2, 2) = tmp2[2]; - transformation(2, 3) = 0.0f; - transformation(3, 0) = 0.0f; - transformation(3, 1) = 0.0f; - transformation(3, 2) = 0.0f; - transformation(3, 3) = 1.0f; -} - -////////////////////////////////////////////////////////////////////////////////////////// -Eigen::Affine3f pcl::getTransFromUnitVectorsXY(const Eigen::Vector3f& x_axis, const Eigen::Vector3f& y_direction) { - Eigen::Affine3f transformation; - getTransFromUnitVectorsXY(x_axis, y_direction, transformation); - return (transformation); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void pcl::getTransformationFromTwoUnitVectors( - const Eigen::Vector3f& y_direction, const Eigen::Vector3f& z_axis, Eigen::Affine3f& transformation) { - getTransFromUnitVectorsZY(z_axis, y_direction, transformation); -} - -////////////////////////////////////////////////////////////////////////////////////////// -Eigen::Affine3f pcl::getTransformationFromTwoUnitVectors( - const Eigen::Vector3f& y_direction, const Eigen::Vector3f& z_axis) { - Eigen::Affine3f transformation; - getTransformationFromTwoUnitVectors(y_direction, z_axis, transformation); - return (transformation); -} - -void pcl::getTransformationFromTwoUnitVectorsAndOrigin(const Eigen::Vector3f& y_direction, - const Eigen::Vector3f& z_axis, const Eigen::Vector3f& origin, Eigen::Affine3f& transformation) { - getTransformationFromTwoUnitVectors(y_direction, z_axis, transformation); - Eigen::Vector3f translation = transformation * origin; - transformation(0, 3) = -translation[0]; - transformation(1, 3) = -translation[1]; - transformation(2, 3) = -translation[2]; -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::getEulerAngles( - const Eigen::Transform& t, Scalar& roll, Scalar& pitch, Scalar& yaw) { - roll = std::atan2(t(2, 1), t(2, 2)); - pitch = asin(-t(2, 0)); - yaw = std::atan2(t(1, 0), t(0, 0)); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::getTranslationAndEulerAngles(const Eigen::Transform& t, Scalar& x, Scalar& y, - Scalar& z, Scalar& roll, Scalar& pitch, Scalar& yaw) { - x = t(0, 3); - y = t(1, 3); - z = t(2, 3); - roll = std::atan2(t(2, 1), t(2, 2)); - pitch = asin(-t(2, 0)); - yaw = std::atan2(t(1, 0), t(0, 0)); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::getTransformation(Scalar x, Scalar y, Scalar z, Scalar roll, Scalar pitch, Scalar yaw, - Eigen::Transform& t) { - Scalar A = std::cos(yaw), B = sin(yaw), C = std::cos(pitch), D = sin(pitch), E = std::cos(roll), F = sin(roll), - DE = D * E, DF = D * F; - - t(0, 0) = A * C; - t(0, 1) = A * DF - B * E; - t(0, 2) = B * F + A * DE; - t(0, 3) = x; - t(1, 0) = B * C; - t(1, 1) = A * E + B * DF; - t(1, 2) = B * DE - A * F; - t(1, 3) = y; - t(2, 0) = -D; - t(2, 1) = C * F; - t(2, 2) = C * E; - t(2, 3) = z; - t(3, 0) = 0; - t(3, 1) = 0; - t(3, 2) = 0; - t(3, 3) = 1; -} - -////////////////////////////////////////////////////////////////////////////////////////// -template void pcl::saveBinary(const Eigen::MatrixBase& matrix, std::ostream& file) { - uint32_t rows = static_cast(matrix.rows()), cols = static_cast(matrix.cols()); - file.write(reinterpret_cast(&rows), sizeof(rows)); - file.write(reinterpret_cast(&cols), sizeof(cols)); - for (uint32_t i = 0; i < rows; ++i) - for (uint32_t j = 0; j < cols; ++j) { - typename Derived::Scalar tmp = matrix(i, j); - file.write(reinterpret_cast(&tmp), sizeof(tmp)); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -template void pcl::loadBinary(Eigen::MatrixBase const& matrix_, std::istream& file) { - Eigen::MatrixBase& matrix = const_cast&>(matrix_); - - uint32_t rows, cols; - file.read(reinterpret_cast(&rows), sizeof(rows)); - file.read(reinterpret_cast(&cols), sizeof(cols)); - if (matrix.rows() != static_cast(rows) || matrix.cols() != static_cast(cols)) - matrix.derived().resize(rows, cols); - - for (uint32_t i = 0; i < rows; ++i) - for (uint32_t j = 0; j < cols; ++j) { - typename Derived::Scalar tmp; - file.read(reinterpret_cast(&tmp), sizeof(tmp)); - matrix(i, j) = tmp; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -typename Eigen::internal::umeyama_transform_matrix_type::type pcl::umeyama( - const Eigen::MatrixBase& src, const Eigen::MatrixBase& dst, bool with_scaling) { -# if EIGEN_VERSION_AT_LEAST(3, 3, 0) - return Eigen::umeyama(src, dst, with_scaling); -# else - using TransformationMatrixType = - typename Eigen::internal::umeyama_transform_matrix_type::type; - using Scalar = typename Eigen::internal::traits::Scalar; - using RealScalar = typename Eigen::NumTraits::Real; - using Index = typename Derived::Index; - - static_assert(!Eigen::NumTraits::IsComplex, "Numeric type must be real."); - static_assert((Eigen::internal::is_same::Scalar>::value), - "You mixed different numeric types. You need to use the cast method of matrixbase to cast numeric types " - "explicitly."); - - enum { Dimension = PCL_EIGEN_SIZE_MIN_PREFER_DYNAMIC(Derived::RowsAtCompileTime, OtherDerived::RowsAtCompileTime) }; - - using VectorType = Eigen::Matrix; - using MatrixType = Eigen::Matrix; - using RowMajorMatrixType = typename Eigen::internal::plain_matrix_type_row_major::type; - - const Index m = src.rows(); // dimension - const Index n = src.cols(); // number of measurements - - // required for demeaning ... - const RealScalar one_over_n = 1 / static_cast(n); - - // computation of mean - const VectorType src_mean = src.rowwise().sum() * one_over_n; - const VectorType dst_mean = dst.rowwise().sum() * one_over_n; - - // demeaning of src and dst points - const RowMajorMatrixType src_demean = src.colwise() - src_mean; - const RowMajorMatrixType dst_demean = dst.colwise() - dst_mean; - - // Eq. (36)-(37) - const Scalar src_var = src_demean.rowwise().squaredNorm().sum() * one_over_n; - - // Eq. (38) - const MatrixType sigma(one_over_n * dst_demean * src_demean.transpose()); - - Eigen::JacobiSVD svd(sigma, Eigen::ComputeFullU | Eigen::ComputeFullV); - - // Initialize the resulting transformation with an identity matrix... - TransformationMatrixType Rt = TransformationMatrixType::Identity(m + 1, m + 1); - - // Eq. (39) - VectorType S = VectorType::Ones(m); - - if (svd.matrixU().determinant() * svd.matrixV().determinant() < 0) S(m - 1) = -1; - - // Eq. (40) and (43) - Rt.block(0, 0, m, m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose(); - - if (with_scaling) { - // Eq. (42) - const Scalar c = Scalar(1) / src_var * svd.singularValues().dot(S); - - // Eq. (41) - Rt.col(m).head(m) = dst_mean; - Rt.col(m).head(m).noalias() -= c * Rt.topLeftCorner(m, m) * src_mean; - Rt.block(0, 0, m, m) *= c; - } else { - Rt.col(m).head(m) = dst_mean; - Rt.col(m).head(m).noalias() -= Rt.topLeftCorner(m, m) * src_mean; - } - - return (Rt); -# endif -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::transformLine(const Eigen::Matrix& line_in, - Eigen::Matrix& line_out, - const Eigen::Transform& transformation) { - if (line_in.innerSize() != 6 || line_out.innerSize() != 6) { - PCL_DEBUG("transformLine: lines size != 6\n"); - return (false); - } - - Eigen::Matrix point, vector; - point << line_in.template head<3>(); - vector << line_out.template tail<3>(); - - pcl::transformPoint(point, point, transformation); - pcl::transformVector(vector, vector, transformation); - line_out << point, vector; - return (true); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::transformPlane(const Eigen::Matrix& plane_in, Eigen::Matrix& plane_out, - const Eigen::Transform& transformation) { - Eigen::Hyperplane plane; - plane.coeffs() << plane_in; - plane.transform(transformation); - plane_out << plane.coeffs(); - -// Versions prior to 3.3.2 don't normalize the result -# if !EIGEN_VERSION_AT_LEAST(3, 3, 2) - plane_out /= plane_out.template head<3>().norm(); -# endif -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::checkCoordinateSystem(const Eigen::Matrix& line_x, - const Eigen::Matrix& line_y, const Scalar norm_limit, const Scalar dot_limit) { - if (line_x.innerSize() != 6 || line_y.innerSize() != 6) { - PCL_DEBUG("checkCoordinateSystem: lines size != 6\n"); - return (false); - } - - if (line_x.template head<3>() != line_y.template head<3>()) { - PCL_DEBUG("checkCoorZdinateSystem: vector origins are different !\n"); - return (false); - } - - // Make a copy of vector directions - // X^Y = Z | Y^Z = X | Z^X = Y - Eigen::Matrix v_line_x(line_x.template tail<3>()), v_line_y(line_y.template tail<3>()), - v_line_z(v_line_x.cross(v_line_y)); - - // Check vectors norms - if (v_line_x.norm() < 1 - norm_limit || v_line_x.norm() > 1 + norm_limit) { - PCL_DEBUG("checkCoordinateSystem: line_x norm %d != 1\n", v_line_x.norm()); - return (false); - } - - if (v_line_y.norm() < 1 - norm_limit || v_line_y.norm() > 1 + norm_limit) { - PCL_DEBUG("checkCoordinateSystem: line_y norm %d != 1\n", v_line_y.norm()); - return (false); - } - - if (v_line_z.norm() < 1 - norm_limit || v_line_z.norm() > 1 + norm_limit) { - PCL_DEBUG("checkCoordinateSystem: line_z norm %d != 1\n", v_line_z.norm()); - return (false); - } - - // Check vectors perendicularity - if (std::abs(v_line_x.dot(v_line_y)) > dot_limit) { - PCL_DEBUG("checkCSAxis: line_x dot line_y %e = > %e\n", v_line_x.dot(v_line_y), dot_limit); - return (false); - } - - if (std::abs(v_line_x.dot(v_line_z)) > dot_limit) { - PCL_DEBUG("checkCSAxis: line_x dot line_z = %e > %e\n", v_line_x.dot(v_line_z), dot_limit); - return (false); - } - - if (std::abs(v_line_y.dot(v_line_z)) > dot_limit) { - PCL_DEBUG("checkCSAxis: line_y dot line_z = %e > %e\n", v_line_y.dot(v_line_z), dot_limit); - return (false); - } - - return (true); -} - -////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::transformBetween2CoordinateSystems(const Eigen::Matrix from_line_x, - const Eigen::Matrix from_line_y, - const Eigen::Matrix to_line_x, const Eigen::Matrix to_line_y, - Eigen::Transform& transformation) { - if (from_line_x.innerSize() != 6 || from_line_y.innerSize() != 6 || to_line_x.innerSize() != 6 || - to_line_y.innerSize() != 6) { - PCL_DEBUG("transformBetween2CoordinateSystems: lines size != 6\n"); - return (false); - } - - // Check if coordinate systems are valid - if (!pcl::checkCoordinateSystem(from_line_x, from_line_y) || !pcl::checkCoordinateSystem(to_line_x, to_line_y)) { - PCL_DEBUG("transformBetween2CoordinateSystems: coordinate systems invalid !\n"); - return (false); - } - - // Convert lines into Vector3 : - Eigen::Matrix fr0(from_line_x.template head<3>()), - fr1(from_line_x.template head<3>() + from_line_x.template tail<3>()), - fr2(from_line_y.template head<3>() + from_line_y.template tail<3>()), - - to0(to_line_x.template head<3>()), to1(to_line_x.template head<3>() + to_line_x.template tail<3>()), - to2(to_line_y.template head<3>() + to_line_y.template tail<3>()); - - // Code is inspired from http://stackoverflow.com/a/15277421/1816078 - // Define matrices and points : - Eigen::Transform T2, T3 = Eigen::Transform::Identity(); - Eigen::Matrix x1, y1, z1, x2, y2, z2; - - // Axes of the coordinate system "fr" - x1 = (fr1 - fr0).normalized(); // the versor (unitary vector) of the (fr1-fr0) axis vector - y1 = (fr2 - fr0).normalized(); - - // Axes of the coordinate system "to" - x2 = (to1 - to0).normalized(); - y2 = (to2 - to0).normalized(); - - // Transform from CS1 to CS2 - // Note: if fr0 == (0,0,0) --> CS1 == CS2 --> T2 = Identity - T2.linear() << x1, y1, x1.cross(y1); - - // Transform from CS1 to CS3 - T3.linear() << x2, y2, x2.cross(y2); - - // Identity matrix = transform to CS2 to CS3 - // Note: if CS1 == CS2 --> transformation = T3 - transformation = Eigen::Transform::Identity(); - transformation.linear() = T3.linear() * T2.linear().inverse(); - transformation.translation() = to0 - (transformation.linear() * fr0); - return (true); -} - diff --git a/plugins/probe/3rd/feature.h b/plugins/probe/3rd/feature.h deleted file mode 100644 index 00fb7b8487..0000000000 --- a/plugins/probe/3rd/feature.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2011, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#pragma once - -#if defined __GNUC__ -# pragma GCC system_header -#endif - -// PCL includes -#include "common.h" -#include "kdtree.h" -#include - -namespace pcl -{ - /** \brief Solve the eigenvalues and eigenvectors of a given 3x3 covariance matrix, and estimate the least-squares - * plane normal and surface curvature. - * \param covariance_matrix the 3x3 covariance matrix - * \param point a point lying on the least-squares plane (SSE aligned) - * \param plane_parameters the resultant plane parameters as: a, b, c, d (ax + by + cz + d = 0) - * \param curvature the estimated surface curvature as a measure of - * \f[ - * \lambda_0 / (\lambda_0 + \lambda_1 + \lambda_2) - * \f] - * \ingroup features - */ - inline void - solvePlaneParameters (const Eigen::Matrix3f &covariance_matrix, - const Eigen::Vector4f &point, - Eigen::Vector4f &plane_parameters, float &curvature); - - /** \brief Solve the eigenvalues and eigenvectors of a given 3x3 covariance matrix, and estimate the least-squares - * plane normal and surface curvature. - * \param covariance_matrix the 3x3 covariance matrix - * \param nx the resultant X component of the plane normal - * \param ny the resultant Y component of the plane normal - * \param nz the resultant Z component of the plane normal - * \param curvature the estimated surface curvature as a measure of - * \f[ - * \lambda_0 / (\lambda_0 + \lambda_1 + \lambda_2) - * \f] - * \ingroup features - */ - inline void - solvePlaneParameters (const Eigen::Matrix3f &covariance_matrix, - float &nx, float &ny, float &nz, float &curvature); - - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - /** \brief Feature represents the base feature class. Some generic 3D operations that - * are applicable to all features are defined here as static methods. - * - * \attention - * The convention for a feature descriptor is: - * - if the nearest neighbors for the query point at which the descriptor is to be computed cannot be - * determined, the descriptor values will be set to NaN (not a number) - * - it is impossible to estimate a feature descriptor for a point that doesn't have finite 3D coordinates. - * Therefore, any point that has NaN data on x, y, or z, will most likely have its descriptor set to NaN. - * - * \author Radu B. Rusu - * \ingroup features - */ - template - class Feature : public PCLBase - { - public: - using PCLBase::indices_; - using PCLBase::input_; - - using BaseClass = PCLBase; - - using Ptr = std::shared_ptr< Feature >; - using ConstPtr = std::shared_ptr< const Feature >; - - using KdTree = KdTreeFLANN; - using KdTreePtr = typename KdTree::Ptr; - - using PointCloudIn = pcl::PointCloud; - using PointCloudInPtr = typename PointCloudIn::Ptr; - using PointCloudInConstPtr = typename PointCloudIn::ConstPtr; - - using PointCloudOut = pcl::PointCloud; - - using SearchMethod = std::function &, std::vector &)>; - using SearchMethodSurface = std::function &, std::vector &)>; - - public: - /** \brief Empty constructor. */ - Feature () : - feature_name_ (), search_method_surface_ (), - surface_(), tree_(), - search_parameter_(0), search_radius_(0), k_(0), - fake_surface_(false) - {} - - /** \brief Empty destructor */ - virtual ~Feature () {} - - /** \brief Provide a pointer to a dataset to add additional information - * to estimate the features for every point in the input dataset. This - * is optional, if this is not set, it will only use the data in the - * input cloud to estimate the features. This is useful when you only - * need to compute the features for a downsampled cloud. - * \param[in] cloud a pointer to a PointCloud message - */ - inline void - setSearchSurface (const PointCloudInConstPtr &cloud) - { - surface_ = cloud; - fake_surface_ = false; - //use_surface_ = true; - } - - /** \brief Get a pointer to the surface point cloud dataset. */ - inline PointCloudInConstPtr - getSearchSurface () const - { - return (surface_); - } - - /** \brief Provide a pointer to the search object. - * \param[in] tree a pointer to the spatial search object. - */ - inline void - setSearchMethod (const KdTreePtr &tree) { tree_ = tree; } - - /** \brief Get a pointer to the search method used. */ - inline KdTreePtr - getSearchMethod () const - { - return (tree_); - } - - /** \brief Get the internal search parameter. */ - inline double - getSearchParameter () const - { - return (search_parameter_); - } - - /** \brief Set the number of k nearest neighbors to use for the feature estimation. - * \param[in] k the number of k-nearest neighbors - */ - inline void - setKSearch (int k) { k_ = k; } - - /** \brief get the number of k nearest neighbors used for the feature estimation. */ - inline int - getKSearch () const - { - return (k_); - } - - /** \brief Set the sphere radius that is to be used for determining the nearest neighbors used for the feature - * estimation. - * \param[in] radius the sphere radius used as the maximum distance to consider a point a neighbor - */ - inline void - setRadiusSearch (double radius) - { - search_radius_ = radius; - } - - /** \brief Get the sphere radius used for determining the neighbors. */ - inline double - getRadiusSearch () const - { - return (search_radius_); - } - - /** \brief Base method for feature estimation for all points given in - * using the surface in setSearchSurface () - * and the spatial locator in setSearchMethod () - * \param[out] output the resultant point cloud model dataset containing the estimated features - */ - void - compute (PointCloudOut &output); - - protected: - /** \brief The feature name. */ - std::string feature_name_; - - /** \brief The search method template for points. */ - SearchMethodSurface search_method_surface_; - - /** \brief An input point cloud describing the surface that is to be used - * for nearest neighbors estimation. - */ - PointCloudInConstPtr surface_; - - /** \brief A pointer to the spatial search object. */ - KdTreePtr tree_; - - /** \brief The actual search parameter (from either \a search_radius_ or \a k_). */ - double search_parameter_; - - /** \brief The nearest neighbors search radius for each point. */ - double search_radius_; - - /** \brief The number of K nearest neighbors to use for each point. */ - int k_; - - /** \brief Get a string representation of the name of this class. */ - inline const std::string& - getClassName () const { return (feature_name_); } - - /** \brief This method should get called before starting the actual computation. */ - virtual bool - initCompute (); - - /** \brief This method should get called after ending the actual computation. */ - virtual bool - deinitCompute (); - - /** \brief If no surface is given, we use the input PointCloud as the surface. */ - bool fake_surface_; - - /** \brief Search for k-nearest neighbors using the spatial locator from - * \a setSearchmethod, and the given surface from \a setSearchSurface. - * \param[in] index the index of the query point - * \param[in] parameter the search parameter (either k or radius) - * \param[out] indices the resultant vector of indices representing the k-nearest neighbors - * \param[out] distances the resultant vector of distances representing the distances from the query point to the - * k-nearest neighbors - * - * \return the number of neighbors found. If no neighbors are found or an error occurred, return 0. - */ - inline int - searchForNeighbors (size_t index, double parameter, - std::vector &indices, std::vector &distances) const - { - return (search_method_surface_ (*input_, index, parameter, indices, distances)); - } - - /** \brief Search for k-nearest neighbors using the spatial locator from - * \a setSearchmethod, and the given surface from \a setSearchSurface. - * \param[in] cloud the query point cloud - * \param[in] index the index of the query point in \a cloud - * \param[in] parameter the search parameter (either k or radius) - * \param[out] indices the resultant vector of indices representing the k-nearest neighbors - * \param[out] distances the resultant vector of distances representing the distances from the query point to the - * k-nearest neighbors - * - * \return the number of neighbors found. If no neighbors are found or an error occurred, return 0. - */ - inline int - searchForNeighbors (const PointCloudIn &cloud, size_t index, double parameter, - std::vector &indices, std::vector &distances) const - { - return (search_method_surface_ (cloud, index, parameter, indices, distances)); - } - - private: - /** \brief Abstract feature estimation method. - * \param[out] output the resultant features - */ - virtual void - computeFeature (PointCloudOut &output) = 0; - - public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - }; - - - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - template - class FeatureFromNormals : public Feature - { - using PointCloudIn = typename Feature::PointCloudIn; - using PointCloudInPtr = typename PointCloudIn::Ptr; - using PointCloudInConstPtr = typename PointCloudIn::ConstPtr; - using PointCloudOut = typename Feature::PointCloudOut; - - public: - using PointCloudN = pcl::PointCloud; - using PointCloudNPtr = typename PointCloudN::Ptr; - using PointCloudNConstPtr = typename PointCloudN::ConstPtr; - - using Ptr = std::shared_ptr< FeatureFromNormals >; - using ConstPtr = std::shared_ptr< const FeatureFromNormals >; - - // Members derived from the base class - using Feature::input_; - using Feature::surface_; - using Feature::getClassName; - - /** \brief Empty constructor. */ - FeatureFromNormals () : normals_ () {} - - /** \brief Empty destructor */ - virtual ~FeatureFromNormals () {} - - /** \brief Provide a pointer to the input dataset that contains the point normals of - * the XYZ dataset. - * In case of search surface is set to be different from the input cloud, - * normals should correspond to the search surface, not the input cloud! - * \param[in] normals the const boost shared pointer to a PointCloud of normals. - * By convention, L2 norm of each normal should be 1. - */ - inline void - setInputNormals (const PointCloudNConstPtr &normals) { normals_ = normals; } - - /** \brief Get a pointer to the normals of the input XYZ point cloud dataset. */ - inline PointCloudNConstPtr - getInputNormals () const { return (normals_); } - - protected: - /** \brief A pointer to the input dataset that contains the point normals of the XYZ - * dataset. - */ - PointCloudNConstPtr normals_; - - /** \brief This method should get called before starting the actual computation. */ - virtual bool - initCompute (); - - public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - }; - - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - template - class FeatureFromLabels : public Feature - { - using PointCloudIn = typename Feature::PointCloudIn; - using PointCloudInPtr = typename PointCloudIn::Ptr; - using PointCloudInConstPtr = typename PointCloudIn::ConstPtr; - - using PointCloudL = pcl::PointCloud; - using PointCloudNPtr = typename PointCloudL::Ptr; - using PointCloudLConstPtr = typename PointCloudL::ConstPtr; - - using PointCloudOut = typename Feature::PointCloudOut; - - public: - using Ptr = std::shared_ptr< FeatureFromLabels >; - using ConstPtr = std::shared_ptr< const FeatureFromLabels >; - - // Members derived from the base class - using Feature::input_; - using Feature::surface_; - using Feature::getClassName; - using Feature::k_; - - /** \brief Empty constructor. */ - FeatureFromLabels () : labels_ () - { - k_ = 1; // Search tree is not always used here. - } - - /** \brief Empty destructor */ - virtual ~FeatureFromLabels () {} - - /** \brief Provide a pointer to the input dataset that contains the point labels of - * the XYZ dataset. - * In case of search surface is set to be different from the input cloud, - * labels should correspond to the search surface, not the input cloud! - * \param[in] labels the const boost shared pointer to a PointCloud of labels. - */ - inline void - setInputLabels (const PointCloudLConstPtr &labels) - { - labels_ = labels; - } - - /** \brief Get a pointer to the labels of the input XYZ point cloud dataset. */ - inline PointCloudLConstPtr - getInputLabels () const - { - return (labels_); - } - - protected: - /** \brief A pointer to the input dataset that contains the point labels of the XYZ - * dataset. - */ - PointCloudLConstPtr labels_; - - /** \brief This method should get called before starting the actual computation. */ - virtual bool - initCompute (); - - public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - }; - - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - /** \brief FeatureWithLocalReferenceFrames provides a public interface for descriptor - * extractor classes which need a local reference frame at each input keypoint. - * - * \attention - * This interface is for backward compatibility with existing code and in the future it could be - * merged with pcl::Feature. Subclasses should call the protected method initLocalReferenceFrames () - * to correctly initialize the frames_ member. - * - * \author Nicola Fioraio - * \ingroup features - */ - template - class FeatureWithLocalReferenceFrames - { - public: - using PointCloudLRF = pcl::PointCloud; - using PointCloudLRFPtr = typename PointCloudLRF::Ptr; - using PointCloudLRFConstPtr = typename PointCloudLRF::ConstPtr; - - /** \brief Empty constructor. */ - FeatureWithLocalReferenceFrames () : frames_ (), frames_never_defined_ (true) {} - - /** \brief Empty destructor. */ - virtual ~FeatureWithLocalReferenceFrames () {} - - /** \brief Provide a pointer to the input dataset that contains the local - * reference frames of the XYZ dataset. - * In case of search surface is set to be different from the input cloud, - * local reference frames should correspond to the input cloud, not the search surface! - * \param[in] frames the const boost shared pointer to a PointCloud of reference frames. - */ - inline void - setInputReferenceFrames (const PointCloudLRFConstPtr &frames) - { - frames_ = frames; - frames_never_defined_ = false; - } - - /** \brief Get a pointer to the local reference frames. */ - inline PointCloudLRFConstPtr - getInputReferenceFrames () const - { - return (frames_); - } - - protected: - /** \brief A boost shared pointer to the local reference frames. */ - PointCloudLRFConstPtr frames_; - /** \brief The user has never set the frames. */ - bool frames_never_defined_; - - /** \brief Check if frames_ has been correctly initialized and compute it if needed. - * \param input the subclass' input cloud dataset. - * \param lrf_estimation a pointer to a local reference frame estimation class to be used as default. - * \return true if frames_ has been correctly initialized. - */ - using LRFEstimationPtr = typename Feature::Ptr; - virtual bool - initLocalReferenceFrames (const size_t& indices_size, - const LRFEstimationPtr& lrf_estimation = LRFEstimationPtr()); - }; -} - -#include "feature.hpp" diff --git a/plugins/probe/3rd/feature.hpp b/plugins/probe/3rd/feature.hpp deleted file mode 100644 index fcd870e86d..0000000000 --- a/plugins/probe/3rd/feature.hpp +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2011, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#ifndef PCL_FEATURES_IMPL_FEATURE_H_ -#define PCL_FEATURES_IMPL_FEATURE_H_ - -////////////////////////////////////////////////////////////////////////////////////////////// -inline void pcl::solvePlaneParameters(const Eigen::Matrix3f& covariance_matrix, const Eigen::Vector4f& point, - Eigen::Vector4f& plane_parameters, float& curvature) { - solvePlaneParameters(covariance_matrix, plane_parameters[0], plane_parameters[1], plane_parameters[2], curvature); - - plane_parameters[3] = 0; - // Hessian form (D = nc . p_plane (centroid here) + p) - plane_parameters[3] = -1 * plane_parameters.dot(point); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -inline void pcl::solvePlaneParameters( - const Eigen::Matrix3f& covariance_matrix, float& nx, float& ny, float& nz, float& curvature) { - // Avoid getting hung on Eigen's optimizers - // for (int i = 0; i < 9; ++i) - // if (!std::isfinite (covariance_matrix.coeff (i))) - // { - // //PCL_WARN ("[pcl::solvePlaneParameteres] Covariance matrix has NaN/Inf values!\n"); - // nx = ny = nz = curvature = std::numeric_limits::quiet_NaN (); - // return; - // } - // Extract the smallest eigenvalue and its eigenvector - EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value; - EIGEN_ALIGN16 Eigen::Vector3f eigen_vector; - pcl::eigen33(covariance_matrix, eigen_value, eigen_vector); - - nx = eigen_vector[0]; - ny = eigen_vector[1]; - nz = eigen_vector[2]; - - // Compute the curvature surface change - float eig_sum = covariance_matrix.coeff(0) + covariance_matrix.coeff(4) + covariance_matrix.coeff(8); - if (eig_sum != 0) - curvature = std::abs(eigen_value / eig_sum); - else - curvature = 0; -} - -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::Feature::initCompute() { - if (!PCLBase::initCompute()) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::initCompute] Init failed.\n", getClassName().c_str()); - return (false); - } - - // If the dataset is empty, just return - if (input_->points.empty()) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::compute] input_ is empty!\n", getClassName().c_str()); - // Cleanup - deinitCompute(); - return (false); - } - - // If no search surface has been defined, use the input dataset as the search surface itself - if (!surface_) { - fake_surface_ = true; - surface_ = input_; - } - - // Check if a space search locator was given - if (!tree_) { - //if (surface_->isOrganized () && input_->isOrganized ()) - // tree_.reset (new pcl::search::OrganizedNeighbor ()); - //else - tree_ = std::make_unique>(false); - } - - if (tree_->getInputCloud() != surface_) // Make sure the tree searches the surface - tree_->setInputCloud(surface_); - - - // Do a fast check to see if the search parameters are well defined - if (search_radius_ != 0.0) { - if (k_ != 0) { - megamol::core::utility::log::Log::DefaultLog.WriteError("[pcl::%s::compute] ", getClassName().c_str()); - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Both radius (%f) and K (%d) defined! ", search_radius_, k_); - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Set one of them to zero first and then re-run compute ().\n"); - // Cleanup - deinitCompute(); - return (false); - } else // Use the radiusSearch () function - { - search_parameter_ = search_radius_; - // Declare the search locator definition - search_method_surface_ = [this](const PointCloudIn& cloud, int index, double radius, - std::vector& k_indices, std::vector& k_distances) { - return tree_->radiusSearch(cloud, index, radius, k_indices, k_distances, 0); - }; - } - } else { - if (k_ != 0) // Use the nearestKSearch () function - { - search_parameter_ = k_; - // Declare the search locator definition - search_method_surface_ = [this](const PointCloudIn& cloud, int index, int k, - std::vector& k_indices, std::vector& k_distances) { - return tree_->nearestKSearch(cloud, index, k, k_indices, k_distances); - }; - } else { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::compute] Neither radius nor K defined! ", getClassName().c_str()); - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Set one of them to a positive number first and then re-run compute ().\n"); - // Cleanup - deinitCompute(); - return (false); - } - } - return (true); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::Feature::deinitCompute() { - // Reset the surface - if (fake_surface_) { - surface_.reset(); - fake_surface_ = false; - } - return (true); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::Feature::compute(PointCloudOut& output) { - if (!initCompute()) { - output.width = output.height = 0; - output.points.clear(); - return; - } - - // Copy the header - output.header = input_->header; - - // Resize the output dataset - if (output.points.size() != indices_->size()) - output.points.resize(indices_->size()); - - // Check if the output will be computed for all points or only a subset - // If the input width or height are not set, set output width as size - if (indices_->size() != input_->points.size() || input_->width * input_->height == 0) { - output.width = static_cast(indices_->size()); - output.height = 1; - } else { - output.width = input_->width; - output.height = input_->height; - } - output.is_dense = input_->is_dense; - - // Perform the actual feature computation - computeFeature(output); - - deinitCompute(); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::FeatureFromNormals::initCompute() { - if (!Feature::initCompute()) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::initCompute] Init failed.\n", getClassName().c_str()); - return (false); - } - - // Check if input normals are set - if (!normals_) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::initCompute] No input dataset containing normals was given!\n", getClassName().c_str()); - Feature::deinitCompute(); - return (false); - } - - // Check if the size of normals is the same as the size of the surface - if (normals_->points.size() != surface_->points.size()) { - megamol::core::utility::log::Log::DefaultLog.WriteError("[pcl::%s::initCompute] ", getClassName().c_str()); - megamol::core::utility::log::Log::DefaultLog.WriteError( - "The number of points in the input dataset (%u) differs from ", surface_->points.size()); - megamol::core::utility::log::Log::DefaultLog.WriteError( - "the number of points in the dataset containing the normals (%u)!\n", normals_->points.size()); - Feature::deinitCompute(); - return (false); - } - - return (true); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::FeatureFromLabels::initCompute() { - if (!Feature::initCompute()) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::initCompute] Init failed.\n", getClassName().c_str()); - return (false); - } - - // Check if input normals are set - if (!labels_) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::initCompute] No input dataset containing labels was given!\n", getClassName().c_str()); - Feature::deinitCompute(); - return (false); - } - - // Check if the size of normals is the same as the size of the surface - if (labels_->points.size() != surface_->points.size()) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[pcl::%s::initCompute] The number of points in the input dataset differs from the number of points in the " - "dataset containing the labels!\n", - getClassName().c_str()); - Feature::deinitCompute(); - return (false); - } - - return (true); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////// -template -bool pcl::FeatureWithLocalReferenceFrames::initLocalReferenceFrames( - const size_t& indices_size, const LRFEstimationPtr& lrf_estimation) { - if (frames_never_defined_) - frames_.reset(); - - // Check if input frames are set - if (!frames_) { - if (!lrf_estimation) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[initLocalReferenceFrames] No input dataset containing reference frames was given!\n"); - return (false); - } else { - //PCL_WARN ("[initLocalReferenceFrames] No input dataset containing reference frames was given! Proceed using default\n"); - PointCloudLRFPtr default_frames = std::make_shared(); - lrf_estimation->compute(*default_frames); - frames_ = default_frames; - } - } - - // Check if the size of frames is the same as the size of the input cloud - if (frames_->points.size() != indices_size) { - if (!lrf_estimation) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "[initLocalReferenceFrames] The number of points in the input dataset differs from the number of " - "points in the dataset containing the reference frames!\n"); - return (false); - } else { - //PCL_WARN ("[initLocalReferenceFrames] The number of points in the input dataset differs from the number of points in the dataset containing the reference frames! Proceed using default\n"); - PointCloudLRFPtr default_frames = std::make_shared(); - lrf_estimation->compute(*default_frames); - frames_ = default_frames; - } - } - - return (true); -} - -#endif //#ifndef PCL_FEATURES_IMPL_FEATURE_H_ diff --git a/plugins/probe/3rd/kdtree.h b/plugins/probe/3rd/kdtree.h deleted file mode 100644 index f486150187..0000000000 --- a/plugins/probe/3rd/kdtree.h +++ /dev/null @@ -1,805 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2012, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * - */ - -#pragma once - -#include "common.h" -#include "nanoflann.hpp" - - -namespace pcl -{ - -/** \brief KdTree represents the base spatial locator class for kd-tree implementations. - * \author Radu B Rusu, Bastian Steder, Michael Dixon - * \ingroup kdtree - */ -template class KdTree { -public: - using IndicesPtr = std::shared_ptr>; - using IndicesConstPtr = std::shared_ptr>; - - using PointCloud = pcl::PointCloud; - using PointCloudPtr = std::shared_ptr; - using PointCloudConstPtr = std::shared_ptr; - - using PointRepresentation = pcl::PointRepresentation; - // using PointRepresentationPtr = std::shared_ptr; - using PointRepresentationConstPtr = std::shared_ptr; - - // shared pointers - typedef std::shared_ptr> Ptr; - typedef std::shared_ptr> ConstPtr; - - /** \brief Empty constructor for KdTree. Sets some internal values to their defaults. - * \param[in] sorted set to true if the application that the tree will be used for requires sorted nearest neighbor - * indices (default). False otherwise. - */ - KdTree(bool sorted = true) - : input_() - , epsilon_(0.0f) - , min_pts_(1) - , sorted_(sorted) - , point_representation_(new DefaultPointRepresentation){}; - - /** \brief Provide a pointer to the input dataset. - * \param[in] cloud the const boost shared pointer to a PointCloud message - * \param[in] indices the point indices subset that is to be used from \a cloud - if NULL the whole cloud is used - */ - virtual void setInputCloud(const PointCloudConstPtr& cloud, const IndicesConstPtr& indices = IndicesConstPtr()) { - input_ = cloud; - indices_ = indices; - } - - /** \brief Get a pointer to the vector of indices used. */ - inline IndicesConstPtr getIndices() const { return (indices_); } - - /** \brief Get a pointer to the input point cloud dataset. */ - inline PointCloudConstPtr getInputCloud() const { return (input_); } - - /** \brief Provide a pointer to the point representation to use to convert points into k-D vectors. - * \param[in] point_representation the const boost shared pointer to a PointRepresentation - */ - inline void setPointRepresentation(const PointRepresentationConstPtr& point_representation) { - point_representation_ = point_representation; - if (!input_) return; - setInputCloud(input_, indices_); // Makes sense in derived classes to reinitialize the tree - } - - /** \brief Get a pointer to the point representation used when converting points into k-D vectors. */ - inline PointRepresentationConstPtr getPointRepresentation() const { return (point_representation_); } - - /** \brief Destructor for KdTree. Deletes all allocated data arrays and destroys the kd-tree structures. */ - virtual ~KdTree(){}; - - /** \brief Search for k-nearest neighbors for the given query point. - * \param[in] p_q the given query point - * \param[in] k the number of neighbors to search for - * \param[out] k_indices the resultant indices of the neighboring points (must be resized to \a k a priori!) - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points (must be resized to \a k - * a priori!) - * \return number of neighbors found - */ - virtual int nearestKSearch( - const PointT& p_q, int k, std::vector& k_indices, std::vector& k_sqr_distances) const = 0; - - /** \brief Search for k-nearest neighbors for the given query point. - * - * \attention This method does not do any bounds checking for the input index - * (i.e., index >= cloud.points.size () || index < 0), and assumes valid (i.e., finite) data. - * - * \param[in] cloud the point cloud data - * \param[in] index a \a valid index in \a cloud representing a \a valid (i.e., finite) query point - * \param[in] k the number of neighbors to search for - * \param[out] k_indices the resultant indices of the neighboring points (must be resized to \a k a priori!) - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points (must be resized to \a k - * a priori!) - * - * \return number of neighbors found - * - * \exception asserts in debug mode if the index is not between 0 and the maximum number of points - */ - virtual int nearestKSearch(const PointCloud& cloud, int index, int k, std::vector& k_indices, - std::vector& k_sqr_distances) const { - assert(index >= 0 && index < static_cast(cloud.points.size()) && - "Out-of-bounds error in nearestKSearch!"); - return (nearestKSearch(cloud.points[index], k, k_indices, k_sqr_distances)); - } - - /** \brief Search for k-nearest neighbors for the given query point. - * This method accepts a different template parameter for the point type. - * \param[in] point the given query point - * \param[in] k the number of neighbors to search for - * \param[out] k_indices the resultant indices of the neighboring points (must be resized to \a k a priori!) - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points (must be resized to \a k - * a priori!) - * \return number of neighbors found - */ - template - inline int nearestKSearchT( - const PointTDiff& point, int k, std::vector& k_indices, std::vector& k_sqr_distances) const { - PointT p; - copyPoint(point, p); - return (nearestKSearch(p, k, k_indices, k_sqr_distances)); - } - - /** \brief Search for k-nearest neighbors for the given query point (zero-copy). - * - * \attention This method does not do any bounds checking for the input index - * (i.e., index >= cloud.points.size () || index < 0), and assumes valid (i.e., finite) data. - * - * \param[in] index a \a valid index representing a \a valid query point in the dataset given - * by \a setInputCloud. If indices were given in setInputCloud, index will be the position in - * the indices vector. - * - * \param[in] k the number of neighbors to search for - * \param[out] k_indices the resultant indices of the neighboring points (must be resized to \a k a priori!) - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points (must be resized to \a k - * a priori!) - * \return number of neighbors found - * - * \exception asserts in debug mode if the index is not between 0 and the maximum number of points - */ - virtual int nearestKSearch( - int index, int k, std::vector& k_indices, std::vector& k_sqr_distances) const { - if (indices_ == nullptr) { - assert(index >= 0 && index < static_cast(input_->points.size()) && - "Out-of-bounds error in nearestKSearch!"); - return (nearestKSearch(input_->points[index], k, k_indices, k_sqr_distances)); - } - assert( - index >= 0 && index < static_cast(indices_->size()) && "Out-of-bounds error in nearestKSearch!"); - return (nearestKSearch(input_->points[(*indices_)[index]], k, k_indices, k_sqr_distances)); - } - - /** \brief Search for all the nearest neighbors of the query point in a given radius. - * \param[in] p_q the given query point - * \param[in] radius the radius of the sphere bounding all of p_q's neighbors - * \param[out] k_indices the resultant indices of the neighboring points - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points - * \param[in] max_nn if given, bounds the maximum returned neighbors to this value. If \a max_nn is set to - * 0 or to a number higher than the number of points in the input cloud, all neighbors in \a radius will be - * returned. - * \return number of neighbors found in radius - */ - virtual int radiusSearch(const PointT& p_q, double radius, std::vector& k_indices, - std::vector& k_sqr_distances, unsigned int max_nn = 0) const = 0; - - /** \brief Search for all the nearest neighbors of the query point in a given radius. - * - * \attention This method does not do any bounds checking for the input index - * (i.e., index >= cloud.points.size () || index < 0), and assumes valid (i.e., finite) data. - * - * \param[in] cloud the point cloud data - * \param[in] index a \a valid index in \a cloud representing a \a valid (i.e., finite) query point - * \param[in] radius the radius of the sphere bounding all of p_q's neighbors - * \param[out] k_indices the resultant indices of the neighboring points - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points - * \param[in] max_nn if given, bounds the maximum returned neighbors to this value. If \a max_nn is set to - * 0 or to a number higher than the number of points in the input cloud, all neighbors in \a radius will be - * returned. - * \return number of neighbors found in radius - * - * \exception asserts in debug mode if the index is not between 0 and the maximum number of points - */ - virtual int radiusSearch(const PointCloud& cloud, int index, double radius, std::vector& k_indices, - std::vector& k_sqr_distances, unsigned int max_nn = 0) const { - assert( - index >= 0 && index < static_cast(cloud.points.size()) && "Out-of-bounds error in radiusSearch!"); - return (radiusSearch(cloud.points[index], radius, k_indices, k_sqr_distances, max_nn)); - } - - /** \brief Search for all the nearest neighbors of the query point in a given radius. - * \param[in] point the given query point - * \param[in] radius the radius of the sphere bounding all of p_q's neighbors - * \param[out] k_indices the resultant indices of the neighboring points - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points - * \param[in] max_nn if given, bounds the maximum returned neighbors to this value. If \a max_nn is set to - * 0 or to a number higher than the number of points in the input cloud, all neighbors in \a radius will be - * returned. - * \return number of neighbors found in radius - */ - template - inline int radiusSearchT(const PointTDiff& point, double radius, std::vector& k_indices, - std::vector& k_sqr_distances, unsigned int max_nn = 0) const { - PointT p; - copyPoint(point, p); - return (radiusSearch(p, radius, k_indices, k_sqr_distances, max_nn)); - } - - /** \brief Search for all the nearest neighbors of the query point in a given radius (zero-copy). - * - * \attention This method does not do any bounds checking for the input index - * (i.e., index >= cloud.points.size () || index < 0), and assumes valid (i.e., finite) data. - * - * \param[in] index a \a valid index representing a \a valid query point in the dataset given - * by \a setInputCloud. If indices were given in setInputCloud, index will be the position in - * the indices vector. - * - * \param[in] radius the radius of the sphere bounding all of p_q's neighbors - * \param[out] k_indices the resultant indices of the neighboring points - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points - * \param[in] max_nn if given, bounds the maximum returned neighbors to this value. If \a max_nn is set to - * 0 or to a number higher than the number of points in the input cloud, all neighbors in \a radius will be - * returned. - * \return number of neighbors found in radius - * - * \exception asserts in debug mode if the index is not between 0 and the maximum number of points - */ - virtual int radiusSearch(int index, double radius, std::vector& k_indices, std::vector& k_sqr_distances, - unsigned int max_nn = 0) const { - if (indices_ == nullptr) { - assert(index >= 0 && index < static_cast(input_->points.size()) && - "Out-of-bounds error in radiusSearch!"); - return (radiusSearch(input_->points[index], radius, k_indices, k_sqr_distances, max_nn)); - } - assert(index >= 0 && index < static_cast(indices_->size()) && "Out-of-bounds error in radiusSearch!"); - return (radiusSearch(input_->points[(*indices_)[index]], radius, k_indices, k_sqr_distances, max_nn)); - } - - /** \brief Set the search epsilon precision (error bound) for nearest neighbors searches. - * \param[in] eps precision (error bound) for nearest neighbors searches - */ - virtual inline void setEpsilon(float eps) { epsilon_ = eps; } - - /** \brief Get the search epsilon precision (error bound) for nearest neighbors searches. */ - inline float getEpsilon() const { return (epsilon_); } - - /** \brief Minimum allowed number of k nearest neighbors points that a viable result must contain. - * \param[in] min_pts the minimum number of neighbors in a viable neighborhood - */ - inline void setMinPts(int min_pts) { min_pts_ = min_pts; } - - /** \brief Get the minimum allowed number of k nearest neighbors points that a viable result must contain. */ - inline int getMinPts() const { return (min_pts_); } - -protected: - /** \brief The input point cloud dataset containing the points we need to use. */ - PointCloudConstPtr input_; - - /** \brief A pointer to the vector of point indices to use. */ - IndicesConstPtr indices_; - - /** \brief Epsilon precision (error bound) for nearest neighbors searches. */ - float epsilon_; - - /** \brief Minimum allowed number of k nearest neighbors points that a viable result must contain. */ - int min_pts_; - - /** \brief Return the radius search neighbours sorted **/ - bool sorted_; - - /** \brief For converting different point structures into k-dimensional vectors for nearest-neighbor search. */ - PointRepresentationConstPtr point_representation_; - - /** \brief Class getName method. */ - virtual std::string getName() const = 0; -}; - - - -// And this is the "dataset to kd-tree" adaptor class: -template struct PointCloudAdaptor { - //typedef typename shvecPointT::element_type vecPointT; - //typedef typename vecPointT::value_type PointT; - //typedef typename PointT::value_t value_t; - typedef typename shvecPointT::element_type PC_type; - typedef typename PC_type::coord_t PointT; - typedef typename PointT::value_t value_t; - - shvecPointT obj; - - /// The constructor that sets the data set source - PointCloudAdaptor(const shvecPointT& obj_) : obj(obj_) {} - - //PointCloudAdaptor(PointCloudAdaptor&&) = delete; - //PointCloudAdaptor(const PointCloudAdaptor&) = delete; - - /// CRTP helper method - inline const shvecPointT& derived() const { return obj; } - - // Must return the number of data points - inline size_t kdtree_get_point_count() const { return derived()->points.size(); } - - // Returns the dim'th component of the idx'th point in the class: - // Since this is inlined and the "dim" argument is typically an immediate value, the - // "if/else's" are actually solved at compile time. - inline value_t kdtree_get_pt(const size_t idx, const size_t dim) const { - if (dim == 0) - return derived()->points[idx].x; - else if (dim == 1) - return derived()->points[idx].y; - else - return derived()->points[idx].z; - } - - // Optional bounding-box computation: return false to default to a standard bbox computation loop. - // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it - // again. Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) - template bool kdtree_get_bbox(BBOX& /*bb*/) const { return false; } - -}; // end of PointCloudAdaptor - - - - /** \brief KdTreeFLANN is a generic type of 3D spatial locator using kD-tree structures. The class is making use of - * the FLANN (Fast Library for Approximate Nearest Neighbor) project by Marius Muja and David Lowe. - * - * \author Radu B. Rusu, Marius Muja - * \ingroup kdtree - */ - template - class KdTreeFLANN : public pcl::KdTree - { - public: - using KdTree::input_; - using KdTree::indices_; - using KdTree::epsilon_; - using KdTree::sorted_; - using KdTree::point_representation_; - using KdTree::nearestKSearch; - using KdTree::radiusSearch; - - using PointCloud = typename KdTree::PointCloud; - using PointCloudConstPtr = typename KdTree::PointCloudConstPtr; - - using IndicesPtr = std::shared_ptr >; - using IndicesConstPtr = std::shared_ptr>; - - // typedef PointCloudAdaptor>>> PC2KD; - typedef PointCloudAdaptor PC2KD; - typedef ::nanoflann::KDTreeSingleIndexAdaptor<::nanoflann::L2_Simple_Adaptor, PC2KD, - 3 /* dim */> FLANNIndex; - - - // Boost shared pointers - using Ptr = std::shared_ptr >; - using ConstPtr = std::shared_ptr >; - - /** \brief Default Constructor for KdTreeFLANN. - * \param[in] sorted set to true if the application that the tree will be used for requires sorted nearest neighbor indices (default). False otherwise. - * - * By setting sorted to false, the \ref radiusSearch operations will be faster. - */ - KdTreeFLANN (bool sorted = true); - - /** \brief Copy constructor - * \param[in] k the tree to copy into this - */ - KdTreeFLANN (const KdTreeFLANN &k); - - /** \brief Copy operator - * \param[in] k the tree to copy into this - */ - inline KdTreeFLANN& - operator = (const KdTreeFLANN& k) - { - KdTree::operator=(k); - flann_index_ = k.flann_index_; - cloud_ = k.cloud_; - index_mapping_ = k.index_mapping_; - identity_mapping_ = k.identity_mapping_; - dim_ = k.dim_; - total_nr_points_ = k.total_nr_points_; - param_k_ = k.param_k_; - param_radius_ = k.param_radius_; - return (*this); - } - - /** \brief Set the search epsilon precision (error bound) for nearest neighbors searches. - * \param[in] eps precision (error bound) for nearest neighbors searches - */ - void - setEpsilon (float eps) override; - - void - setSortedResults (bool sorted); - - inline Ptr makeShared () { return Ptr (new KdTreeFLANN (*this)); } - - /** \brief Destructor for KdTreeFLANN. - * Deletes all allocated data arrays and destroys the kd-tree structures. - */ - ~KdTreeFLANN () - { - cleanup (); - } - - /** \brief Provide a pointer to the input dataset. - * \param[in] cloud the const boost shared pointer to a PointCloud message - * \param[in] indices the point indices subset that is to be used from \a cloud - if NULL the whole cloud is used - */ - void - setInputCloud(const PointCloudConstPtr& cloud, const IndicesConstPtr& indices = IndicesConstPtr()) override; - - /** \brief Search for k-nearest neighbors for the given query point. - * - * \attention This method does not do any bounds checking for the input index - * (i.e., index >= cloud.points.size () || index < 0), and assumes valid (i.e., finite) data. - * - * \param[in] point a given \a valid (i.e., finite) query point - * \param[in] k the number of neighbors to search for - * \param[out] k_indices the resultant indices of the neighboring points (must be resized to \a k a priori!) - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points (must be resized to \a k - * a priori!) - * \return number of neighbors found - * - * \exception asserts in debug mode if the index is not between 0 and the maximum number of points - */ - int - nearestKSearch (const PointT &point, int k, - std::vector &k_indices, std::vector &k_sqr_distances) const override; - - /** \brief Search for all the nearest neighbors of the query point in a given radius. - * - * \attention This method does not do any bounds checking for the input index - * (i.e., index >= cloud.points.size () || index < 0), and assumes valid (i.e., finite) data. - * - * \param[in] point a given \a valid (i.e., finite) query point - * \param[in] radius the radius of the sphere bounding all of p_q's neighbors - * \param[out] k_indices the resultant indices of the neighboring points - * \param[out] k_sqr_distances the resultant squared distances to the neighboring points - * \param[in] max_nn if given, bounds the maximum returned neighbors to this value. If \a max_nn is set to - * 0 or to a number higher than the number of points in the input cloud, all neighbors in \a radius will be - * returned. - * \return number of neighbors found in radius - * - * \exception asserts in debug mode if the index is not between 0 and the maximum number of points - */ - int - radiusSearch(const PointT &point, double radius, std::vector &k_indices, - std::vector &k_sqr_distances, unsigned int max_nn = 0) const override; - - private: - /** \brief Internal cleanup method. */ - void - cleanup (); - - /** \brief Converts a PointCloud to the internal FLANN point array representation. Returns the number - * of points. - * \param cloud the PointCloud - */ - void - convertCloudToArray(const PointCloud &cloud); - - /** \brief Converts a PointCloud with a given set of indices to the internal FLANN point array - * representation. Returns the number of points. - * \param[in] cloud the PointCloud data - * \param[in] indices the point cloud indices - */ - void - convertCloudToArray(const PointCloud& cloud, const std::vector& indices); - - private: - /** \brief Class getName method. */ - std::string - getName () const override { return ("KdTreeFLANN"); } - - /** \brief A FLANN index object. */ - std::shared_ptr flann_index_; - - PC2KD pc2kd; - - /** \brief Internal pointer to data. */ - std::shared_ptr>> cloud_; - - /** \brief mapping between internal and external indices. */ - std::vector index_mapping_; - - /** \brief whether the mapping between internal and external indices is identity */ - bool identity_mapping_; - - /** \brief Tree dimensionality (i.e. the number of dimensions per point). */ - int dim_; - - /** \brief The total size of the data (either equal to the number of points in the input cloud or to the number of indices - if passed). */ - int total_nr_points_; - - /** \brief The KdTree search parameters for K-nearest neighbors. */ - ::nanoflann::SearchParams param_k_; - - /** \brief The KdTree search parameters for radius search. */ - ::nanoflann::SearchParams param_radius_; - }; -} - - -// #include - - -/////////////////////////////////////////////////////////////////////////////////////////// -template -pcl::KdTreeFLANN::KdTreeFLANN(bool sorted) - : pcl::KdTree(sorted) - , flann_index_(nullptr) - , identity_mapping_(false) - , dim_(0) - , total_nr_points_(0) - , param_k_(::nanoflann::SearchParams(-1, epsilon_)) - , param_radius_(::nanoflann::SearchParams(-1, epsilon_, sorted)) - , pc2kd(nullptr) {} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -pcl::KdTreeFLANN::KdTreeFLANN(const KdTreeFLANN& k) - : pcl::KdTree(false) - , flann_index_(nullptr) - , identity_mapping_(false) - , dim_(0) - , total_nr_points_(0) - , param_k_(::nanoflann::SearchParams(-1, epsilon_)) - , param_radius_(::nanoflann::SearchParams(-1, epsilon_, false)) - , pc2kd(nullptr) { - *this = k; -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template void pcl::KdTreeFLANN::setEpsilon(float eps) { - epsilon_ = eps; - param_k_ = ::nanoflann::SearchParams(-1, epsilon_); - param_radius_ = ::nanoflann::SearchParams(-1, epsilon_, sorted_); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template void pcl::KdTreeFLANN::setSortedResults(bool sorted) { - sorted_ = sorted; - param_k_ = ::nanoflann::SearchParams(-1, epsilon_); - param_radius_ = ::nanoflann::SearchParams(-1, epsilon_, sorted_); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::KdTreeFLANN::setInputCloud(const PointCloudConstPtr& cloud, const IndicesConstPtr& indices) { - cleanup(); // Perform an automatic cleanup of structures - - epsilon_ = 0.0f; // default error bound value - dim_ = point_representation_->getNumberOfDimensions(); // Number of dimensions - default is 3 = xyz - - input_ = cloud; - indices_ = indices; - total_nr_points_ = cloud->points.size(); - - // Allocate enough data - //if (!input_) { - // vislib::sys::Log::DefaultLog.WriteError("[pcl::KdTreeFLANN::setInputCloud] Invalid input!\n"); - // return; - //} - //if (indices != nullptr) { - // convertCloudToArray(*input_, *indices_); - //} else { - // convertCloudToArray(*input_); - //} - //total_nr_points_ = static_cast(index_mapping_.size()); - //if (total_nr_points_ == 0) { - // vislib::sys::Log::DefaultLog.WriteError("[pcl::KdTreeFLANN::setInputCloud] Cannot create a KDTree with an empty input cloud!\n"); - // return; - //} - // - // pc2kd = PC2KD(cloud_); - - - pc2kd = PC2KD(cloud); - flann_index_ = std::make_unique(3 /*dim*/, pc2kd, ::nanoflann::KDTreeSingleIndexAdaptorParams(15 /* max leaf */)); - flann_index_->buildIndex(); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -int pcl::KdTreeFLANN::nearestKSearch( - const PointT& point, int k, std::vector& k_indices, std::vector& k_distances) const { - assert(point_representation_->isValid(point) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!"); - - // if (k > total_nr_points_) k = total_nr_points_; - - k_indices.resize(k); - k_distances.resize(k); - - std::vector query(dim_); - point_representation_->vectorize(static_cast(point), query); - - //::flann::Matrix k_indices_mat(&k_indices[0], 1, k); - //::flann::Matrix k_distances_mat(&k_distances[0], 1, k); - // Wrap the k_indices and k_distances vectors (no data copy) - //const PC2KD pc2kd(cloud_); - - //flann_index_ = new FLANNIndex(3 /*dim*/, pc2kd, ::nanoflann::KDTreeSingleIndexAdaptorParams(10)); - //auto flann_idx = new FLANNIndex(3 /*dim*/, pc2kd, ::nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); - //flann_index_.reset( new FLANNIndex(3 /*dim*/, pc2kd, ::nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */))); - //flann_index_.reset(new FLANNIndex(3 /*dim*/, pc2kd, ::nanoflann::KDTreeSingleIndexAdaptorParams(10))); - //flann_index_->buildIndex(); - //flann_index_->knnSearch(::flann::Matrix(&query[0], 1, dim_), k_indices_mat, k_distances_mat, k, param_k_); - - nanoflann::KNNResultSet resultSet(k); - resultSet.init(k_indices.data(), k_distances.data()); - flann_index_->findNeighbors(resultSet, point.data, nanoflann::SearchParams(10)); - - // Do mapping to original point cloud - //if (!identity_mapping_) { - // for (size_t i = 0; i < static_cast(k); ++i) { - // int& neighbor_index = k_indices[i]; - // neighbor_index = index_mapping_[neighbor_index]; - // } - //} - - return (k); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -int pcl::KdTreeFLANN::radiusSearch(const PointT& point, double radius, std::vector& k_indices, - std::vector& k_sqr_dists, unsigned int max_nn) const { - assert(point_representation_->isValid(point) && "Invalid (NaN, Inf) point coordinates given to radiusSearch!"); - - std::vector query(dim_); - point_representation_->vectorize(static_cast(point), query); - - // Has max_nn been set properly? - if (max_nn == 0 || max_nn > static_cast(total_nr_points_)) max_nn = total_nr_points_; - - std::vector> indices(1); - std::vector> dists(1); - - //const PC2KD pc2kd(cloud_); - //auto flann_idx = FLANNIndex(3 /*dim*/, pc2kd, ::nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); - //*flann_index_ = flann_idx; - //flann_index_ = new FLANNIndex(3 /*dim*/, pc2kd, ::nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); - //flann_index_->buildIndex(); - - std::vector> ret_matches; - - ::nanoflann::SearchParams params; - //if (max_nn == static_cast(total_nr_points_)) - // params.max_neighbors = -1; // return all neighbors in radius - //else - // params.max_neighbors = max_nn; - - - //int neighbors_in_radius = flann_index_->radiusSearch( - // ::flann::Matrix(&query[0], 1, dim_), indices, dists, static_cast(radius * radius), params); - - int neighbors_in_radius = flann_index_->radiusSearch(point.data, radius, ret_matches, params); - - // XXX - k_indices.clear(); - k_sqr_dists.clear(); - k_indices.reserve(ret_matches.size()); - k_sqr_dists.reserve(ret_matches.size()); - for (auto& element : ret_matches) { - k_indices.push_back(element.first); - k_sqr_dists.push_back(element.second); - } - - // Do mapping to original point cloud - //if (!identity_mapping_) { - // for (int i = 0; i < neighbors_in_radius; ++i) { - // uint32_t& neighbor_index = k_indices[i]; - // neighbor_index = index_mapping_[neighbor_index]; - // } - //} - - return (neighbors_in_radius); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template void pcl::KdTreeFLANN::cleanup() { - // Data array cleanup - index_mapping_.clear(); - - if (indices_) indices_.reset(); -} - -///////////////////////////////////////////////////////////////////////////////////////////// -//template -//void pcl::KdTreeFLANN::convertCloudToArray(const PointCloud& cloud) { -// // No point in doing anything if the array is empty -// if (cloud.points.empty()) { -// cloud_.reset(); -// return; -// } -// -// int original_no_of_points = static_cast(cloud.points.size()); -// -// cloud_.reset(new float[original_no_of_points * dim_]); -// float* cloud_ptr = cloud_.get(); -// index_mapping_.reserve(original_no_of_points); -// identity_mapping_ = true; -// -// for (int cloud_index = 0; cloud_index < original_no_of_points; ++cloud_index) { -// // Check if the point is invalid -// if (!point_representation_->isValid(cloud.points[cloud_index])) { -// identity_mapping_ = false; -// continue; -// } -// -// index_mapping_.push_back(cloud_index); -// -// point_representation_->vectorize(cloud.points[cloud_index], cloud_ptr); -// cloud_ptr += dim_; -// } -//} -// -///////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::KdTreeFLANN::convertCloudToArray(const PointCloud& cloud, const std::vector& indices) { - // No point in doing anything if the array is empty - if (cloud.points.empty()) { - cloud_.reset(); - return; - } - - int original_no_of_points = static_cast(indices.size()); - - cloud_.reset(new std::vector>(original_no_of_points)); - float* cloud_ptr = reinterpret_cast(cloud_.get()->data()); - index_mapping_.reserve(original_no_of_points); - // its a subcloud -> false - // true only identity: - // - indices size equals cloud size - // - indices only contain values between 0 and cloud.size - 1 - // - no index is multiple times in the list - // => index is complete - // But we can not guarantee that => identity_mapping_ = false - identity_mapping_ = false; - - for (const int& index : indices) { - // Check if the point is invalid - if (!point_representation_->isValid(cloud.points[index])) continue; - - // map from 0 - N -> indices [0] - indices [N] - index_mapping_.push_back(index); // If the returned index should be for the indices vector - - point_representation_->vectorize(cloud.points[index], cloud_ptr); - cloud_ptr += dim_; - } -} - - template - void pcl::KdTreeFLANN::convertCloudToArray(const PointCloud& cloud) { - // No point in doing anything if the array is empty - if (cloud.points.empty()) { - cloud_.reset(); - return; - } - - auto original_no_of_points = static_cast(cloud.points.size()); - - cloud_ = std::make_shared>>(cloud.points); - } - -#define PCL_INSTANTIATE_KdTreeFLANN(T) template class PCL_EXPORTS pcl::KdTreeFLANN; diff --git a/plugins/probe/3rd/normal_3d.h b/plugins/probe/3rd/normal_3d.h deleted file mode 100644 index 6b47cb7722..0000000000 --- a/plugins/probe/3rd/normal_3d.h +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2011, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#pragma once - - -#include "centroid.h" -#include "feature.h" - -namespace pcl { -/** \brief Compute the Least-Squares plane fit for a given set of points, and return the estimated plane - * parameters together with the surface curvature. - * \param cloud the input point cloud - * \param plane_parameters the plane parameters as: a, b, c, d (ax + by + cz + d = 0) - * \param curvature the estimated surface curvature as a measure of - * \f[ - * \lambda_0 / (\lambda_0 + \lambda_1 + \lambda_2) - * \f] - * \ingroup features - */ -template -inline bool computePointNormal( - const pcl::PointCloud& cloud, Eigen::Vector4f& plane_parameters, float& curvature) { - // Placeholder for the 3x3 covariance matrix at each surface patch - EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; - // 16-bytes aligned placeholder for the XYZ centroid of a surface patch - Eigen::Vector4f xyz_centroid; - - if (cloud.size() < 3 || computeMeanAndCovarianceMatrix(cloud, covariance_matrix, xyz_centroid) == 0) { - plane_parameters.setConstant(std::numeric_limits::quiet_NaN()); - curvature = std::numeric_limits::quiet_NaN(); - return false; - } - - // Get the plane normal and surface curvature - solvePlaneParameters(covariance_matrix, xyz_centroid, plane_parameters, curvature); - return true; -} - -/** \brief Compute the Least-Squares plane fit for a given set of points, using their indices, - * and return the estimated plane parameters together with the surface curvature. - * \param cloud the input point cloud - * \param indices the point cloud indices that need to be used - * \param plane_parameters the plane parameters as: a, b, c, d (ax + by + cz + d = 0) - * \param curvature the estimated surface curvature as a measure of - * \f[ - * \lambda_0 / (\lambda_0 + \lambda_1 + \lambda_2) - * \f] - * \ingroup features - */ -template -inline bool computePointNormal(const pcl::PointCloud& cloud, const std::vector& indices, - Eigen::Vector4f& plane_parameters, float& curvature, std::array center) { - // Placeholder for the 3x3 covariance matrix at each surface patch - EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; - if (center[0] != std::numeric_limits::quiet_NaN()) { - center[0] = 0.0f; - } - - - // 16-bytes aligned placeholder for the XYZ centroid of a surface patch - Eigen::Vector4f xyz_centroid; - if (indices.size() < 3 || computeMeanAndCovarianceMatrix(cloud, indices, covariance_matrix, xyz_centroid) == 0) { - plane_parameters.setConstant(std::numeric_limits::quiet_NaN()); - curvature = std::numeric_limits::quiet_NaN(); - return false; - } - // Get the plane normal and surface curvature - solvePlaneParameters(covariance_matrix, xyz_centroid, plane_parameters, curvature); - return true; -} - -/** \brief Flip (in place) the estimated normal of a point towards a given viewpoint - * \param point a given point - * \param vp_x the X coordinate of the viewpoint - * \param vp_y the X coordinate of the viewpoint - * \param vp_z the X coordinate of the viewpoint - * \param normal the plane normal to be flipped - * \ingroup features - */ -template -inline void flipNormalTowardsViewpoint( - const PointT& point, float vp_x, float vp_y, float vp_z, Eigen::Matrix& normal) { - Eigen::Matrix vp(vp_x - point.x, vp_y - point.y, vp_z - point.z, 0); - - // Dot product between the (viewpoint - point) and the plane normal - float cos_theta = vp.dot(normal); - - // Flip the plane normal - if (cos_theta < 0) { - normal *= -1; - normal[3] = 0.0f; - // Hessian form (D = nc . p_plane (centroid here) + p) - normal[3] = -1 * normal.dot(point.getVector4fMap()); - } -} - -/** \brief Flip (in place) the estimated normal of a point towards a given viewpoint - * \param point a given point - * \param vp_x the X coordinate of the viewpoint - * \param vp_y the X coordinate of the viewpoint - * \param vp_z the X coordinate of the viewpoint - * \param normal the plane normal to be flipped - * \ingroup features - */ -template -inline void flipNormalTowardsViewpoint( - const PointT& point, float vp_x, float vp_y, float vp_z, Eigen::Matrix& normal) { - Eigen::Matrix vp(vp_x - point.x, vp_y - point.y, vp_z - point.z); - - // Flip the plane normal - if (vp.dot(normal) < 0) normal *= -1; -} - -/** \brief Flip (in place) the estimated normal of a point towards a given viewpoint - * \param point a given point - * \param vp_x the X coordinate of the viewpoint - * \param vp_y the X coordinate of the viewpoint - * \param vp_z the X coordinate of the viewpoint - * \param nx the resultant X component of the plane normal - * \param ny the resultant Y component of the plane normal - * \param nz the resultant Z component of the plane normal - * \ingroup features - */ -template -inline void flipNormalTowardsViewpoint( - const PointT& point, float vp_x, float vp_y, float vp_z, float& nx, float& ny, float& nz) { - // See if we need to flip any plane normals - vp_x -= point.x; - vp_y -= point.y; - vp_z -= point.z; - - // Dot product between the (viewpoint - point) and the plane normal - float cos_theta = (vp_x * nx + vp_y * ny + vp_z * nz); - - // Flip the plane normal - if (cos_theta < 0) { - nx *= -1; - ny *= -1; - nz *= -1; - } -} - -/** \brief Flip (in place) normal to get the same sign of the mean of the normals specified by normal_indices. - * - * The method is described in: - * A. Petrelli, L. Di Stefano, "A repeatable and efficient canonical reference for surface matching", 3DimPVT, 2012 - * A. Petrelli, L. Di Stefano, "On the repeatability of the local reference frame for partial shape matching", 13th - * International Conference on Computer Vision (ICCV), 2011 - * - * Normals should be unit vectors. Otherwise the resulting mean would be weighted by the normal norms. - * \param[in] normal_cloud Cloud of normals used to compute the mean - * \param[in] normal_indices Indices of normals used to compute the mean - * \param[in] normal input Normal to flip. Normal is modified by the function. - * \return false if normal_indices does not contain any valid normal. - * \ingroup features - */ -template -inline bool flipNormalTowardsNormalsMean( - pcl::PointCloud const& normal_cloud, std::vector const& normal_indices, Eigen::Vector3f& normal) { - Eigen::Vector3f normal_mean = Eigen::Vector3f::Zero(); - - for (const int& normal_index : normal_indices) { - const PointNT& cur_pt = normal_cloud[normal_index]; - - if (cur_pt.isfinite()) { - normal_mean += cur_pt.getNormalVector3fMap(); - } - } - - if (normal_mean.isZero()) return false; - - normal_mean.normalize(); - - if (normal.dot(normal_mean) < 0) { - normal = -normal; - } - - return true; -} - -/** \brief NormalEstimation estimates local surface properties (surface normals and curvatures)at each - * 3D point. If PointOutT is specified as pcl::Normal, the normal is stored in the first 3 components (0-2), - * and the curvature is stored in component 3. - * - * \note The code is stateful as we do not expect this class to be multicore parallelized. Please look at - * \ref NormalEstimationOMP for a parallel implementation. - * \author Radu B. Rusu - * \ingroup features - */ -template class NormalEstimation : public Feature { -public: - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - using Feature::feature_name_; - using Feature::getClassName; - using Feature::indices_; - using Feature::input_; - using Feature::surface_; - using Feature::k_; - using Feature::search_radius_; - using Feature::search_parameter_; - - using PointCloudIn = PointCloud; - using PointCloudInConstPtr = typename PointCloud::ConstPtr; - - using PointCloudOut = PointCloud; - using PointCloudOutConstPtr = typename PointCloud::ConstPtr; - - - /** \brief Empty constructor. */ - NormalEstimation() : vpx_(0), vpy_(0), vpz_(0) { feature_name_ = "NormalEstimation"; }; - - /** \brief Empty destructor */ - ~NormalEstimation() {} - - /** \brief Compute the Least-Squares plane fit for a given set of points, using their indices, - * and return the estimated plane parameters together with the surface curvature. - * \param cloud the input point cloud - * \param indices the point cloud indices that need to be used - * \param plane_parameters the plane parameters as: a, b, c, d (ax + by + cz + d = 0) - * \param curvature the estimated surface curvature as a measure of - * \f[ - * \lambda_0 / (\lambda_0 + \lambda_1 + \lambda_2) - * \f] - */ - inline bool computePointNormal(const pcl::PointCloud& cloud, const std::vector& indices, - Eigen::Vector4f& plane_parameters, float& curvature) { - if (indices.size() < 3 || - computeMeanAndCovarianceMatrix(cloud, indices, covariance_matrix_, xyz_centroid_) == 0) { - plane_parameters.setConstant(std::numeric_limits::quiet_NaN()); - curvature = std::numeric_limits::quiet_NaN(); - return false; - } - - // Get the plane normal and surface curvature - solvePlaneParameters(covariance_matrix_, xyz_centroid_, plane_parameters, curvature); - return true; - } - - /** \brief Compute the Least-Squares plane fit for a given set of points, using their indices, - * and return the estimated plane parameters together with the surface curvature. - * \param cloud the input point cloud - * \param indices the point cloud indices that need to be used - * \param nx the resultant X component of the plane normal - * \param ny the resultant Y component of the plane normal - * \param nz the resultant Z component of the plane normal - * \param curvature the estimated surface curvature as a measure of - * \f[ - * \lambda_0 / (\lambda_0 + \lambda_1 + \lambda_2) - * \f] - */ - inline bool computePointNormal(const pcl::PointCloud& cloud, const std::vector& indices, - float& nx, float& ny, float& nz, float& curvature) { - if (indices.size() < 3 || - computeMeanAndCovarianceMatrix(cloud, indices, covariance_matrix_, xyz_centroid_) == 0) { - nx = ny = nz = curvature = std::numeric_limits::quiet_NaN(); - return false; - } - - // Get the plane normal and surface curvature - solvePlaneParameters(covariance_matrix_, nx, ny, nz, curvature); - return true; - } - - /** \brief Provide a pointer to the input dataset - * \param cloud the const shared pointer to a PointCloud message - */ - inline void setInputCloud(const PointCloudInConstPtr& cloud) override { - input_ = cloud; - // if (use_sensor_origin_) - //{ - // vpx_ = input_->sensor_origin_.coeff (0); - // vpy_ = input_->sensor_origin_.coeff (1); - // vpz_ = input_->sensor_origin_.coeff (2); - //} - } - - /** \brief Set the viewpoint. - * \param vpx the X coordinate of the viewpoint - * \param vpy the Y coordinate of the viewpoint - * \param vpz the Z coordinate of the viewpoint - */ - inline void setViewPoint(float vpx, float vpy, float vpz) { - vpx_ = vpx; - vpy_ = vpy; - vpz_ = vpz; - use_sensor_origin_ = false; - } - - /** \brief Get the viewpoint. - * \param [out] vpx x-coordinate of the view point - * \param [out] vpy y-coordinate of the view point - * \param [out] vpz z-coordinate of the view point - * \note this method returns the currently used viewpoint for normal flipping. - * If the viewpoint is set manually using the setViewPoint method, this method will return the set view point - * coordinates. If an input cloud is set, it will return the sensor origin otherwise it will return the origin (0, - * 0, 0) - */ - inline void getViewPoint(float& vpx, float& vpy, float& vpz) { - vpx = vpx_; - vpy = vpy_; - vpz = vpz_; - } - - /** \brief sets whether the sensor origin or a user given viewpoint should be used. After this method, the - * normal estimation method uses the sensor origin of the input cloud. - * to use a user defined view point, use the method setViewPoint - */ - inline void useSensorOriginAsViewPoint() { - // use_sensor_origin_ = true; - // if (input_) - //{ - // vpx_ = input_->sensor_origin_.coeff (0); - // vpy_ = input_->sensor_origin_.coeff (1); - // vpz_ = input_->sensor_origin_.coeff (2); - //} - // else - { - vpx_ = 0; - vpy_ = 0; - vpz_ = 0; - } - } - -protected: - /** \brief Estimate normals for all points given in using the surface in - * setSearchSurface () and the spatial locator in setSearchMethod () - * \note In situations where not enough neighbors are found, the normal and curvature values are set to NaN. - * \param output the resultant point cloud model dataset that contains surface normals and curvatures - */ - void computeFeature(PointCloudOut& output) override; - - /** \brief Values describing the viewpoint ("pinhole" camera model assumed). For per point viewpoints, inherit - * from NormalEstimation and provide your own computeFeature (). By default, the viewpoint is set to 0,0,0. */ - float vpx_, vpy_, vpz_; - - /** \brief Placeholder for the 3x3 covariance matrix at each surface patch. */ - EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix_; - - /** \brief 16-bytes aligned placeholder for the XYZ centroid of a surface patch. */ - Eigen::Vector4f xyz_centroid_; - - /** whether the sensor origin of the input cloud or a user given viewpoint should be used.*/ - bool use_sensor_origin_ = false; - - /** Cloud center */ - std::array center_ = {std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN (),std::numeric_limits::quiet_NaN ()}; - -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -}; -} // namespace pcl - - -#include "normal_3d.hpp" diff --git a/plugins/probe/3rd/normal_3d.hpp b/plugins/probe/3rd/normal_3d.hpp deleted file mode 100644 index ba6609e6a7..0000000000 --- a/plugins/probe/3rd/normal_3d.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2011, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#ifndef PCL_FEATURES_IMPL_NORMAL_3D_H_ -#define PCL_FEATURES_IMPL_NORMAL_3D_H_ - -#include "normal_3d.h" - -/////////////////////////////////////////////////////////////////////////////////////////// -template void -pcl::NormalEstimation::computeFeature (PointCloudOut &output) -{ - // Allocate enough space to hold the results - // \note This resize is irrelevant for a radiusSearch (). - std::vector nn_indices (k_); - std::vector nn_dists (k_); - - output.is_dense = true; - // Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense - if (input_->is_dense) - { - // Iterating over the entire index vector - for (size_t idx = 0; idx < indices_->size (); ++idx) - { - if (this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0 || - !computePointNormal (*surface_, nn_indices, output.points[idx].normal[0], output.points[idx].normal[1], output.points[idx].normal[2], output.points[idx].curvature)) - { - output.points[idx].normal[0] = output.points[idx].normal[1] = output.points[idx].normal[2] = output.points[idx].curvature = std::numeric_limits::quiet_NaN (); - - output.is_dense = false; - continue; - } - - flipNormalTowardsViewpoint (input_->points[(*indices_)[idx]], vpx_, vpy_, vpz_, - output.points[idx].normal[0], output.points[idx].normal[1], output.points[idx].normal[2]); - - } - } - else - { - // Iterating over the entire index vector - for (size_t idx = 0; idx < indices_->size (); ++idx) - { - if (!(input_->points[(*indices_)[idx]].isfinite()) || - this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0 || - !computePointNormal (*surface_, nn_indices, output.points[idx].normal[0], output.points[idx].normal[1], output.points[idx].normal[2], output.points[idx].curvature)) - { - output.points[idx].normal[0] = output.points[idx].normal[1] = output.points[idx].normal[2] = output.points[idx].curvature = std::numeric_limits::quiet_NaN (); - - output.is_dense = false; - continue; - } - - flipNormalTowardsViewpoint (input_->points[(*indices_)[idx]], vpx_, vpy_, vpz_, - output.points[idx].normal[0], output.points[idx].normal[1], output.points[idx].normal[2]); - - } - } -} - -#define PCL_INSTANTIATE_NormalEstimation(T,NT) template class PCL_EXPORTS pcl::NormalEstimation; - -#endif // PCL_FEATURES_IMPL_NORMAL_3D_H_ diff --git a/plugins/probe/3rd/normal_3d_omp.h b/plugins/probe/3rd/normal_3d_omp.h deleted file mode 100644 index 14c2332a0a..0000000000 --- a/plugins/probe/3rd/normal_3d_omp.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2011, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#pragma once - -#include "normal_3d.h" - -namespace pcl -{ - /** \brief NormalEstimationOMP estimates local surface properties at each 3D point, such as surface normals and - * curvatures, in parallel, using the OpenMP standard. - * \author Radu Bogdan Rusu - * \ingroup features - */ - template - class NormalEstimationOMP: public NormalEstimation - { - public: - using Ptr = std::shared_ptr >; - using ConstPtr = std::shared_ptr >; - using NormalEstimation::feature_name_; - using NormalEstimation::getClassName; - using NormalEstimation::indices_; - using NormalEstimation::input_; - using NormalEstimation::k_; - using NormalEstimation::vpx_; - using NormalEstimation::vpy_; - using NormalEstimation::vpz_; - using NormalEstimation::search_parameter_; - using NormalEstimation::surface_; - using NormalEstimation::getViewPoint; - - using PointCloudOut = typename NormalEstimation::PointCloudOut; - - public: - /** \brief Initialize the scheduler and set the number of threads to use. - * \param nr_threads the number of hardware threads to use (0 sets the value back to automatic) - */ - NormalEstimationOMP (unsigned int nr_threads = 0) - { - feature_name_ = "NormalEstimationOMP"; - - setNumberOfThreads(nr_threads); - } - - /** \brief Initialize the scheduler and set the number of threads to use. - * \param nr_threads the number of hardware threads to use (0 sets the value back to automatic) - */ - void - setNumberOfThreads (unsigned int nr_threads = 0); - - protected: - /** \brief The number of threads the scheduler should use. */ - unsigned int threads_; - - private: - /** \brief Estimate normals for all points given in using the surface in - * setSearchSurface () and the spatial locator in setSearchMethod () - * \param output the resultant point cloud model dataset that contains surface normals and curvatures - */ - void - computeFeature (PointCloudOut &output) override; - }; -} - - -#include "normal_3d_omp.hpp" diff --git a/plugins/probe/3rd/normal_3d_omp.hpp b/plugins/probe/3rd/normal_3d_omp.hpp deleted file mode 100644 index 9557fc3f84..0000000000 --- a/plugins/probe/3rd/normal_3d_omp.hpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010-2011, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#ifndef PCL_FEATURES_IMPL_NORMAL_3D_OMP_H_ -#define PCL_FEATURES_IMPL_NORMAL_3D_OMP_H_ - -#include "normal_3d_omp.h" - -/////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::NormalEstimationOMP::setNumberOfThreads(unsigned int nr_threads) { - if (nr_threads == 0) -#ifdef _OPENMP - threads_ = omp_get_num_procs(); -#else - threads_ = 1; -#endif - else - threads_ = nr_threads; -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::NormalEstimationOMP::computeFeature(PointCloudOut& output) { - // Allocate enough space to hold the results - // \note This resize is irrelevant for a radiusSearch (). - std::vector nn_indices(k_); - std::vector nn_dists(k_); - - output.is_dense = true; - // Save a few cycles by not checking every point for NaN/Inf values if the cloud is set to dense - if (input_->is_dense) { -#ifdef _OPENMP -# pragma omp parallel for shared(output) private(nn_indices, nn_dists) num_threads(threads_) -#endif - // Iterating over the entire index vector - for (int idx = 0; idx < static_cast(indices_->size()); ++idx) { - Eigen::Vector4f n; - if (this->searchForNeighbors((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0 || - !pcl::computePointNormal(*surface_, nn_indices, n, output.points[idx].curvature, this->center_)) { - output.points[idx].normal[0] = output.points[idx].normal[1] = output.points[idx].normal[2] = - output.points[idx].curvature = std::numeric_limits::quiet_NaN(); - - output.is_dense = false; - continue; - } - - output.points[idx].normal_x = n[0]; - output.points[idx].normal_y = n[1]; - output.points[idx].normal_z = n[2]; - output.points[idx].x = input_->points[idx].x; - output.points[idx].y = input_->points[idx].y; - output.points[idx].z = input_->points[idx].z; - - flipNormalTowardsViewpoint(input_->points[(*indices_)[idx]], vpx_, vpy_, vpz_, output.points[idx].normal[0], - output.points[idx].normal[1], output.points[idx].normal[2]); - } - } else { -#ifdef _OPENMP -# pragma omp parallel for shared(output) private(nn_indices, nn_dists) num_threads(threads_) -#endif - // Iterating over the entire index vector - for (int idx = 0; idx < static_cast(indices_->size()); ++idx) { - Eigen::Vector4f n; - if (!(input_->points[(*indices_)[idx]].isfinite()) || - this->searchForNeighbors((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0 || - !pcl::computePointNormal(*surface_, nn_indices, n, output.points[idx].curvature, this->center_)) { - output.points[idx].normal[0] = output.points[idx].normal[1] = output.points[idx].normal[2] = - output.points[idx].curvature = std::numeric_limits::quiet_NaN(); - - output.is_dense = false; - continue; - } - - output.points[idx].normal_x = n[0]; - output.points[idx].normal_y = n[1]; - output.points[idx].normal_z = n[2]; - output.points[idx].x = input_->points[idx].x; - output.points[idx].y = input_->points[idx].y; - output.points[idx].z = input_->points[idx].z; - - flipNormalTowardsViewpoint(input_->points[(*indices_)[idx]], vpx_, vpy_, vpz_, - output.points[idx].normal[0], output.points[idx].normal[1], output.points[idx].normal[2]); - } - } -} - -#define PCL_INSTANTIATE_NormalEstimationOMP(T, NT) template class PCL_EXPORTS pcl::NormalEstimationOMP; - -#endif // PCL_FEATURES_IMPL_NORMAL_3D_OMP_H_ diff --git a/plugins/probe/3rd/poisson.h b/plugins/probe/3rd/poisson.h deleted file mode 100644 index b347a2c660..0000000000 --- a/plugins/probe/3rd/poisson.h +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2010, Willow Garage, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - * - */ - -#pragma once - -#include "common.h" -#include "poisson4/function_data.h" -#include "poisson4/geometry.h" -#include "poisson4/multi_grid_octree_data.h" -#include "poisson4/octree_poisson.h" -#include "poisson4/ppolynomial.h" -#include "poisson4/sparse_matrix.h" -#include "reconstruction.h" - -namespace pcl { -namespace poisson { -class CoredVectorMeshData; -template struct Point3D; -} // namespace poisson - -/** \brief The Poisson surface reconstruction algorithm. - * \note Code adapted from Misha Kazhdan: http://www.cs.jhu.edu/~misha/Code/PoissonRecon/ - * \note Based on the paper: - * * Michael Kazhdan, Matthew Bolitho, Hugues Hoppe, "Poisson surface reconstruction", - * SGP '06 Proceedings of the fourth Eurographics symposium on Geometry processing - * \author Alexandru-Eugen Ichim - * \ingroup surface - */ -template class Poisson : public SurfaceReconstruction { -public: - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - - using SurfaceReconstruction::input_; - using SurfaceReconstruction::tree_; - - using PointCloud = PointCloud; - using PointCloudPtr = typename PointCloud::Ptr; - using PointCloudConstPtr = typename PointCloud::ConstPtr; - - - using KdTree = pcl::KdTree; - using KdTreePtr = typename KdTree::Ptr; - - /** \brief Constructor that sets all the parameters to working default values. */ - Poisson(); - - /** \brief Destructor. */ - ~Poisson(); - - /** \brief Create the surface. - * \param[out] points the vertex positions of the resulting mesh - * \param[out] polygons the connectivity of the resulting mesh - */ - void performReconstruction(pcl::PointCloud& points, std::vector& polygons) override; - - /** \brief Set the maximum depth of the tree that will be used for surface reconstruction. - * \note Running at depth d corresponds to solving on a voxel grid whose resolution is no larger than - * 2^d x 2^d x 2^d. Note that since the reconstructor adapts the octree to the sampling density, the specified - * reconstruction depth is only an upper bound. - * \param[in] depth the depth parameter - */ - inline void setDepth(int depth) { depth_ = depth; } - - /** \brief Get the depth parameter */ - inline int getDepth() { return depth_; } - - inline void setMinDepth(int min_depth) { min_depth_ = min_depth; } - - inline int getMinDepth() { return min_depth_; } - - inline void setPointWeight(float point_weight) { point_weight_ = point_weight; } - - inline float getPointWeight() { return point_weight_; } - - /** \brief Set the ratio between the diameter of the cube used for reconstruction and the diameter of the - * samples' bounding cube. - * \param[in] scale the given parameter value - */ - inline void setScale(float scale) { scale_ = scale; } - - /** Get the ratio between the diameter of the cube used for reconstruction and the diameter of the - * samples' bounding cube. - */ - inline float getScale() { return scale_; } - - /** \brief Set the the depth at which a block Gauss-Seidel solver is used to solve the Laplacian equation - * \note Using this parameter helps reduce the memory overhead at the cost of a small increase in - * reconstruction time. (In practice, we have found that for reconstructions of depth 9 or higher a subdivide - * depth of 7 or 8 can greatly reduce the memory usage.) - * \param[in] solver_divide the given parameter value - */ - inline void setSolverDivide(int solver_divide) { solver_divide_ = solver_divide; } - - /** \brief Get the depth at which a block Gauss-Seidel solver is used to solve the Laplacian equation */ - inline int getSolverDivide() { return solver_divide_; } - - /** \brief Set the depth at which a block iso-surface extractor should be used to extract the iso-surface - * \note Using this parameter helps reduce the memory overhead at the cost of a small increase in extraction - * time. (In practice, we have found that for reconstructions of depth 9 or higher a subdivide depth of 7 or 8 - * can greatly reduce the memory usage.) - * \param[in] iso_divide the given parameter value - */ - inline void setIsoDivide(int iso_divide) { iso_divide_ = iso_divide; } - - /** \brief Get the depth at which a block iso-surface extractor should be used to extract the iso-surface */ - inline int getIsoDivide() { return iso_divide_; } - - /** \brief Set the minimum number of sample points that should fall within an octree node as the octree - * construction is adapted to sampling density - * \note For noise-free samples, small values in the range [1.0 - 5.0] can be used. For more noisy samples, - * larger values in the range [15.0 - 20.0] may be needed to provide a smoother, noise-reduced, reconstruction. - * \param[in] samples_per_node the given parameter value - */ - inline void setSamplesPerNode(float samples_per_node) { samples_per_node_ = samples_per_node; } - - /** \brief Get the minimum number of sample points that should fall within an octree node as the octree - * construction is adapted to sampling density - */ - inline float getSamplesPerNode() { return samples_per_node_; } - - /** \brief Set the confidence flag - * \note Enabling this flag tells the reconstructor to use the size of the normals as confidence information. - * When the flag is not enabled, all normals are normalized to have unit-length prior to reconstruction. - * \param[in] confidence the given flag - */ - inline void setConfidence(bool confidence) { confidence_ = confidence; } - - /** \brief Get the confidence flag */ - inline bool getConfidence() { return confidence_; } - - /** \brief Enabling this flag tells the reconstructor to output a polygon mesh (rather than triangulating the - * results of Marching Cubes). - * \param[in] output_polygons the given flag - */ - inline void setOutputPolygons(bool output_polygons) { output_polygons_ = output_polygons; } - - /** \brief Get whether the algorithm outputs a polygon mesh or a triangle mesh */ - inline bool getOutputPolygons() { return output_polygons_; } - - /** \brief Set the degree parameter - * \param[in] degree the given degree - */ - inline void setDegree(int degree) { degree_ = degree; } - - /** \brief Get the degree parameter */ - inline int getDegree() { return degree_; } - - /** \brief Set the manifold flag. - * \note Enabling this flag tells the reconstructor to add the polygon barycenter when triangulating polygons - * with more than three vertices. - * \param[in] manifold the given flag - */ - inline void setManifold(bool manifold) { manifold_ = manifold; } - - /** \brief Get the manifold flag */ - inline bool getManifold() { return manifold_; } - - /** \brief Sets data input - * - * \param the input cloud - */ - inline void setInputCloud(const PointCloudConstPtr& input) override { this->input_ = input; } - - //inline void setIndices(const IndicesConstPtr& indices) override { this->indices_ = indices; } - - inline void setIndices(const IndicesPtr& indices) override { this->indices_ = indices; } - -protected: - /** \brief Class get name method. */ - std::string getClassName() const override { return ("Poisson"); } - -private: - int depth_; - int min_depth_; - float point_weight_; - float scale_; - int solver_divide_; - int iso_divide_; - float samples_per_node_; - bool confidence_; - bool output_polygons_; - - bool no_reset_samples_; - bool no_clip_tree_; - bool manifold_; - - int refine_; - int kernel_depth_; - int degree_; - bool non_adaptive_weights_; - bool show_residual_; - int min_iterations_; - float solver_accuracy_; - - template - void execute(poisson::CoredVectorMeshData& mesh, poisson::Point3D& translate, float& scale); - -public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW -}; - - -////////////////////////////////////////////////////////////////////////////////////////////// -template -pcl::Poisson::Poisson() - : depth_(8) - , min_depth_(5) - , point_weight_(4) - , scale_(1.1f) - , solver_divide_(8) - , iso_divide_(8) - , samples_per_node_(1.0) - , confidence_(false) - , output_polygons_(false) - , no_reset_samples_(false) - , no_clip_tree_(false) - , manifold_(true) - , refine_(3) - , kernel_depth_(8) - , degree_(2) - , non_adaptive_weights_(false) - , show_residual_(false) - , min_iterations_(8) - , solver_accuracy_(1e-3f) {} - -////////////////////////////////////////////////////////////////////////////////////////////// -template pcl::Poisson::~Poisson() {} - -////////////////////////////////////////////////////////////////////////////////////////////// -template -template -void pcl::Poisson::execute(poisson::CoredVectorMeshData& mesh, poisson::Point3D& center, float& scale) { - pcl::poisson::Real iso_value = 0; - poisson::TreeNodeData::UseIndex = 1; - poisson::Octree tree; - - /// TODO OPENMP stuff - // tree.threads = Threads.value; - center.coords[0] = center.coords[1] = center.coords[2] = 0; - - - if (solver_divide_ < min_depth_) { - megamol::core::utility::log::Log::DefaultLog.WriteWarn( - "[pcl::Poisson] solver_divide_ must be at least as large as min_depth_: %d >= %d\n", solver_divide_, - min_depth_); - solver_divide_ = min_depth_; - } - if (iso_divide_ < min_depth_) { - megamol::core::utility::log::Log::DefaultLog.WriteWarn( - "[pcl::Poisson] iso_divide_ must be at least as large as min_depth_: %d >= %d\n", iso_divide_, min_depth_); - iso_divide_ = min_depth_; - } - - pcl::poisson::TreeOctNode::SetAllocator(MEMORY_ALLOCATOR_BLOCK_SIZE); - - kernel_depth_ = depth_ - 2; - - tree.setBSplineData(depth_, pcl::poisson::Real(1.0 / (1 << depth_)), true); - - tree.maxMemoryUsage = 0; - - - int point_count = tree.template setTree(input_, depth_, min_depth_, kernel_depth_, samples_per_node_, - scale_, center, scale, confidence_, point_weight_, !non_adaptive_weights_); - - tree.ClipTree(); - tree.finalize(); - tree.RefineBoundary(iso_divide_); - - PCL_DEBUG("Input Points: %d\n", point_count); - PCL_DEBUG("Leaves/Nodes: %d/%d\n", tree.tree.leaves(), tree.tree.nodes()); - - tree.maxMemoryUsage = 0; - tree.SetLaplacianConstraints(); - - tree.maxMemoryUsage = 0; - tree.LaplacianMatrixIteration(solver_divide_, show_residual_, min_iterations_, solver_accuracy_); - - iso_value = tree.GetIsoValue(); - - tree.GetMCIsoTriangles(iso_value, iso_divide_, &mesh, 0, 1, manifold_, output_polygons_); -} - - -template -void pcl::Poisson::performReconstruction( - pcl::PointCloud& points, std::vector& polygons) { - poisson::CoredVectorMeshData mesh; - poisson::Point3D center; - float scale = 1.0f; - - switch (degree_) { - case 1: { - execute<1>(mesh, center, scale); - break; - } - case 2: { - execute<2>(mesh, center, scale); - break; - } - case 3: { - execute<3>(mesh, center, scale); - break; - } - case 4: { - execute<4>(mesh, center, scale); - break; - } - case 5: { - execute<5>(mesh, center, scale); - break; - } - default: { - megamol::core::utility::log::Log::DefaultLog.WriteError("Degree %d not supported\n", degree_); - } - } - - // Write output PolygonMesh - // Write vertices - points.points.resize(int(mesh.outOfCorePointCount() + mesh.inCorePoints.size())); - poisson::Point3D p; - for (int i = 0; i < int(mesh.inCorePoints.size()); i++) { - p = mesh.inCorePoints[i]; - points.points[i].x = p.coords[0] * scale + center.coords[0]; - points.points[i].y = p.coords[1] * scale + center.coords[1]; - points.points[i].z = p.coords[2] * scale + center.coords[2]; - } - for (int i = int(mesh.inCorePoints.size()); i < int(mesh.outOfCorePointCount() + mesh.inCorePoints.size()); i++) { - mesh.nextOutOfCorePoint(p); - points.points[i].x = p.coords[0] * scale + center.coords[0]; - points.points[i].y = p.coords[1] * scale + center.coords[1]; - points.points[i].z = p.coords[2] * scale + center.coords[2]; - } - - polygons.resize(mesh.polygonCount()); - - // Write faces - std::vector polygon; - for (int p_i = 0; p_i < mesh.polygonCount(); p_i++) { - pcl::Vertices v; - mesh.nextPolygon(polygon); - assert(polygon.size() == 3); - //v.vertices.resize(polygon.size()); - - for (int i = 0; i < static_cast(polygon.size()); ++i) - if (polygon[i].inCore) - v.vertices[i] = polygon[i].idx; - else - v.vertices[i] = polygon[i].idx + int(mesh.inCorePoints.size()); - - polygons[p_i] = v; - } -} - - -#define PCL_INSTANTIATE_Poisson(T) template class PCL_EXPORTS pcl::Poisson; - -} // namespace pcl diff --git a/plugins/probe/3rd/poisson4/allocator.h b/plugins/probe/3rd/poisson4/allocator.h deleted file mode 100644 index 1b5cb0aafd..0000000000 --- a/plugins/probe/3rd/poisson4/allocator.h +++ /dev/null @@ -1,168 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef ALLOCATOR_INCLUDED -#define ALLOCATOR_INCLUDED -#include - -namespace pcl -{ - namespace poisson - { - class AllocatorState{ - public: - int index,remains; - }; - /** This templated class assists in memory allocation and is well suited for instances - * when it is known that the sequence of memory allocations is performed in a stack-based - * manner, so that memory allocated last is released first. It also preallocates memory - * in chunks so that multiple requests for small chunks of memory do not require separate - * system calls to the memory manager. - * The allocator is templated off of the class of objects that we would like it to allocate, - * ensuring that appropriate constructors and destructors are called as necessary. - */ - template - class Allocator{ - int blockSize; - int index,remains; - std::vector memory; - public: - Allocator(void){ - blockSize=index=remains=0; - } - ~Allocator(void){ - reset(); - } - - /** This method is the allocators destructor. It frees up any of the memory that - * it has allocated. */ - void reset(void){ - for(size_t i=0;iblockSize=blockSize; - index=-1; - remains=0; - } - - /** This method returns a pointer to an array of elements objects. If there is left over pre-allocated - * memory, this method simply returns a pointer to the next free piece of memory, otherwise it pre-allocates - * more memory. Note that if the number of objects requested is larger than the value blockSize with which - * the allocator was initialized, the request for memory will fail. - */ - T* newElements( int elements=1){ - T* mem; - if(!elements){return NULL;} - if(elements>blockSize){ - fprintf(stderr,"Allocator Error, elements bigger than block-size: %d>%d\n",elements,blockSize); - return NULL; - } - if(remains - class BinaryNode - { - public: - static inline int CenterCount( int depth ) { return 1<>= 1; - depth++; - } -#if MSVC_2010_FIX - depth--; -#endif // MSVC_2010_FIX - offset = ( idx+1 ) - (1< - class BSplineData - { - bool useDotRatios; - bool reflectBoundary; - public: - struct BSplineComponents - { - Polynomial< Degree > polys[Degree+1]; - Polynomial< Degree >& operator[] ( int idx ) { return polys[idx]; } - const Polynomial< Degree >& operator[] ( int idx ) const { return polys[idx]; } - void printnl( void ) const { for( int d=0 ; d<=Degree ; d++ ) polys[d].printnl(); } - BSplineComponents scale( double s ) const { BSplineComponents b ; for( int d=0 ; d<=Degree ; d++ ) b[d] = polys[d].scale(s) ; return b; } - BSplineComponents shift( double s ) const { BSplineComponents b ; for( int d=0 ; d<=Degree ; d++ ) b[d] = polys[d].shift(s) ; return b; } - }; - const static int VV_DOT_FLAG = 1; - const static int DV_DOT_FLAG = 2; - const static int DD_DOT_FLAG = 4; - const static int VALUE_FLAG = 1; - const static int D_VALUE_FLAG = 2; - - int depth , functionCount , sampleCount; - Real *vvDotTable , *dvDotTable , *ddDotTable; - Real *valueTables , *dValueTables; - PPolynomial< Degree > baseFunction , leftBaseFunction , rightBaseFunction; - PPolynomial< Degree-1 > dBaseFunction , dLeftBaseFunction , dRightBaseFunction; - BSplineComponents baseBSpline, leftBSpline , rightBSpline; - PPolynomial* baseFunctions; - BSplineComponents* baseBSplines; - - BSplineData(void); - ~BSplineData(void); - - virtual void setDotTables( int flags ); - virtual void clearDotTables( int flags ); - - virtual void setValueTables( int flags,double smooth=0); - virtual void setValueTables( int flags,double valueSmooth,double normalSmooth); - virtual void clearValueTables(void); - - void setSampleSpan( int idx , int& start , int& end , double smooth=0 ) const; - - /******************************************************** - * Sets the translates and scales of the basis function - * up to the prescribed depth - * the maximum depth - * specifies if dot-products of derivatives - * should be pre-divided by function integrals - * spcifies if function space should be - * forced to be reflectively symmetric across the boundary - ********************************************************/ - void set( int maxDepth , bool useDotRatios=true , bool reflectBoundary=false ); - - inline int Index( int i1 , int i2 ) const; - static inline int SymmetricIndex( int i1 , int i2 ); - static inline int SymmetricIndex( int i1 , int i2 , int& index ); - }; - - template< int Degree > - struct BSplineElementCoefficients - { - int coeffs[Degree+1]; - BSplineElementCoefficients( void ) { memset( coeffs , 0 , sizeof( int ) * ( Degree+1 ) ); } - int& operator[]( int idx ){ return coeffs[idx]; } - const int& operator[]( int idx ) const { return coeffs[idx]; } - }; - template< int Degree > - struct BSplineElements : public std::vector< BSplineElementCoefficients< Degree > > - { - static const int _off = (Degree+1)/2; - void _addLeft ( int offset , int boundary ); - void _addRight( int offset , int boundary ); - public: - enum - { - NONE = 0, - DIRICHLET = -1, - NEUMANN = 1 - }; - // Coefficients are ordered as "/" "-" "\" - int denominator; - - BSplineElements( void ) { denominator = 1; } - BSplineElements( int res , int offset , int boundary=NONE ); - - void upSample( BSplineElements& high ) const; - void differentiate( BSplineElements< Degree-1 >& d ) const; - - void print( FILE* fp=stdout ) const - { - for( int i=0 ; isize() ; i++ ) - { - printf( "%d]" , i ); - for( int j=0 ; j<=Degree ; j++ ) printf( " %d" , (*this)[i][j] ); - printf( " (%d)\n" , denominator ); - } - } - }; - template< int Degree1 , int Degree2 > void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ); - - - } -} - - -#include "poisson4/bspline_data.hpp" - -#endif // BSPLINE_DATA_INCLUDED diff --git a/plugins/probe/3rd/poisson4/bspline_data.hpp b/plugins/probe/3rd/poisson4/bspline_data.hpp deleted file mode 100644 index 8a2110efc8..0000000000 --- a/plugins/probe/3rd/poisson4/bspline_data.hpp +++ /dev/null @@ -1,534 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include "poisson_exceptions.h" - - -namespace pcl -{ - namespace poisson - { - - ///////////////// - // BSplineData // - ///////////////// - // Support[i]: - // Odd: i +/- 0.5 * ( 1 + Degree ) - // i - 0.5 * ( 1 + Degree ) < 0 - // <=> i < 0.5 * ( 1 + Degree ) - // i + 0.5 * ( 1 + Degree ) > 0 - // <=> i > - 0.5 * ( 1 + Degree ) - // i + 0.5 * ( 1 + Degree ) > r - // <=> i > r - 0.5 * ( 1 + Degree ) - // i - 0.5 * ( 1 + Degree ) < r - // <=> i < r + 0.5 * ( 1 + Degree ) - // Even: i + 0.5 +/- 0.5 * ( 1 + Degree ) - // i - 0.5 * Degree < 0 - // <=> i < 0.5 * Degree - // i + 1 + 0.5 * Degree > 0 - // <=> i > -1 - 0.5 * Degree - // i + 1 + 0.5 * Degree > r - // <=> i > r - 1 - 0.5 * Degree - // i - 0.5 * Degree < r - // <=> i < r + 0.5 * Degree - template< int Degree > inline bool LeftOverlap( unsigned int depth , int offset ) - { - offset <<= 1; - if( Degree & 1 ) return (offset < 1+Degree) && (offset > -1-Degree ); - else return (offset < Degree) && (offset > -2-Degree ); - } - template< int Degree > inline bool RightOverlap( unsigned int depth , int offset ) - { - offset <<= 1; - int r = 1<<(depth+1); - if( Degree & 1 ) return (offset > 2-1-Degree) && (offset < 2+1+Degree ); - else return (offset > 2-2-Degree) && (offset < 2+ Degree ); - } - template< int Degree > inline int ReflectLeft( unsigned int depth , int offset ) - { - if( Degree&1 ) return -offset; - else return -1-offset; - } - template< int Degree > inline int ReflectRight( unsigned int depth , int offset ) - { - int r = 1<<(depth+1); - if( Degree&1 ) return r -offset; - else return r-1-offset; - } - - template< int Degree , class Real > - inline BSplineData::BSplineData( void ) - { - vvDotTable = dvDotTable = ddDotTable = NULL; - valueTables = dValueTables = NULL; - baseFunctions = NULL; - baseBSplines = NULL; - functionCount = sampleCount = 0; - } - - template< int Degree , class Real > - BSplineData< Degree , Real >::~BSplineData(void) - { - if( functionCount ) - { - if( vvDotTable ) delete[] vvDotTable; - if( dvDotTable ) delete[] dvDotTable; - if( ddDotTable ) delete[] ddDotTable; - - if( valueTables ) delete[] valueTables; - if( dValueTables ) delete[] dValueTables; - - if( baseFunctions ) delete[] baseFunctions; - if( baseBSplines ) delete[] baseBSplines; - } - vvDotTable = dvDotTable = ddDotTable = NULL; - valueTables = dValueTables=NULL; - baseFunctions = NULL; - baseBSplines = NULL; - functionCount = 0; - } - - template - void BSplineData::set( int maxDepth , bool useDotRatios , bool reflectBoundary ) - { - this->useDotRatios = useDotRatios; - this->reflectBoundary = reflectBoundary; - - depth = maxDepth; - // [Warning] This assumes that the functions spacing is dual - functionCount = BinaryNode< double >::CumulativeCenterCount( depth ); - sampleCount = BinaryNode< double >::CenterCount( depth ) + BinaryNode< double >::CornerCount( depth ); - baseFunctions = new PPolynomial[functionCount]; - baseBSplines = new BSplineComponents[functionCount]; - - baseFunction = PPolynomial< Degree >::BSpline(); - for( int i=0 ; i<=Degree ; i++ ) baseBSpline[i] = Polynomial< Degree >::BSplineComponent( i ).shift( double(-(Degree+1)/2) + i - 0.5 ); - dBaseFunction = baseFunction.derivative(); - StartingPolynomial< Degree > sPolys[Degree+3]; - - for( int i=0 ; i=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1]; - for( int j=0 ; j=1 && i<=Degree+1 ) sPolys[i].p += baseBSpline[i-1].shift( 1 ); - for( int j=0 ; j::CenterAndWidth( i , c , w ); - baseFunctions[i] = baseFunction.scale(w).shift(c); - baseBSplines[i] = baseBSpline.scale(w).shift(c); - if( reflectBoundary ) - { - int d , off , r; - BinaryNode< double >::DepthAndOffset( i , d , off ); - r = 1< - void BSplineData::setDotTables( int flags ) - { - clearDotTables( flags ); - int size = ( functionCount*functionCount + functionCount )>>1; - int fullSize = functionCount*functionCount; - if( flags & VV_DOT_FLAG ) - { - vvDotTable = new Real[size]; - memset( vvDotTable , 0 , sizeof(Real)*size ); - } - if( flags & DV_DOT_FLAG ) - { - dvDotTable = new Real[fullSize]; - memset( dvDotTable , 0 , sizeof(Real)*fullSize ); - } - if( flags & DD_DOT_FLAG ) - { - ddDotTable = new Real[size]; - memset( ddDotTable , 0 , sizeof(Real)*size ); - } - double vvIntegrals[Degree+1][Degree+1]; - double vdIntegrals[Degree+1][Degree ]; - double dvIntegrals[Degree ][Degree+1]; - double ddIntegrals[Degree ][Degree ]; - int vvSums[Degree+1][Degree+1]; - int vdSums[Degree+1][Degree ]; - int dvSums[Degree ][Degree+1]; - int ddSums[Degree ][Degree ]; - SetBSplineElementIntegrals< Degree , Degree >( vvIntegrals ); - SetBSplineElementIntegrals< Degree , Degree-1 >( vdIntegrals ); - SetBSplineElementIntegrals< Degree-1 , Degree >( dvIntegrals ); - SetBSplineElementIntegrals< Degree-1 , Degree-1 >( ddIntegrals ); - - for( int d1=0 ; d1<=depth ; d1++ ) - for( int off1=0 ; off1<(1<::CenterIndex( d1 , off1 ); - BSplineElements< Degree > b1( 1<::NEUMANN : BSplineElements< Degree>::NONE ); - BSplineElements< Degree-1 > db1; - b1.differentiate( db1 ); - - int start1 , end1; - - start1 = -1; - for( int i=0 ; i=end1 || start1>=end2 ) continue; - start2 = std::max< int >( start1 , start2 ); - end2 = std::min< int >( end1 , end2 ); - if( d1==d2 && off2::CenterIndex( d2 , off2 ); - BSplineElements< Degree > b2( 1<::NEUMANN : BSplineElements< Degree>::NONE ); - BSplineElements< Degree-1 > db2; - b2.differentiate( db2 ); - - int idx = SymmetricIndex( ii , jj ); - int idx1 = Index( ii , jj ) , idx2 = Index( jj , ii ); - - memset( vvSums , 0 , sizeof( int ) * ( Degree+1 ) * ( Degree+1 ) ); - memset( vdSums , 0 , sizeof( int ) * ( Degree+1 ) * ( Degree ) ); - memset( dvSums , 0 , sizeof( int ) * ( Degree ) * ( Degree+1 ) ); - memset( ddSums , 0 , sizeof( int ) * ( Degree ) * ( Degree ) ); - for( int i=start2 ; i b; - b = b1; - b.upSample( b1 ); - b1.differentiate( db1 ); - start1 = -1; - for( int i=0 ; i - void BSplineData::clearDotTables( int flags ) - { - if( (flags & VV_DOT_FLAG) && vvDotTable ) delete[] vvDotTable , vvDotTable = NULL; - if( (flags & DV_DOT_FLAG) && dvDotTable ) delete[] dvDotTable , dvDotTable = NULL; - if( (flags & DD_DOT_FLAG) && ddDotTable ) delete[] ddDotTable , ddDotTable = NULL; - } - template< int Degree , class Real > - void BSplineData< Degree , Real >::setSampleSpan( int idx , int& start , int& end , double smooth ) const - { - int d , off , res; - BinaryNode< double >::DepthAndOffset( idx , d , off ); - res = 1<_start && (start-1)/(sampleCount-1)<=_start - // => start > _start * (sampleCount-1 ) && start <= _start*(sampleCount-1) + 1 - // => _start * (sampleCount-1) + 1 >= start > _start * (sampleCount-1) - start = int( floor( _start * (sampleCount-1) + 1 ) ); - if( start<0 ) start = 0; - // (end)/(sampleCount-1)<_end && (end+1)/(sampleCount-1)>=_end - // => end < _end * (sampleCount-1 ) && end >= _end*(sampleCount-1) - 1 - // => _end * (sampleCount-1) > end >= _end * (sampleCount-1) - 1 - end = int( ceil( _end * (sampleCount-1) - 1 ) ); - if( end>=sampleCount ) end = sampleCount-1; - } - template - void BSplineData::setValueTables( int flags , double smooth ) - { - clearValueTables(); - if( flags & VALUE_FLAG ) valueTables = new Real[functionCount*sampleCount]; - if( flags & D_VALUE_FLAG ) dValueTables = new Real[functionCount*sampleCount]; - PPolynomial function; - PPolynomial dFunction; - for( int i=0 ; i0) - { - function = baseFunctions[i].MovingAverage(smooth); - dFunction = baseFunctions[i].derivative().MovingAverage(smooth); - } - else - { - function = baseFunctions[i]; - dFunction = baseFunctions[i].derivative(); - } - for( int j=0 ; j - void BSplineData::setValueTables(int flags,double valueSmooth,double normalSmooth){ - clearValueTables(); - if(flags & VALUE_FLAG){ valueTables=new Real[functionCount*sampleCount];} - if(flags & D_VALUE_FLAG){dValueTables=new Real[functionCount*sampleCount];} - PPolynomial function; - PPolynomial dFunction; - for(int i=0;i0) { function=baseFunctions[i].MovingAverage(valueSmooth);} - else { function=baseFunctions[i];} - if(normalSmooth>0) {dFunction=baseFunctions[i].derivative().MovingAverage(normalSmooth);} - else {dFunction=baseFunctions[i].derivative();} - - for(int j=0;j - void BSplineData::clearValueTables(void){ - if( valueTables){delete[] valueTables;} - if(dValueTables){delete[] dValueTables;} - valueTables=dValueTables=NULL; - } - - template - inline int BSplineData::Index( int i1 , int i2 ) const { return i1*functionCount+i2; } - template - inline int BSplineData::SymmetricIndex( int i1 , int i2 ) - { - if( i1>i2 ) return ((i1*i1+i1)>>1)+i2; - else return ((i2*i2+i2)>>1)+i1; - } - template - inline int BSplineData::SymmetricIndex( int i1 , int i2 , int& index ) - { - if( i1>1)+i1; - return 1; - } - else - { - index = ((i1*i1+i1)>>1)+i2; - return 0; - } - } - - - //////////////////////// - // BSplineElementData // - //////////////////////// - template< int Degree > - BSplineElements< Degree >::BSplineElements( int res , int offset , int boundary ) - { - denominator = 1; - this->resize( res , BSplineElementCoefficients() ); - - for( int i=0 ; i<=Degree ; i++ ) - { - int idx = -_off + offset + i; - if( idx>=0 && idx - void BSplineElements< Degree >::_addLeft( int offset , int boundary ) - { - int res = int( this->size() ); - bool set = false; - for( int i=0 ; i<=Degree ; i++ ) - { - int idx = -_off + offset + i; - if( idx>=0 && idx - void BSplineElements< Degree >::_addRight( int offset , int boundary ) - { - int res = int( this->size() ); - bool set = false; - for( int i=0 ; i<=Degree ; i++ ) - { - int idx = -_off + offset + i; - if( idx>=0 && idx - void BSplineElements< Degree >::upSample( BSplineElements< Degree >& high ) const - { - POISSON_THROW_EXCEPTION (pcl::poisson::PoissonBadArgumentException, "B-spline up-sampling not supported for degree " << Degree); - } - template<> inline void BSplineElements< 1 >::upSample( BSplineElements< 1 >& high ) const - { - high.resize( size()*2 ); - high.assign( high.size() , BSplineElementCoefficients<1>() ); - for( int i=0 ; i inline void BSplineElements< 2 >::upSample( BSplineElements< 2 >& high ) const - { - // /----\ - // / \ - // / \ = 1 /--\ +3 /--\ +3 /--\ +1 /--\ - // / \ / \ / \ / \ / \ - // |----------| |----------| |----------| |----------| |----------| - - high.resize( size()*2 ); - high.assign( high.size() , BSplineElementCoefficients<2>() ); - for( int i=0 ; i - void BSplineElements< Degree >::differentiate( BSplineElements< Degree-1 >& d ) const - { - d.resize( this->size() ); - d.assign( d.size() , BSplineElementCoefficients< Degree-1 >() ); - for( int i=0 ; isize()) ; i++ ) for( int j=0 ; j<=Degree ; j++ ) - { - if( j-1>=0 ) d[i][j-1] -= (*this)[i][j]; - if( j - void SetBSplineElementIntegrals( double integrals[Degree1+1][Degree2+1] ) - { - for( int i=0 ; i<=Degree1 ; i++ ) - { - Polynomial< Degree1 > p1 = Polynomial< Degree1 >::BSplineComponent( i ); - for( int j=0 ; j<=Degree2 ; j++ ) - { - Polynomial< Degree2 > p2 = Polynomial< Degree2 >::BSplineComponent( j ); - integrals[i][j] = ( p1 * p2 ).integral( 0 , 1 ); - } - } - } - - - } -} diff --git a/plugins/probe/3rd/poisson4/factor.cpp b/plugins/probe/3rd/poisson4/factor.cpp deleted file mode 100644 index f554b66a7e..0000000000 --- a/plugins/probe/3rd/poisson4/factor.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -////////////////////// -// Polynomial Roots // -////////////////////// -#include -#include "poisson4/factor.h" - -namespace pcl -{ - namespace poisson - { - - - int Factor(double a1,double a0,double roots[1][2],double EPS){ - if(fabs(a1)<=EPS){return 0;} - roots[0][0]=-a0/a1; - roots[0][1]=0; - return 1; - } - int Factor(double a2,double a1,double a0,double roots[2][2],double EPS){ - double d; - if(fabs(a2)<=EPS){return Factor(a1,a0,roots,EPS);} - - d=a1*a1-4*a0*a2; - a1/=(2*a2); - if(d<0){ - d=sqrt(-d)/(2*a2); - roots[0][0]=roots[1][0]=-a1; - roots[0][1]=-d; - roots[1][1]= d; - } - else{ - d=sqrt(d)/(2*a2); - roots[0][1]=roots[1][1]=0; - roots[0][0]=-a1-d; - roots[1][0]=-a1+d; - } - return 2; - } - // Solution taken from: http://mathworld.wolfram.com/CubicFormula.html - // and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 - int Factor(double a3,double a2,double a1,double a0,double roots[3][2],double EPS){ - double q,r,r2,q3; - - if(fabs(a3)<=EPS){return Factor(a2,a1,a0,roots,EPS);} - a2/=a3; - a1/=a3; - a0/=a3; - - q=-(3*a1-a2*a2)/9; - r=-(9*a2*a1-27*a0-2*a2*a2*a2)/54; - r2=r*r; - q3=q*q*q; - - if(r20){return PI/2.0;} - else{return -PI/2.0;} - } - if(x>=0){return atan(y/x);} - else{ - if(y>=0){return atan(y/x)+PI;} - else{return atan(y/x)-PI;} - } - } - double Angle(const double in[2]){ - if((in[0]*in[0]+in[1]*in[1])==0.0){return 0;} - else{return ArcTan2(in[1],in[0]);} - } - void Sqrt(const double in[2],double out[2]){ - double r=sqrt(sqrt(in[0]*in[0]+in[1]*in[1])); - double a=Angle(in)*0.5; - out[0]=r*cos(a); - out[1]=r*sin(a); - } - void Add(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]+in2[0]; - out[1]=in1[1]+in2[1]; - } - void Subtract(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]-in2[0]; - out[1]=in1[1]-in2[1]; - } - void Multiply(const double in1[2],const double in2[2],double out[2]){ - out[0]=in1[0]*in2[0]-in1[1]*in2[1]; - out[1]=in1[0]*in2[1]+in1[1]*in2[0]; - } - void Divide(const double in1[2],const double in2[2],double out[2]){ - double temp[2]; - double l=in2[0]*in2[0]+in2[1]*in2[1]; - temp[0]= in2[0]/l; - temp[1]=-in2[1]/l; - Multiply(in1,temp,out); - } - // Solution taken from: http://mathworld.wolfram.com/QuarticEquation.html - // and http://www.csit.fsu.edu/~burkardt/f_src/subpak/subpak.f90 - int Factor(double a4,double a3,double a2,double a1,double a0,double roots[4][2],double EPS){ - double R[2],D[2],E[2],R2[2]; - - if(fabs(a4)10e-8){ - double temp1[2],temp2[2]; - double p1[2],p2[2]; - - p1[0]=a3*a3*0.75-2.0*a2-R2[0]; - p1[1]=0; - - temp2[0]=((4.0*a3*a2-8.0*a1-a3*a3*a3)/4.0); - temp2[1]=0; - Divide(temp2,R,p2); - - Add (p1,p2,temp1); - Subtract(p1,p2,temp2); - - Sqrt(temp1,D); - Sqrt(temp2,E); - } - else{ - R[0]=R[1]=0; - double temp1[2],temp2[2]; - temp1[0]=roots[0][0]*roots[0][0]-4.0*a0; - temp1[1]=0; - Sqrt(temp1,temp2); - temp1[0]=a3*a3*0.75-2.0*a2+2.0*temp2[0]; - temp1[1]= 2.0*temp2[1]; - Sqrt(temp1,D); - temp1[0]=a3*a3*0.75-2.0*a2-2.0*temp2[0]; - temp1[1]= -2.0*temp2[1]; - Sqrt(temp1,E); - } - - roots[0][0]=-a3/4.0+R[0]/2.0+D[0]/2.0; - roots[0][1]= R[1]/2.0+D[1]/2.0; - - roots[1][0]=-a3/4.0+R[0]/2.0-D[0]/2.0; - roots[1][1]= R[1]/2.0-D[1]/2.0; - - roots[2][0]=-a3/4.0-R[0]/2.0+E[0]/2.0; - roots[2][1]= -R[1]/2.0+E[1]/2.0; - - roots[3][0]=-a3/4.0-R[0]/2.0-E[0]/2.0; - roots[3][1]= -R[1]/2.0-E[1]/2.0; - return 4; - } - - int Solve(const double* eqns,const double* values,double* solutions,int dim){ - int i,j,eIndex; - double v,m; - int *index=new int[dim]; - int *set=new int[dim]; - double* myEqns=new double[dim*dim]; - double* myValues=new double[dim]; - - for(i=0;im){ - m=fabs(myEqns[j*dim+i]); - eIndex=j; - } - } - if(eIndex==-1){ - delete[] index; - delete[] myValues; - delete[] myEqns; - delete[] set; - return 0; - } - // The position in which the solution for the i-th variable can be found - index[i]=eIndex; - set[eIndex]=1; - - // Normalize the equation - v=myEqns[eIndex*dim+i]; - for(j=0;j - class FunctionData{ - bool useDotRatios; - int normalize; -#if BOUNDARY_CONDITIONS - bool reflectBoundary; -#endif // BOUNDARY_CONDITIONS - public: - const static int DOT_FLAG = 1; - const static int D_DOT_FLAG = 2; - const static int D2_DOT_FLAG = 4; - const static int VALUE_FLAG = 1; - const static int D_VALUE_FLAG = 2; - - int depth , res , res2; - Real *dotTable , *dDotTable , *d2DotTable; - Real *valueTables , *dValueTables; -#if BOUNDARY_CONDITIONS - PPolynomial baseFunction , leftBaseFunction , rightBaseFunction; - PPolynomial dBaseFunction , dLeftBaseFunction , dRightBaseFunction; -#else // !BOUNDARY_CONDITIONS - PPolynomial baseFunction; - PPolynomial dBaseFunction; -#endif // BOUNDARY_CONDITIONS - PPolynomial* baseFunctions; - - FunctionData(void); - ~FunctionData(void); - - virtual void setDotTables(const int& flags); - virtual void clearDotTables(const int& flags); - - virtual void setValueTables(const int& flags,const double& smooth=0); - virtual void setValueTables(const int& flags,const double& valueSmooth,const double& normalSmooth); - virtual void clearValueTables(void); - - /******************************************************** - * Sets the translates and scales of the basis function - * up to the prescribed depth - * the maximum depth - * the basis function - * how the functions should be scaled - * 0] Value at zero equals 1 - * 1] Integral equals 1 - * 2] L2-norm equals 1 - * specifies if dot-products of derivatives - * should be pre-divided by function integrals - * spcifies if function space should be - * forced to be reflectively symmetric across the boundary - ********************************************************/ -#if BOUNDARY_CONDITIONS - void set( const int& maxDepth , const PPolynomial& F , const int& normalize , bool useDotRatios=true , bool reflectBoundary=false ); -#else // !BOUNDARY_CONDITIONS - void set(const int& maxDepth,const PPolynomial& F,const int& normalize , bool useDotRatios=true ); -#endif // BOUNDARY_CONDITIONS - -#if BOUNDARY_CONDITIONS - Real dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; - Real dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; - Real d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const; -#else // !BOUNDARY_CONDITIONS - Real dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; - Real dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; - Real d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 ) const; -#endif // BOUNDARY_CONDITIONS - - static inline int SymmetricIndex( const int& i1 , const int& i2 ); - static inline int SymmetricIndex( const int& i1 , const int& i2 , int& index ); - }; - - - } -} - - -#include "function_data.hpp" - -#endif // FUNCTION_DATA_INCLUDED diff --git a/plugins/probe/3rd/poisson4/function_data.hpp b/plugins/probe/3rd/poisson4/function_data.hpp deleted file mode 100644 index 8fa4cdc37e..0000000000 --- a/plugins/probe/3rd/poisson4/function_data.hpp +++ /dev/null @@ -1,423 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -////////////////// -// FunctionData // -////////////////// - -namespace pcl -{ - namespace poisson - { - - template - FunctionData::FunctionData(void) - { - dotTable=dDotTable=d2DotTable=NULL; - valueTables=dValueTables=NULL; - res=0; - } - - template - FunctionData::~FunctionData(void) - { - if(res) - { - if( dotTable) delete[] dotTable; - if( dDotTable) delete[] dDotTable; - if(d2DotTable) delete[] d2DotTable; - if( valueTables) delete[] valueTables; - if(dValueTables) delete[] dValueTables; - } - dotTable=dDotTable=d2DotTable=NULL; - valueTables=dValueTables=NULL; - res=0; - } - - template -#if BOUNDARY_CONDITIONS - void FunctionData::set( const int& maxDepth , const PPolynomial& F , const int& normalize , bool useDotRatios , bool reflectBoundary ) -#else // !BOUNDARY_CONDITIONS - void FunctionData::set(const int& maxDepth,const PPolynomial& F,const int& normalize , bool useDotRatios ) -#endif // BOUNDARY_CONDITIONS - { - this->normalize = normalize; - this->useDotRatios = useDotRatios; -#if BOUNDARY_CONDITIONS - this->reflectBoundary = reflectBoundary; -#endif // BOUNDARY_CONDITIONS - - depth = maxDepth; - res = BinaryNode::CumulativeCenterCount( depth ); - res2 = (1<<(depth+1))+1; - baseFunctions = new PPolynomial[res]; - // Scale the function so that it has: - // 0] Value 1 at 0 - // 1] Integral equal to 1 - // 2] Square integral equal to 1 - switch( normalize ) - { - case 2: - baseFunction=F/sqrt((F*F).integral(F.polys[0].start,F.polys[F.polyCount-1].start)); - break; - case 1: - baseFunction=F/F.integral(F.polys[0].start,F.polys[F.polyCount-1].start); - break; - default: - baseFunction=F/F(0); - } - dBaseFunction = baseFunction.derivative(); -#if BOUNDARY_CONDITIONS - leftBaseFunction = baseFunction + baseFunction.shift( -1 ); - rightBaseFunction = baseFunction + baseFunction.shift( 1 ); - dLeftBaseFunction = leftBaseFunction.derivative(); - dRightBaseFunction = rightBaseFunction.derivative(); -#endif // BOUNDARY_CONDITIONS - double c1,w1; - for( int i=0 ; i::CenterAndWidth( i , c1 , w1 ); -#if BOUNDARY_CONDITIONS - if( reflectBoundary ) - { - int d , off; - BinaryNode< double >::DepthAndOffset( i , d , off ); - if ( off==0 ) baseFunctions[i] = leftBaseFunction.scale( w1 ).shift( c1 ); - else if( off==((1< - void FunctionData::setDotTables( const int& flags ) - { - clearDotTables( flags ); - int size; - size = ( res*res + res )>>1; - if( flags & DOT_FLAG ) - { - dotTable = new Real[size]; - memset( dotTable , 0 , sizeof(Real)*size ); - } - if( flags & D_DOT_FLAG ) - { - dDotTable = new Real[size]; - memset( dDotTable , 0 , sizeof(Real)*size ); - } - if( flags & D2_DOT_FLAG ) - { - d2DotTable = new Real[size]; - memset( d2DotTable , 0 , sizeof(Real)*size ); - } - double t1 , t2; - t1 = baseFunction.polys[0].start; - t2 = baseFunction.polys[baseFunction.polyCount-1].start; - for( int i=0 ; i::CenterAndWidth( i , c1 , w1 ); -#if BOUNDARY_CONDITIONS - int d1 , d2 , off1 , off2; - BinaryNode< double >::DepthAndOffset( i , d1 , off1 ); - int boundary1 = 0; - if ( reflectBoundary && off1==0 ) boundary1 = -1; - else if( reflectBoundary && off1==( (1<::CenterAndWidth( j , c2 , w2 ); -#if BOUNDARY_CONDITIONS - BinaryNode< double >::DepthAndOffset( j , d2 , off2 ); - int boundary2 = 0; - if ( reflectBoundary && off2==0 ) boundary2 = -1; - else if( reflectBoundary && off2==( (1<1 ) start = 1; - if( end <0 ) end = 0; - if( end >1 ) end = 1; - } -#endif // BOUNDARY_CONDITIONS - - if( start< start1 ) start = start1; - if( end > end1 ) end = end1; - if( start>= end ) continue; - -#if BOUNDARY_CONDITIONS - Real dot = dotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); -#else // !BOUNDARY_CONDITIONS - Real dot = dotProduct( c1 , w1 , c2 , w2 ); -#endif // BOUNDARY_CONDITIONS - if( fabs(dot)<1e-15 ) continue; - if( flags & DOT_FLAG ) dotTable[idx]=dot; - if( useDotRatios ) - { -#if BOUNDARY_CONDITIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = -dDotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ) / dot; - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ) / dot; -#else // !BOUNDARY_CONDITIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = -dDotProduct(c1,w1,c2,w2)/dot; - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct(c1,w1,c2,w2)/dot; -#endif // BOUNDARY_CONDITIONS - } - else - { -#if BOUNDARY_CONDITIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = dDotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct( c1 , w1 , c2 , w2 , boundary1 , boundary2 ); -#else // !BOUNDARY_CONDTIONS - if( flags & D_DOT_FLAG ) dDotTable[idx] = dDotProduct(c1,w1,c2,w2); - if( flags & D2_DOT_FLAG ) d2DotTable[idx] = d2DotProduct(c1,w1,c2,w2); -#endif // BOUNDARY_CONDITIONS - } - } - } - } - template - void FunctionData::clearDotTables( const int& flags ) - { - if((flags & DOT_FLAG) && dotTable) - { - delete[] dotTable; - dotTable=NULL; - } - if((flags & D_DOT_FLAG) && dDotTable) - { - delete[] dDotTable; - dDotTable=NULL; - } - if((flags & D2_DOT_FLAG) && d2DotTable) - { - delete[] d2DotTable; - d2DotTable=NULL; - } - } - template - void FunctionData::setValueTables( const int& flags , const double& smooth ) - { - clearValueTables(); - if( flags & VALUE_FLAG ) valueTables = new Real[res*res2]; - if( flags & D_VALUE_FLAG ) dValueTables = new Real[res*res2]; - PPolynomial function; - PPolynomial dFunction; - for( int i=0 ; i0) - { - function=baseFunctions[i].MovingAverage(smooth); - dFunction=baseFunctions[i].derivative().MovingAverage(smooth); - } - else - { - function=baseFunctions[i]; - dFunction=baseFunctions[i].derivative(); - } - for( int j=0 ; j - void FunctionData::setValueTables(const int& flags,const double& valueSmooth,const double& normalSmooth){ - clearValueTables(); - if(flags & VALUE_FLAG){ valueTables=new Real[res*res2];} - if(flags & D_VALUE_FLAG){dValueTables=new Real[res*res2];} - PPolynomial function; - PPolynomial dFunction; - for(int i=0;i0) { function=baseFunctions[i].MovingAverage(valueSmooth);} - else { function=baseFunctions[i];} - if(normalSmooth>0) {dFunction=baseFunctions[i].derivative().MovingAverage(normalSmooth);} - else {dFunction=baseFunctions[i].derivative();} - - for(int j=0;j - void FunctionData::clearValueTables(void){ - if( valueTables){delete[] valueTables;} - if(dValueTables){delete[] dValueTables;} - valueTables=dValueTables=NULL; - } - -#if BOUNDARY_CONDITIONS - template - Real FunctionData::dotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const - { - const PPolynomial< Degree > *b1 , *b2; - if ( boundary1==-1 ) b1 = & leftBaseFunction; - else if( boundary1== 0 ) b1 = & baseFunction; - else if( boundary1== 1 ) b1 = &rightBaseFunction; - if ( boundary2==-1 ) b2 = & leftBaseFunction; - else if( boundary2== 0 ) b2 = & baseFunction; - else if( boundary2== 1 ) b2 = &rightBaseFunction; - double r=fabs( baseFunction.polys[0].start ); - switch( normalize ) - { - case 2: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/sqrt(width1*width2)); - case 1: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/(width1*width2)); - default: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1); - } - } - template - Real FunctionData::dDotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const - { - const PPolynomial< Degree-1 > *b1; - const PPolynomial< Degree > *b2; - if ( boundary1==-1 ) b1 = & dLeftBaseFunction; - else if( boundary1== 0 ) b1 = & dBaseFunction; - else if( boundary1== 1 ) b1 = &dRightBaseFunction; - if ( boundary2==-1 ) b2 = & leftBaseFunction; - else if( boundary2== 0 ) b2 = & baseFunction; - else if( boundary2== 1 ) b2 = & rightBaseFunction; - double r=fabs(baseFunction.polys[0].start); - switch(normalize){ - case 2: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/sqrt(width1*width2)); - case 1: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/(width1*width2)); - default: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)); - } - } - template - Real FunctionData::d2DotProduct( const double& center1 , const double& width1 , const double& center2 , const double& width2 , int boundary1 , int boundary2 ) const - { - const PPolynomial< Degree-1 > *b1 , *b2; - if ( boundary1==-1 ) b1 = & dLeftBaseFunction; - else if( boundary1== 0 ) b1 = & dBaseFunction; - else if( boundary1== 1 ) b1 = &dRightBaseFunction; - if ( boundary2==-1 ) b2 = & dLeftBaseFunction; - else if( boundary2== 0 ) b2 = & dBaseFunction; - else if( boundary2== 1 ) b2 = &dRightBaseFunction; - double r=fabs(baseFunction.polys[0].start); - switch( normalize ) - { - case 2: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/sqrt(width1*width2)); - case 1: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/(width1*width2)); - default: - return Real(((*b1)*b2->scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2); - } - } -#else // !BOUNDARY_CONDITIONS - template - Real FunctionData::dotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ - double r=fabs(baseFunction.polys[0].start); - switch( normalize ) - { - case 2: - return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/sqrt(width1*width2)); - case 1: - return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1/(width1*width2)); - default: - return Real((baseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)*width1); - } - } - template - Real FunctionData::dDotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ - double r=fabs(baseFunction.polys[0].start); - switch(normalize){ - case 2: - return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/sqrt(width1*width2)); - case 1: - return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/(width1*width2)); - default: - return Real((dBaseFunction*baseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)); - } - } - template - Real FunctionData::d2DotProduct(const double& center1,const double& width1,const double& center2,const double& width2) const{ - double r=fabs(baseFunction.polys[0].start); - switch(normalize){ - case 2: - return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/sqrt(width1*width2)); - case 1: - return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2/(width1*width2)); - default: - return Real((dBaseFunction*dBaseFunction.scale(width2/width1).shift((center2-center1)/width1)).integral(-2*r,2*r)/width2); - } - } -#endif // BOUNDARY_CONDITIONS - template - inline int FunctionData::SymmetricIndex( const int& i1 , const int& i2 ) - { - if( i1>i2 ) return ((i1*i1+i1)>>1)+i2; - else return ((i2*i2+i2)>>1)+i1; - } - template - inline int FunctionData::SymmetricIndex( const int& i1 , const int& i2 , int& index ) - { - if( i1>1)+i1; - return 1; - } - else{ - index = ((i1*i1+i1)>>1)+i2; - return 0; - } - } - } -} diff --git a/plugins/probe/3rd/poisson4/geometry.cpp b/plugins/probe/3rd/poisson4/geometry.cpp deleted file mode 100644 index a2c6ebeb8a..0000000000 --- a/plugins/probe/3rd/poisson4/geometry.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -#include "poisson4/geometry.h" - -/////////////////// -// CoredMeshData // -/////////////////// -namespace pcl -{ - namespace poisson - { - - TriangulationEdge::TriangulationEdge(void){pIndex[0]=pIndex[1]=tIndex[0]=tIndex[1]=-1;} - TriangulationTriangle::TriangulationTriangle(void){eIndex[0]=eIndex[1]=eIndex[2]=-1;} - - ///////////////////////// - // CoredVectorMeshData // - ///////////////////////// - CoredVectorMeshData::CoredVectorMeshData( void ) { oocPointIndex = polygonIndex = 0; } - void CoredVectorMeshData::resetIterator ( void ) { oocPointIndex = polygonIndex = 0; } - int CoredVectorMeshData::addOutOfCorePoint(const Point3D& p){ - oocPoints.push_back(p); - return int(oocPoints.size())-1; - } - int CoredVectorMeshData::addPolygon( const std::vector< CoredVertexIndex >& vertices ) - { - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i& p){ - if(oocPointIndex& vertices ) - { - if( polygonIndex& polygon = polygons[ polygonIndex++ ]; - vertices.resize( polygon.size() ); - for( int i=0 ; i& vertices ) - { - std::vector< int > polygon( vertices.size() ); - for( int i=0 ; i& vertices ) - { - if( polygonIndex& polygon = polygons[ polygonIndex++ ]; - vertices.resize( polygon.size() ); - for( int i=0 ; i -#include -#include -extern "C" { -#include "stdlib.h" -} - - -namespace pcl { -namespace poisson { - -template Real Random(void); - -template struct Point3D { - Real coords[3]; - Point3D(void) { coords[0] = coords[1] = coords[2] = Real(0); } - inline Real& operator[](int i) { return coords[i]; } - inline const Real& operator[](int i) const { return coords[i]; } - inline Point3D& operator+=(Point3D p) { - coords[0] += p.coords[0], coords[1] += p.coords[1], coords[2] += p.coords[2]; - return *this; - } - inline Point3D& operator-=(Point3D p) { - coords[0] -= p.coords[0], coords[1] -= p.coords[1], coords[2] -= p.coords[2]; - return *this; - } - inline Point3D& operator*=(Real r) { - coords[0] *= r, coords[1] *= r, coords[2] *= r; - return *this; - } - inline Point3D& operator/=(Real r) { - coords[0] /= r, coords[1] /= r, coords[2] /= r; - return *this; - } - inline Point3D operator+(Point3D p) const { - Point3D q; - q.coords[0] = coords[0] + p.coords[0], q.coords[1] = coords[1] + p.coords[1], - q.coords[2] = coords[2] + p.coords[2]; - return q; - } - inline Point3D operator-(Point3D p) const { - Point3D q; - q.coords[0] = coords[0] - p.coords[0], q.coords[1] = coords[1] - p.coords[1], - q.coords[2] = coords[2] - p.coords[2]; - return q; - } - inline Point3D operator*(Real r) const { - Point3D q; - q.coords[0] = coords[0] * r, q.coords[1] = coords[1] * r, q.coords[2] = coords[2] * r; - return q; - } - inline Point3D operator/(Real r) const { return (*this) * (Real(1.) / r); } -}; - -template Point3D RandomBallPoint(void); - -template Point3D RandomSpherePoint(void); - -template double Length(const Point3D& p); - -template double SquareLength(const Point3D& p); - -template double Distance(const Point3D& p1, const Point3D& p2); - -template double SquareDistance(const Point3D& p1, const Point3D& p2); - -template void CrossProduct(const Point3D& p1, const Point3D& p2, Point3D& p); - -class Edge { -public: - double p[2][2]; - double Length(void) const { - double d[2]; - d[0] = p[0][0] - p[1][0]; - d[1] = p[0][1] - p[1][1]; - - return sqrt(d[0] * d[0] + d[1] * d[1]); - } -}; -class Triangle { -public: - double p[3][3]; - double Area(void) const { - double v1[3], v2[3], v[3]; - for (int d = 0; d < 3; d++) { - v1[d] = p[1][d] - p[0][d]; - v2[d] = p[2][d] - p[0][d]; - } - v[0] = v1[1] * v2[2] - v1[2] * v2[1]; - v[1] = -v1[0] * v2[2] + v1[2] * v2[0]; - v[2] = v1[0] * v2[1] - v1[1] * v2[0]; - return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) / 2; - } - double AspectRatio(void) const { - double d = 0; - int i, j; - for (i = 0; i < 3; i++) { - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) { - d += (p[(i + 1) % 3][j] - p[i][j]) * (p[(i + 1) % 3][j] - p[i][j]); - } - } - return Area() / d; - } -}; -class CoredPointIndex { -public: - int index; - char inCore; - - int operator==(const CoredPointIndex& cpi) const { return (index == cpi.index) && (inCore == cpi.inCore); }; - int operator!=(const CoredPointIndex& cpi) const { return (index != cpi.index) || (inCore != cpi.inCore); }; -}; -class EdgeIndex { -public: - int idx[2]; -}; -class CoredEdgeIndex { -public: - CoredPointIndex idx[2]; -}; -class TriangleIndex { -public: - int idx[3]; -}; - -class TriangulationEdge { -public: - TriangulationEdge(void); - int pIndex[2]; - int tIndex[2]; -}; - -class TriangulationTriangle { -public: - TriangulationTriangle(void); - int eIndex[3]; -}; - -template class Triangulation { -public: - std::vector> points; - std::vector edges; - std::vector triangles; - - int factor(int tIndex, int& p1, int& p2, int& p3); - double area(void); - double area(int tIndex); - double area(int p1, int p2, int p3); - int flipMinimize(int eIndex); - int addTriangle(int p1, int p2, int p3); - -protected: - std::unordered_map edgeMap; - static long long EdgeIndex(int p1, int p2); - double area(const Triangle& t); -}; - - -template -void EdgeCollapse(const Real& edgeRatio, std::vector& triangles, std::vector>& positions, - std::vector>* normals); -template -void TriangleCollapse(const Real& edgeRatio, std::vector& triangles, - std::vector>& positions, std::vector>* normals); - -struct CoredVertexIndex { - int idx; - bool inCore; -}; -class CoredMeshData { -public: - std::vector> inCorePoints; - virtual void resetIterator(void) = 0; - - virtual int addOutOfCorePoint(const Point3D& p) = 0; - virtual int addPolygon(const std::vector& vertices) = 0; - - virtual int nextOutOfCorePoint(Point3D& p) = 0; - virtual int nextPolygon(std::vector& vertices) = 0; - - virtual int outOfCorePointCount(void) = 0; - virtual int polygonCount(void) = 0; -}; -// Stores the iso-span of each vertex, rather than it's position -class CoredMeshData2 { -public: - struct Vertex { - Point3D start, end; - float value; - Vertex(void) { ; } - Vertex(Point3D s, Point3D e, float v) { start = s, end = e, value = v; } - Vertex(Point3D s, Point3D e, Point3D p) { - start = s, end = e; - // < p , e-s > = < s + v*(e-s) , e-s > - // < p , e-s > - < s , e-s > = v || e-s || ^2 - // v = < p-s , e-s > / || e-s ||^2 - Point3D p1 = p - s, p2 = e - s; - value = (p1[0] * p2[0] + p1[1] * p2[1] + p1[2] * p2[2]) / (p2[0] * p2[0] + p2[1] * p2[1] + p2[2] * p2[2]); - } - }; - std::vector inCorePoints; - virtual void resetIterator(void) = 0; - - virtual int addOutOfCorePoint(const Vertex& v) = 0; - virtual int addPolygon(const std::vector& vertices) = 0; - - virtual int nextOutOfCorePoint(Vertex& v) = 0; - virtual int nextPolygon(std::vector& vertices) = 0; - - virtual int outOfCorePointCount(void) = 0; - virtual int polygonCount(void) = 0; -}; - -class CoredVectorMeshData : public CoredMeshData { - std::vector> oocPoints; - std::vector> polygons; - int polygonIndex; - int oocPointIndex; - -public: - CoredVectorMeshData(void); - - void resetIterator(void); - - int addOutOfCorePoint(const Point3D& p); - int addPolygon(const std::vector& vertices); - - int nextOutOfCorePoint(Point3D& p); - int nextPolygon(std::vector& vertices); - - int outOfCorePointCount(void); - int polygonCount(void); -}; -class CoredVectorMeshData2 : public CoredMeshData2 { - std::vector oocPoints; - std::vector> polygons; - int polygonIndex; - int oocPointIndex; - -public: - CoredVectorMeshData2(void); - - void resetIterator(void); - - int addOutOfCorePoint(const CoredMeshData2::Vertex& v); - int addPolygon(const std::vector& vertices); - - int nextOutOfCorePoint(CoredMeshData2::Vertex& v); - int nextPolygon(std::vector& vertices); - - int outOfCorePointCount(void); - int polygonCount(void); -}; -class CoredFileMeshData : public CoredMeshData { - FILE *oocPointFile, *polygonFile; - int oocPoints, polygons; - -public: - CoredFileMeshData(void); - ~CoredFileMeshData(void); - - void resetIterator(void); - - int addOutOfCorePoint(const Point3D& p); - int addPolygon(const std::vector& vertices); - - int nextOutOfCorePoint(Point3D& p); - int nextPolygon(std::vector& vertices); - - int outOfCorePointCount(void); - int polygonCount(void); -}; -class CoredFileMeshData2 : public CoredMeshData2 { - FILE *oocPointFile, *polygonFile; - int oocPoints, polygons; - -public: - CoredFileMeshData2(void); - ~CoredFileMeshData2(void); - - void resetIterator(void); - - int addOutOfCorePoint(const CoredMeshData2::Vertex& v); - int addPolygon(const std::vector& vertices); - - int nextOutOfCorePoint(CoredMeshData2::Vertex& v); - int nextPolygon(std::vector& vertices); - - int outOfCorePointCount(void); - int polygonCount(void); -}; - - -template Real Random(void) { return Real(rand()) / RAND_MAX; } - -template Point3D RandomBallPoint(void) { - Point3D p; - while (1) { - p.coords[0] = Real(1.0 - 2.0 * Random()); - p.coords[1] = Real(1.0 - 2.0 * Random()); - p.coords[2] = Real(1.0 - 2.0 * Random()); - double l = SquareLength(p); - if (l <= 1) { - return p; - } - } -} -template Point3D RandomSpherePoint(void) { - Point3D p = RandomBallPoint(); - Real l = Real(Length(p)); - p.coords[0] /= l; - p.coords[1] /= l; - p.coords[2] /= l; - return p; -} - -template double SquareLength(const Point3D& p) { - return p.coords[0] * p.coords[0] + p.coords[1] * p.coords[1] + p.coords[2] * p.coords[2]; -} - -template double Length(const Point3D& p) { return sqrt(SquareLength(p)); } - -template double SquareDistance(const Point3D& p1, const Point3D& p2) { - return (p1.coords[0] - p2.coords[0]) * (p1.coords[0] - p2.coords[0]) + - (p1.coords[1] - p2.coords[1]) * (p1.coords[1] - p2.coords[1]) + - (p1.coords[2] - p2.coords[2]) * (p1.coords[2] - p2.coords[2]); -} - -template double Distance(const Point3D& p1, const Point3D& p2) { - return sqrt(SquareDistance(p1, p2)); -} - -template void CrossProduct(const Point3D& p1, const Point3D& p2, Point3D& p) { - p.coords[0] = p1.coords[1] * p2.coords[2] - p1.coords[2] * p2.coords[1]; - p.coords[1] = -p1.coords[0] * p2.coords[2] + p1.coords[2] * p2.coords[0]; - p.coords[2] = p1.coords[0] * p2.coords[1] - p1.coords[1] * p2.coords[0]; -} -template -void EdgeCollapse(const Real& edgeRatio, std::vector& triangles, std::vector>& positions, - std::vector>* normals) { - int i, j, *remapTable, *pointCount, idx[3]; - Point3D p[3], q[2], c; - double d[3], a; - double Ratio = 12.0 / sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable = new int[positions.size()]; - pointCount = new int[positions.size()]; - for (i = 0; i < int(positions.size()); i++) { - remapTable[i] = i; - pointCount[i] = 1; - } - for (i = int(triangles.size() - 1); i >= 0; i--) { - for (j = 0; j < 3; j++) { - idx[j] = triangles[i].idx[j]; - while (remapTable[idx[j]] < idx[j]) { - idx[j] = remapTable[idx[j]]; - } - } - if (idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2]) { - triangles[i] = triangles[triangles.size() - 1]; - triangles.pop_back(); - continue; - } - for (j = 0; j < 3; j++) { - p[j].coords[0] = positions[idx[j]].coords[0] / pointCount[idx[j]]; - p[j].coords[1] = positions[idx[j]].coords[1] / pointCount[idx[j]]; - p[j].coords[2] = positions[idx[j]].coords[2] / pointCount[idx[j]]; - } - for (j = 0; j < 3; j++) { - q[0].coords[j] = p[1].coords[j] - p[0].coords[j]; - q[1].coords[j] = p[2].coords[j] - p[0].coords[j]; - d[j] = SquareDistance(p[j], p[(j + 1) % 3]); - } - CrossProduct(q[0], q[1], c); - a = Length(c) / 2; - - if ((d[0] + d[1] + d[2]) * edgeRatio > a * Ratio) { - // Find the smallest edge - j = 0; - if (d[1] < d[j]) { - j = 1; - } - if (d[2] < d[j]) { - j = 2; - } - - int idx1, idx2; - if (idx[j] < idx[(j + 1) % 3]) { - idx1 = idx[j]; - idx2 = idx[(j + 1) % 3]; - } else { - idx2 = idx[j]; - idx1 = idx[(j + 1) % 3]; - } - positions[idx1].coords[0] += positions[idx2].coords[0]; - positions[idx1].coords[1] += positions[idx2].coords[1]; - positions[idx1].coords[2] += positions[idx2].coords[2]; - if (normals) { - (*normals)[idx1].coords[0] += (*normals)[idx2].coords[0]; - (*normals)[idx1].coords[1] += (*normals)[idx2].coords[1]; - (*normals)[idx1].coords[2] += (*normals)[idx2].coords[2]; - } - pointCount[idx1] += pointCount[idx2]; - remapTable[idx2] = idx1; - triangles[i] = triangles[triangles.size() - 1]; - triangles.pop_back(); - } - } - int pCount = 0; - for (i = 0; i < int(positions.size()); i++) { - for (j = 0; j < 3; j++) { - positions[i].coords[j] /= pointCount[i]; - } - if (normals) { - Real l = Real(Length((*normals)[i])); - for (j = 0; j < 3; j++) { - (*normals)[i].coords[j] /= l; - } - } - if (remapTable[i] == i) { // If vertex i is being used - positions[pCount] = positions[i]; - if (normals) { - (*normals)[pCount] = (*normals)[i]; - } - pointCount[i] = pCount; - pCount++; - } - } - positions.resize(pCount); - for (i = int(triangles.size() - 1); i >= 0; i--) { - for (j = 0; j < 3; j++) { - idx[j] = triangles[i].idx[j]; - while (remapTable[idx[j]] < idx[j]) { - idx[j] = remapTable[idx[j]]; - } - triangles[i].idx[j] = pointCount[idx[j]]; - } - if (idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2]) { - triangles[i] = triangles[triangles.size() - 1]; - triangles.pop_back(); - } - } - - delete[] pointCount; - delete[] remapTable; -} -template -void TriangleCollapse(const Real& edgeRatio, std::vector& triangles, - std::vector>& positions, std::vector>* normals) { - int i, j, *remapTable, *pointCount, idx[3]; - Point3D p[3], q[2], c; - double d[3], a; - double Ratio = 12.0 / sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable = new int[positions.size()]; - pointCount = new int[positions.size()]; - for (i = 0; i < int(positions.size()); i++) { - remapTable[i] = i; - pointCount[i] = 1; - } - for (i = int(triangles.size() - 1); i >= 0; i--) { - for (j = 0; j < 3; j++) { - idx[j] = triangles[i].idx[j]; - while (remapTable[idx[j]] < idx[j]) { - idx[j] = remapTable[idx[j]]; - } - } - if (idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2]) { - triangles[i] = triangles[triangles.size() - 1]; - triangles.pop_back(); - continue; - } - for (j = 0; j < 3; j++) { - p[j].coords[0] = positions[idx[j]].coords[0] / pointCount[idx[j]]; - p[j].coords[1] = positions[idx[j]].coords[1] / pointCount[idx[j]]; - p[j].coords[2] = positions[idx[j]].coords[2] / pointCount[idx[j]]; - } - for (j = 0; j < 3; j++) { - q[0].coords[j] = p[1].coords[j] - p[0].coords[j]; - q[1].coords[j] = p[2].coords[j] - p[0].coords[j]; - d[j] = SquareDistance(p[j], p[(j + 1) % 3]); - } - CrossProduct(q[0], q[1], c); - a = Length(c) / 2; - - if ((d[0] + d[1] + d[2]) * edgeRatio > a * Ratio) { - // Find the smallest edge - j = 0; - if (d[1] < d[j]) { - j = 1; - } - if (d[2] < d[j]) { - j = 2; - } - - int idx1, idx2, idx3; - if (idx[0] < idx[1]) { - if (idx[0] < idx[2]) { - idx1 = idx[0]; - idx2 = idx[2]; - idx3 = idx[1]; - } else { - idx1 = idx[2]; - idx2 = idx[0]; - idx3 = idx[1]; - } - } else { - if (idx[1] < idx[2]) { - idx1 = idx[1]; - idx2 = idx[2]; - idx3 = idx[0]; - } else { - idx1 = idx[2]; - idx2 = idx[1]; - idx3 = idx[0]; - } - } - positions[idx1].coords[0] += positions[idx2].coords[0] + positions[idx3].coords[0]; - positions[idx1].coords[1] += positions[idx2].coords[1] + positions[idx3].coords[1]; - positions[idx1].coords[2] += positions[idx2].coords[2] + positions[idx3].coords[2]; - if (normals) { - (*normals)[idx1].coords[0] += (*normals)[idx2].coords[0] + (*normals)[idx3].coords[0]; - (*normals)[idx1].coords[1] += (*normals)[idx2].coords[1] + (*normals)[idx3].coords[1]; - (*normals)[idx1].coords[2] += (*normals)[idx2].coords[2] + (*normals)[idx3].coords[2]; - } - pointCount[idx1] += pointCount[idx2] + pointCount[idx3]; - remapTable[idx2] = idx1; - remapTable[idx3] = idx1; - triangles[i] = triangles[triangles.size() - 1]; - triangles.pop_back(); - } - } - int pCount = 0; - for (i = 0; i < int(positions.size()); i++) { - for (j = 0; j < 3; j++) { - positions[i].coords[j] /= pointCount[i]; - } - if (normals) { - Real l = Real(Length((*normals)[i])); - for (j = 0; j < 3; j++) { - (*normals)[i].coords[j] /= l; - } - } - if (remapTable[i] == i) { // If vertex i is being used - positions[pCount] = positions[i]; - if (normals) { - (*normals)[pCount] = (*normals)[i]; - } - pointCount[i] = pCount; - pCount++; - } - } - positions.resize(pCount); - for (i = int(triangles.size() - 1); i >= 0; i--) { - for (j = 0; j < 3; j++) { - idx[j] = triangles[i].idx[j]; - while (remapTable[idx[j]] < idx[j]) { - idx[j] = remapTable[idx[j]]; - } - triangles[i].idx[j] = pointCount[idx[j]]; - } - if (idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2]) { - triangles[i] = triangles[triangles.size() - 1]; - triangles.pop_back(); - } - } - delete[] pointCount; - delete[] remapTable; -} - -/////////////////// -// Triangulation // -/////////////////// -template long long Triangulation::EdgeIndex(int p1, int p2) { - if (p1 > p2) { - return ((long long)(p1) << 32) | ((long long)(p2)); - } else { - return ((long long)(p2) << 32) | ((long long)(p1)); - } -} - -template int Triangulation::factor(int tIndex, int& p1, int& p2, int& p3) { - if (triangles[tIndex].eIndex[0] < 0 || triangles[tIndex].eIndex[1] < 0 || triangles[tIndex].eIndex[2] < 0) { - return 0; - } - if (edges[triangles[tIndex].eIndex[0]].tIndex[0] == tIndex) { - p1 = edges[triangles[tIndex].eIndex[0]].pIndex[0]; - } else { - p1 = edges[triangles[tIndex].eIndex[0]].pIndex[1]; - } - if (edges[triangles[tIndex].eIndex[1]].tIndex[0] == tIndex) { - p2 = edges[triangles[tIndex].eIndex[1]].pIndex[0]; - } else { - p2 = edges[triangles[tIndex].eIndex[1]].pIndex[1]; - } - if (edges[triangles[tIndex].eIndex[2]].tIndex[0] == tIndex) { - p3 = edges[triangles[tIndex].eIndex[2]].pIndex[0]; - } else { - p3 = edges[triangles[tIndex].eIndex[2]].pIndex[1]; - } - return 1; -} -template double Triangulation::area(int p1, int p2, int p3) { - Point3D q1, q2, q; - for (int i = 0; i < 3; i++) { - q1.coords[i] = points[p2].coords[i] - points[p1].coords[i]; - q2.coords[i] = points[p3].coords[i] - points[p1].coords[i]; - } - CrossProduct(q1, q2, q); - return Length(q); -} -template double Triangulation::area(int tIndex) { - int p1, p2, p3; - factor(tIndex, p1, p2, p3); - return area(p1, p2, p3); -} -template double Triangulation::area(void) { - double a = 0; - for (int i = 0; i < int(triangles.size()); i++) { - a += area(i); - } - return a; -} -template int Triangulation::addTriangle(int p1, int p2, int p3) { - int tIdx, eIdx, p[3]; - p[0] = p1; - p[1] = p2; - p[2] = p3; - triangles.push_back(TriangulationTriangle()); - tIdx = int(triangles.size()) - 1; - - for (int i = 0; i < 3; i++) { - long long e = EdgeIndex(p[i], p[(i + 1) % 3]); - if (edgeMap.count(e) == 0) { - TriangulationEdge edge; - edge.pIndex[0] = p[i]; - edge.pIndex[1] = p[(i + 1) % 3]; - edges.push_back(edge); - eIdx = int(edges.size()) - 1; - edgeMap[e] = eIdx; - edges[eIdx].tIndex[0] = tIdx; - } else { - eIdx = edgeMap[e]; - if (edges[eIdx].pIndex[0] == p[i]) { - if (edges[eIdx].tIndex[0] < 0) { - edges[eIdx].tIndex[0] = tIdx; - } else { - PCL_DEBUG("Edge Triangle in use 1\n"); - return 0; - } - } else { - if (edges[eIdx].tIndex[1] < 0) { - edges[eIdx].tIndex[1] = tIdx; - } else { - PCL_DEBUG("Edge Triangle in use 2\n"); - return 0; - } - } - } - triangles[tIdx].eIndex[i] = eIdx; - } - return tIdx; -} -template int Triangulation::flipMinimize(int eIndex) { - double oldArea, newArea; - int oldP[3], oldQ[3], newP[3], newQ[3]; - TriangulationEdge newEdge; - - if (edges[eIndex].tIndex[0] < 0 || edges[eIndex].tIndex[1] < 0) { - return 0; - } - - if (!factor(edges[eIndex].tIndex[0], oldP[0], oldP[1], oldP[2])) { - return 0; - } - if (!factor(edges[eIndex].tIndex[1], oldQ[0], oldQ[1], oldQ[2])) { - return 0; - } - - oldArea = area(oldP[0], oldP[1], oldP[2]) + area(oldQ[0], oldQ[1], oldQ[2]); - int idxP, idxQ; - for (idxP = 0; idxP < 3; idxP++) { - int i; - for (i = 0; i < 3; i++) { - if (oldP[idxP] == oldQ[i]) { - break; - } - } - if (i == 3) { - break; - } - } - for (idxQ = 0; idxQ < 3; idxQ++) { - int i; - for (i = 0; i < 3; i++) { - if (oldP[i] == oldQ[idxQ]) { - break; - } - } - if (i == 3) { - break; - } - } - if (idxP == 3 || idxQ == 3) { - return 0; - } - newP[0] = oldP[idxP]; - newP[1] = oldP[(idxP + 1) % 3]; - newP[2] = oldQ[idxQ]; - newQ[0] = oldQ[idxQ]; - newQ[1] = oldP[(idxP + 2) % 3]; - newQ[2] = oldP[idxP]; - - newArea = area(newP[0], newP[1], newP[2]) + area(newQ[0], newQ[1], newQ[2]); - if (oldArea <= newArea) { - return 0; - } - - // Remove the entry in the hash_table for the old edge - edgeMap.erase(EdgeIndex(edges[eIndex].pIndex[0], edges[eIndex].pIndex[1])); - // Set the new edge so that the zero-side is newQ - edges[eIndex].pIndex[0] = newP[0]; - edges[eIndex].pIndex[1] = newQ[0]; - // Insert the entry into the hash_table for the new edge - edgeMap[EdgeIndex(newP[0], newQ[0])] = eIndex; - // Update the triangle information - for (int i = 0; i < 3; i++) { - int idx; - idx = edgeMap[EdgeIndex(newQ[i], newQ[(i + 1) % 3])]; - triangles[edges[eIndex].tIndex[0]].eIndex[i] = idx; - if (idx != eIndex) { - if (edges[idx].tIndex[0] == edges[eIndex].tIndex[1]) { - edges[idx].tIndex[0] = edges[eIndex].tIndex[0]; - } - if (edges[idx].tIndex[1] == edges[eIndex].tIndex[1]) { - edges[idx].tIndex[1] = edges[eIndex].tIndex[0]; - } - } - - idx = edgeMap[EdgeIndex(newP[i], newP[(i + 1) % 3])]; - triangles[edges[eIndex].tIndex[1]].eIndex[i] = idx; - if (idx != eIndex) { - if (edges[idx].tIndex[0] == edges[eIndex].tIndex[0]) { - edges[idx].tIndex[0] = edges[eIndex].tIndex[1]; - } - if (edges[idx].tIndex[1] == edges[eIndex].tIndex[0]) { - edges[idx].tIndex[1] = edges[eIndex].tIndex[1]; - } - } - } - return 1; -} - - -} // namespace poisson -} // namespace pcl - - -#endif // GEOMETRY_INCLUDED diff --git a/plugins/probe/3rd/poisson4/geometry.hpp b/plugins/probe/3rd/poisson4/geometry.hpp deleted file mode 100644 index 40589b5e84..0000000000 --- a/plugins/probe/3rd/poisson4/geometry.hpp +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - - -namespace pcl -{ - namespace poisson - { - - - template - Real Random(void){return Real(rand())/RAND_MAX;} - - template - Point3D RandomBallPoint(void){ - Point3D p; - while(1){ - p.coords[0]=Real(1.0-2.0*Random()); - p.coords[1]=Real(1.0-2.0*Random()); - p.coords[2]=Real(1.0-2.0*Random()); - double l=SquareLength(p); - if(l<=1){return p;} - } - } - template - Point3D RandomSpherePoint(void){ - Point3D p=RandomBallPoint(); - Real l=Real(Length(p)); - p.coords[0]/=l; - p.coords[1]/=l; - p.coords[2]/=l; - return p; - } - - template - double SquareLength(const Point3D& p){return p.coords[0]*p.coords[0]+p.coords[1]*p.coords[1]+p.coords[2]*p.coords[2];} - - template - double Length(const Point3D& p){return sqrt(SquareLength(p));} - - template - double SquareDistance(const Point3D& p1,const Point3D& p2){ - return (p1.coords[0]-p2.coords[0])*(p1.coords[0]-p2.coords[0])+(p1.coords[1]-p2.coords[1])*(p1.coords[1]-p2.coords[1])+(p1.coords[2]-p2.coords[2])*(p1.coords[2]-p2.coords[2]); - } - - template - double Distance(const Point3D& p1,const Point3D& p2){return sqrt(SquareDistance(p1,p2));} - - template - void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p){ - p.coords[0]= p1.coords[1]*p2.coords[2]-p1.coords[2]*p2.coords[1]; - p.coords[1]=-p1.coords[0]*p2.coords[2]+p1.coords[2]*p2.coords[0]; - p.coords[2]= p1.coords[0]*p2.coords[1]-p1.coords[1]*p2.coords[0]; - } - template - void EdgeCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ - int i,j,*remapTable,*pointCount,idx[3]; - Point3D p[3],q[2],c; - double d[3],a; - double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable=new int[positions.size()]; - pointCount=new int[positions.size()]; - for(i=0;i=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] a*Ratio){ - // Find the smallest edge - j=0; - if(d[1]=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] - void TriangleCollapse(const Real& edgeRatio,std::vector& triangles,std::vector< Point3D >& positions,std::vector< Point3D >* normals){ - int i,j,*remapTable,*pointCount,idx[3]; - Point3D p[3],q[2],c; - double d[3],a; - double Ratio=12.0/sqrt(3.0); // (Sum of Squares Length / Area) for and equilateral triangle - - remapTable=new int[positions.size()]; - pointCount=new int[positions.size()]; - for(i=0;i=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] a*Ratio){ - // Find the smallest edge - j=0; - if(d[1]=0;i--){ - for(j=0;j<3;j++){ - idx[j]=triangles[i].idx[j]; - while(remapTable[idx[j]] - long long Triangulation::EdgeIndex( int p1 , int p2 ) - { - if(p1>p2) {return ((long long)(p1)<<32) | ((long long)(p2));} - else {return ((long long)(p2)<<32) | ((long long)(p1));} - } - - template - int Triangulation::factor(int tIndex,int& p1,int& p2,int & p3){ - if(triangles[tIndex].eIndex[0]<0 || triangles[tIndex].eIndex[1]<0 || triangles[tIndex].eIndex[2]<0){return 0;} - if(edges[triangles[tIndex].eIndex[0]].tIndex[0]==tIndex){p1=edges[triangles[tIndex].eIndex[0]].pIndex[0];} - else {p1=edges[triangles[tIndex].eIndex[0]].pIndex[1];} - if(edges[triangles[tIndex].eIndex[1]].tIndex[0]==tIndex){p2=edges[triangles[tIndex].eIndex[1]].pIndex[0];} - else {p2=edges[triangles[tIndex].eIndex[1]].pIndex[1];} - if(edges[triangles[tIndex].eIndex[2]].tIndex[0]==tIndex){p3=edges[triangles[tIndex].eIndex[2]].pIndex[0];} - else {p3=edges[triangles[tIndex].eIndex[2]].pIndex[1];} - return 1; - } - template - double Triangulation::area(int p1,int p2,int p3){ - Point3D q1,q2,q; - for(int i=0;i<3;i++){ - q1.coords[i]=points[p2].coords[i]-points[p1].coords[i]; - q2.coords[i]=points[p3].coords[i]-points[p1].coords[i]; - } - CrossProduct(q1,q2,q); - return Length(q); - } - template - double Triangulation::area(int tIndex){ - int p1,p2,p3; - factor(tIndex,p1,p2,p3); - return area(p1,p2,p3); - } - template - double Triangulation::area(void){ - double a=0; - for(int i=0;i - int Triangulation::addTriangle(int p1,int p2,int p3){ - int tIdx,eIdx,p[3]; - p[0]=p1; - p[1]=p2; - p[2]=p3; - triangles.push_back(TriangulationTriangle()); - tIdx=int(triangles.size())-1; - - for(int i=0;i<3;i++) - { - long long e = EdgeIndex(p[i],p[(i+1)%3]); - if(edgeMap.count(e) == 0) - { - TriangulationEdge edge; - edge.pIndex[0]=p[i]; - edge.pIndex[1]=p[(i+1)%3]; - edges.push_back(edge); - eIdx=int(edges.size())-1; - edgeMap[e]=eIdx; - edges[eIdx].tIndex[0]=tIdx; - } - else{ - eIdx=edgeMap[e]; - if(edges[eIdx].pIndex[0]==p[i]){ - if(edges[eIdx].tIndex[0]<0){edges[eIdx].tIndex[0]=tIdx;} - else{PCL_DEBUG("Edge Triangle in use 1\n");return 0;} - } - else{ - if(edges[eIdx].tIndex[1]<0){edges[eIdx].tIndex[1]=tIdx;} - else{PCL_DEBUG("Edge Triangle in use 2\n");return 0;} - } - - } - triangles[tIdx].eIndex[i]=eIdx; - } - return tIdx; - } - template - int Triangulation::flipMinimize(int eIndex){ - double oldArea,newArea; - int oldP[3],oldQ[3],newP[3],newQ[3]; - TriangulationEdge newEdge; - - if(edges[eIndex].tIndex[0]<0 || edges[eIndex].tIndex[1]<0){return 0;} - - if(!factor(edges[eIndex].tIndex[0],oldP[0],oldP[1],oldP[2])){return 0;} - if(!factor(edges[eIndex].tIndex[1],oldQ[0],oldQ[1],oldQ[2])){return 0;} - - oldArea=area(oldP[0],oldP[1],oldP[2])+area(oldQ[0],oldQ[1],oldQ[2]); - int idxP,idxQ; - for(idxP=0;idxP<3;idxP++){ - int i; - for(i=0;i<3;i++){if(oldP[idxP]==oldQ[i]){break;}} - if(i==3){break;} - } - for(idxQ=0;idxQ<3;idxQ++){ - int i; - for(i=0;i<3;i++){if(oldP[i]==oldQ[idxQ]){break;}} - if(i==3){break;} - } - if(idxP==3 || idxQ==3){return 0;} - newP[0]=oldP[idxP]; - newP[1]=oldP[(idxP+1)%3]; - newP[2]=oldQ[idxQ]; - newQ[0]=oldQ[idxQ]; - newQ[1]=oldP[(idxP+2)%3]; - newQ[2]=oldP[idxP]; - - newArea=area(newP[0],newP[1],newP[2])+area(newQ[0],newQ[1],newQ[2]); - if(oldArea<=newArea){return 0;} - - // Remove the entry in the hash_table for the old edge - edgeMap.erase(EdgeIndex(edges[eIndex].pIndex[0],edges[eIndex].pIndex[1])); - // Set the new edge so that the zero-side is newQ - edges[eIndex].pIndex[0]=newP[0]; - edges[eIndex].pIndex[1]=newQ[0]; - // Insert the entry into the hash_table for the new edge - edgeMap[EdgeIndex(newP[0],newQ[0])]=eIndex; - // Update the triangle information - for(int i=0;i<3;i++){ - int idx; - idx=edgeMap[EdgeIndex(newQ[i],newQ[(i+1)%3])]; - triangles[edges[eIndex].tIndex[0]].eIndex[i]=idx; - if(idx!=eIndex){ - if(edges[idx].tIndex[0]==edges[eIndex].tIndex[1]){edges[idx].tIndex[0]=edges[eIndex].tIndex[0];} - if(edges[idx].tIndex[1]==edges[eIndex].tIndex[1]){edges[idx].tIndex[1]=edges[eIndex].tIndex[0];} - } - - idx=edgeMap[EdgeIndex(newP[i],newP[(i+1)%3])]; - triangles[edges[eIndex].tIndex[1]].eIndex[i]=idx; - if(idx!=eIndex){ - if(edges[idx].tIndex[0]==edges[eIndex].tIndex[0]){edges[idx].tIndex[0]=edges[eIndex].tIndex[1];} - if(edges[idx].tIndex[1]==edges[eIndex].tIndex[0]){edges[idx].tIndex[1]=edges[eIndex].tIndex[1];} - } - } - return 1; - } - - } -} diff --git a/plugins/probe/3rd/poisson4/marching_cubes_poisson.cpp b/plugins/probe/3rd/poisson4/marching_cubes_poisson.cpp deleted file mode 100644 index f75d7b2d99..0000000000 --- a/plugins/probe/3rd/poisson4/marching_cubes_poisson.cpp +++ /dev/null @@ -1,996 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include "poisson4/marching_cubes_poisson.h" - -//////////// -// Square // -//////////// - -namespace pcl -{ - namespace poisson - { - - int Square::AntipodalCornerIndex(int idx){ - int x,y; - FactorCornerIndex(idx,x,y); - return CornerIndex( (x+1)%2 , (y+1)%2 ); - } - int Square::CornerIndex(int x,int y){return (y<<1)|x;} - void Square::FactorCornerIndex(int idx,int& x,int& y){ - x=(idx>>0)%2; - y=(idx>>1)%2; - } - int Square::EdgeIndex(int orientation,int i){ - switch(orientation){ - case 0: // x - if(!i) {return 0;} // (0,0) -> (1,0) - else {return 2;} // (0,1) -> (1,1) - case 1: // y - if(!i) {return 3;} // (0,0) -> (0,1) - else {return 1;} // (1,0) -> (1,1) - }; - return -1; - } - void Square::FactorEdgeIndex(int idx,int& orientation,int& i){ - switch(idx){ - case 0: case 2: - orientation=0; - i=idx/2; - return; - case 1: case 3: - orientation=1; - i=((idx/2)+1)%2; - return; - }; - } - void Square::EdgeCorners(int idx,int& c1,int& c2){ - int orientation,i; - FactorEdgeIndex(idx,orientation,i); - switch(orientation){ - case 0: - c1=CornerIndex(0,i); - c2=CornerIndex(1,i); - break; - case 1: - c1=CornerIndex(i,0); - c2=CornerIndex(i,1); - break; - }; - } - int Square::ReflectEdgeIndex(int idx,int edgeIndex){ - int orientation=edgeIndex%2; - int o,i; - FactorEdgeIndex(idx,o,i); - if(o!=orientation){return idx;} - else{return EdgeIndex(o,(i+1)%2);} - } - int Square::ReflectCornerIndex(int idx,int edgeIndex){ - int orientation=edgeIndex%2; - int x,y; - FactorCornerIndex(idx,x,y); - switch(orientation){ - case 0: return CornerIndex((x+1)%2,y); - case 1: return CornerIndex(x,(y+1)%2); - }; - return -1; - } - - - - ////////// - // Cube // - ////////// - int Cube::CornerIndex(int x,int y,int z){return (z<<2)|(y<<1)|x;} - void Cube::FactorCornerIndex(int idx,int& x,int& y,int& z){ - x=(idx>>0)%2; - y=(idx>>1)%2; - z=(idx>>2)%2; - } - int Cube::EdgeIndex(int orientation,int i,int j){return (i | (j<<1))|(orientation<<2);} - void Cube::FactorEdgeIndex( int idx , int& orientation , int& i , int &j ) - { - orientation=idx>>2; - i = (idx&1); - j = (idx&2)>>1; - } - int Cube::FaceIndex(int x,int y,int z){ - if (x<0) {return 0;} - else if (x>0) {return 1;} - else if (y<0) {return 2;} - else if (y>0) {return 3;} - else if (z<0) {return 4;} - else if (z>0) {return 5;} - else {return -1;} - } - int Cube::FaceIndex(int dir,int offSet){return (dir<<1)|offSet;} - - void Cube::FactorFaceIndex(int idx,int& x,int& y,int& z){ - x=y=z=0; - switch(idx){ - case 0: x=-1; break; - case 1: x= 1; break; - case 2: y=-1; break; - case 3: y= 1; break; - case 4: z=-1; break; - case 5: z= 1; break; - }; - } - void Cube::FactorFaceIndex(int idx,int& dir,int& offSet){ - dir = idx>>1; - offSet=idx &1; - } - - int Cube::FaceAdjacentToEdges(int eIndex1,int eIndex2){ - int f1,f2,g1,g2; - FacesAdjacentToEdge(eIndex1,f1,f2); - FacesAdjacentToEdge(eIndex2,g1,g2); - if(f1==g1 || f1==g2){return f1;} - if(f2==g1 || f2==g2){return f2;} - return -1; - } - - void Cube::FacesAdjacentToEdge(int eIndex,int& f1Index,int& f2Index){ - int orientation,i1,i2; - FactorEdgeIndex(eIndex,orientation,i1,i2); - i1<<=1; - i2<<=1; - i1--; - i2--; - switch(orientation){ - case 0: - f1Index=FaceIndex( 0,i1, 0); - f2Index=FaceIndex( 0, 0,i2); - break; - case 1: - f1Index=FaceIndex(i1, 0, 0); - f2Index=FaceIndex( 0, 0,i2); - break; - case 2: - f1Index=FaceIndex(i1, 0, 0); - f2Index=FaceIndex( 0,i2, 0); - break; - }; - } - void Cube::EdgeCorners(int idx,int& c1,int& c2){ - int orientation,i1,i2; - FactorEdgeIndex(idx,orientation,i1,i2); - switch(orientation){ - case 0: - c1=CornerIndex(0,i1,i2); - c2=CornerIndex(1,i1,i2); - break; - case 1: - c1=CornerIndex(i1,0,i2); - c2=CornerIndex(i1,1,i2); - break; - case 2: - c1=CornerIndex(i1,i2,0); - c2=CornerIndex(i1,i2,1); - break; - }; - } - void Cube::FaceCorners(int idx,int& c1,int& c2,int& c3,int& c4){ - int i=idx%2; - switch(idx/2){ - case 0: - c1=CornerIndex(i,0,0); - c2=CornerIndex(i,1,0); - c3=CornerIndex(i,0,1); - c4=CornerIndex(i,1,1); - return; - case 1: - c1=CornerIndex(0,i,0); - c2=CornerIndex(1,i,0); - c3=CornerIndex(0,i,1); - c4=CornerIndex(1,i,1); - return; - case 2: - c1=CornerIndex(0,0,i); - c2=CornerIndex(1,0,i); - c3=CornerIndex(0,1,i); - c4=CornerIndex(1,1,i); - return; - } - } - int Cube::AntipodalCornerIndex(int idx){ - int x,y,z; - FactorCornerIndex(idx,x,y,z); - return CornerIndex((x+1)%2,(y+1)%2,(z+1)%2); - } - int Cube::FaceReflectFaceIndex(int idx,int faceIndex){ - if(idx/2!=faceIndex/2){return idx;} - else{ - if(idx%2) {return idx-1;} - else {return idx+1;} - } - } - int Cube::FaceReflectEdgeIndex(int idx,int faceIndex){ - int orientation=faceIndex/2; - int o,i,j; - FactorEdgeIndex(idx,o,i,j); - if(o==orientation){return idx;} - switch(orientation){ - case 0: return EdgeIndex(o,(i+1)%2,j); - case 1: - switch(o){ - case 0: return EdgeIndex(o,(i+1)%2,j); - case 2: return EdgeIndex(o,i,(j+1)%2); - }; - case 2: return EdgeIndex(o,i,(j+1)%2); - }; - return -1; - } - int Cube::FaceReflectCornerIndex(int idx,int faceIndex){ - int orientation=faceIndex/2; - int x,y,z; - FactorCornerIndex(idx,x,y,z); - switch(orientation){ - case 0: return CornerIndex((x+1)%2,y,z); - case 1: return CornerIndex(x,(y+1)%2,z); - case 2: return CornerIndex(x,y,(z+1)%2); - }; - return -1; - } - int Cube::EdgeReflectCornerIndex(int idx,int edgeIndex){ - int orientation,x,y,z; - FactorEdgeIndex(edgeIndex,orientation,x,y); - FactorCornerIndex(idx,x,y,z); - switch(orientation){ - case 0: return CornerIndex( x ,(y+1)%2,(z+1)%2); - case 1: return CornerIndex((x+1)%2, y ,(z+1)%2); - case 2: return CornerIndex((x+1)%2,(y+1)%2, z ); - }; - return -1; - } - int Cube::EdgeReflectEdgeIndex(int edgeIndex){ - int o,i1,i2; - FactorEdgeIndex(edgeIndex,o,i1,i2); - return Cube::EdgeIndex(o,(i1+1)%2,(i2+1)%2); - } - - - ///////////////////// - // MarchingSquares // - ///////////////////// - /* -0} // (0,0) -> (1,0) -1} // (1,0) -> (1,1) -2} // (0,1) -> (1,1) -3} // (0,0) -> (0,1) -*/ - const int* MarchingSquares::edgeMask() - { - const static int edgeMask_local[1< -> -> - 9, // 1 -> 0 -> (0,0) -> 0,3 -> 9 - 3, // 2 -> 1 -> (1,0) -> 0,1 -> 3 - 10, // 3 -> 0,1 -> (0,0) (1,0) -> 1,3 -> 10 - 12, // 4 -> 2 -> (0,1) -> 2,3 -> 12 - 5, // 5 -> 0,2 -> (0,0) (0,1) -> 0,2 -> 5 - 15, // 6 -> 1,2 -> (1,0) (0,1) -> 0,1,2,3 -> 15 - 6, // 7 -> 0,1,2 -> (0,0) (1,0) (0,1) -> 1,2 -> 6 - 6, // 8 -> 3 -> (1,1) -> 1,2 -> 6 - 15, // 9 -> 0,3 -> (0,0) (1,1) -> 0,1,2,3 -> 15 - 5, // 10 -> 1,3 -> (1,0) (1,1) -> 0,2 -> 5 - 12, // 11 -> 0,1,3 -> (0,0) (1,0) (1,1) -> 2,3 -> 12 - 10, // 12 -> 2,3 -> (0,1) (1,1) -> 1,3 -> 10 - 3, // 13 -> 0,2,3 -> (0,0) (0,1) (1,1) -> 0,1 -> 3 - 9, // 14 -> 1,2,3 -> (1,0) (0,1) (1,1) -> 0,3 -> 9 - 0, // 15 -> 0,1,2,3 -> (0,0) (1,0) (0,1) (1,1) -> - }; - return edgeMask_local; - } - - int MarchingSquares::edges(int i, int j) - { - const static int edges_local[1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} - else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} - else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} - else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} - else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} - if (v[0][0] < iso) idx |= 1; - if (v[1][0] < iso) idx |= 2; - if (v[1][1] < iso) idx |= 4; - if (v[0][1] < iso) idx |= 8; - return idx; -} -int MarchingCubes::IsAmbiguous(const double v[Cube::CORNERS],double isoValue,int faceIndex){ - int idx=GetFaceIndex(v,isoValue,faceIndex); - return (idx==5) || (idx==10); -} -int MarchingCubes::HasRoots(const double v[Cube::CORNERS],double isoValue,int faceIndex){ - int idx=GetFaceIndex(v,isoValue,faceIndex); - return (idx!=0) && (idx !=15); -} -int MarchingCubes::HasRoots(const double v[Cube::CORNERS],double isoValue){ - int idx=GetIndex(v,isoValue); - if(idx==0 || idx==255){return 0;} - else{return 1;} -} -int MarchingCubes::HasRoots(int mcIndex){ - if(mcIndex==0 || mcIndex==255){return 0;} - else{return 1;} -} -int MarchingCubes::AddTriangles( const double v[Cube::CORNERS] , double iso , Triangle* isoTriangles ) -{ - int idx,ntriang=0; - Triangle tri; - - idx=GetIndex(v,iso); - - /* Cube is entirely in/out of the surface */ - if (!edgeMask()[idx]) return 0; - - /* Find the vertices where the surface intersects the cube */ - int i,j,ii=1; - for(i=0;i<12;i++){ - if(edgeMask()[idx] & ii){SetVertex(i,v,iso);} - ii<<=1; - } - /* Create the triangle */ - for( i=0 ; triangles(idx, i)!=-1 ; i+=3 ) - { - for(j=0;j<3;j++){ - tri.p[0][j]=vertexList(triangles(idx, i+0), j); - tri.p[1][j]=vertexList(triangles(idx, i+1), j); - tri.p[2][j]=vertexList(triangles(idx, i+2), j); - } - isoTriangles[ntriang++]=tri; - } - return ntriang; -} - -int MarchingCubes::AddTriangleIndices(const double v[Cube::CORNERS],double iso,int* isoIndices){ - int idx,ntriang=0; - - idx=GetIndex(v,iso); - - /* Cube is entirely in/out of the surface */ - if (!edgeMask()[idx]) return 0; - - /* Create the triangle */ - for(int i=0;triangles(idx, i)!=-1;i+=3){ - for(int j=0;j<3;j++){isoIndices[i+j]=triangles(idx, i+j);} - ntriang++; - } - return ntriang; -} - -void MarchingCubes::SetVertex( int e , const double values[Cube::CORNERS] , double iso ) -{ - double t; - int o , i1 , i2; - Cube::FactorEdgeIndex( e , o , i1 , i2 ); - switch( o ) - { - case 0: - t = Interpolate( values[ Cube::CornerIndex( 0 , i1 , i2 ) ] - iso , values[ Cube::CornerIndex( 1 , i1 , i2 ) ] - iso ); - vertexList(e, 0) = t , vertexList(e, 1) = i1 , vertexList(e, 2) = i2; - break; - case 1: - t = Interpolate( values[ Cube::CornerIndex( i1 , 0 , i2 ) ] - iso , values[ Cube::CornerIndex( i1 , 1 , i2 ) ] - iso ); - vertexList(e, 0) = i1 , vertexList(e, 1) = t , vertexList(e, 2) = i2; - break; - case 2: - t = Interpolate( values[ Cube::CornerIndex( i1 , i2 , 0 ) ] - iso , values[ Cube::CornerIndex( i1 , i2 , 1 ) ] - iso ); - vertexList(e, 0) = i1 , vertexList(e, 1) = i2 , vertexList(e, 2) = t; - break; - } -} -double MarchingCubes::Interpolate( double v1 , double v2 ) { return v1/(v1-v2); } - - -/////////////////////////////////// -int MarchingCubes::GetIndex(const float v[Cube::CORNERS],float iso){ - int idx=0; - if (v[Cube::CornerIndex(0,0,0)] < iso) idx |= 1; - if (v[Cube::CornerIndex(1,0,0)] < iso) idx |= 2; - if (v[Cube::CornerIndex(1,1,0)] < iso) idx |= 4; - if (v[Cube::CornerIndex(0,1,0)] < iso) idx |= 8; - if (v[Cube::CornerIndex(0,0,1)] < iso) idx |= 16; - if (v[Cube::CornerIndex(1,0,1)] < iso) idx |= 32; - if (v[Cube::CornerIndex(1,1,1)] < iso) idx |= 64; - if (v[Cube::CornerIndex(0,1,1)] < iso) idx |= 128; - return idx; -} -int MarchingCubes::GetFaceIndex(const float values[Cube::CORNERS],float iso,int faceIndex){ - int i,j,x,y,z,idx=0; - double v[2][2]; - Cube::FactorFaceIndex(faceIndex,x,y,z); - if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(0,i,j)];}}} - else if (x>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(1,i,j)];}}} - else if (y<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,0,j)];}}} - else if (y>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,1,j)];}}} - else if (z<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,0)];}}} - else if (z>0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=values[Cube::CornerIndex(i,j,1)];}}} - if (v[0][0] < iso) idx |= 1; - if (v[1][0] < iso) idx |= 2; - if (v[1][1] < iso) idx |= 4; - if (v[0][1] < iso) idx |= 8; - return idx; -} -int MarchingCubes::GetFaceIndex(int mcIndex,int faceIndex){ - int i,j,x,y,z,idx=0; - int v[2][2]; - Cube::FactorFaceIndex(faceIndex,x,y,z); - if (x<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1<0){for(i=0;i<2;i++){for(j=0;j<2;j++){v[i][j]=mcIndex&(1< -#include "geometry.h" - - -namespace pcl -{ - namespace poisson - { - - class Square - { - public: - enum { CORNERS=4,EDGES=4,NEIGHBORS=4 }; - static int CornerIndex (int x,int y); - static int AntipodalCornerIndex(int idx); - static void FactorCornerIndex (int idx,int& x,int& y); - static int EdgeIndex (int orientation,int i); - static void FactorEdgeIndex (int idx,int& orientation,int& i); - - static int ReflectCornerIndex (int idx,int edgeIndex); - static int ReflectEdgeIndex (int idx,int edgeIndex); - - static void EdgeCorners(int idx,int& c1,int &c2); - }; - - class Cube - { - public: - enum { CORNERS=8,EDGES=12,NEIGHBORS=6 }; - - static int CornerIndex (int x,int y,int z); - static void FactorCornerIndex (int idx,int& x,int& y,int& z); - static int EdgeIndex (int orientation,int i,int j); - static void FactorEdgeIndex (int idx,int& orientation,int& i,int &j); - static int FaceIndex (int dir,int offSet); - static int FaceIndex (int x,int y,int z); - static void FactorFaceIndex (int idx,int& x,int &y,int& z); - static void FactorFaceIndex (int idx,int& dir,int& offSet); - - static int AntipodalCornerIndex (int idx); - static int FaceReflectCornerIndex (int idx,int faceIndex); - static int FaceReflectEdgeIndex (int idx,int faceIndex); - static int FaceReflectFaceIndex (int idx,int faceIndex); - static int EdgeReflectCornerIndex (int idx,int edgeIndex); - static int EdgeReflectEdgeIndex (int edgeIndex); - - static int FaceAdjacentToEdges (int eIndex1,int eIndex2); - static void FacesAdjacentToEdge (int eIndex,int& f1Index,int& f2Index); - - static void EdgeCorners(int idx,int& c1,int &c2); - static void FaceCorners(int idx,int& c1,int &c2,int& c3,int& c4); - }; - - class MarchingSquares - { - static double Interpolate(double v1,double v2); - static void SetVertex(int e,const double values[Square::CORNERS],double iso); - public: - enum { MAX_EDGES=2 }; - static const int* edgeMask(); - static int edges(int i, int j); - static double& vertexList(int i, int j); - - static int GetIndex(const double values[Square::CORNERS],double iso); - static int IsAmbiguous(const double v[Square::CORNERS],double isoValue); - static int AddEdges(const double v[Square::CORNERS],double isoValue,Edge* edges); - static int AddEdgeIndices(const double v[Square::CORNERS],double isoValue,int* edges); - }; - - class MarchingCubes - { - static void SetVertex(int e,const double values[Cube::CORNERS],double iso); - static int GetFaceIndex(const double values[Cube::CORNERS],double iso,int faceIndex); - - static void SetVertex(int e,const float values[Cube::CORNERS],float iso); - static int GetFaceIndex(const float values[Cube::CORNERS],float iso,int faceIndex); - - static int GetFaceIndex(int mcIndex,int faceIndex); - public: - static double Interpolate(double v1,double v2); - static float Interpolate(float v1,float v2); - enum { MAX_TRIANGLES=5 }; - static const int* edgeMask(); - static int triangles(int i, int j); - static const int* cornerMap(); - static double& vertexList(int i, int j); - - static int AddTriangleIndices(int mcIndex,int* triangles); - - static int GetIndex(const double values[Cube::CORNERS],double iso); - static int IsAmbiguous(const double v[Cube::CORNERS],double isoValue,int faceIndex); - static int HasRoots(const double v[Cube::CORNERS],double isoValue); - static int HasRoots(const double v[Cube::CORNERS],double isoValue,int faceIndex); - static int AddTriangles(const double v[Cube::CORNERS],double isoValue,Triangle* triangles); - static int AddTriangleIndices(const double v[Cube::CORNERS],double isoValue,int* triangles); - - static int GetIndex(const float values[Cube::CORNERS],float iso); - static int IsAmbiguous(const float v[Cube::CORNERS],float isoValue,int faceIndex); - static int HasRoots(const float v[Cube::CORNERS],float isoValue); - static int HasRoots(const float v[Cube::CORNERS],float isoValue,int faceIndex); - static int AddTriangles(const float v[Cube::CORNERS],float isoValue,Triangle* triangles); - static int AddTriangleIndices(const float v[Cube::CORNERS],float isoValue,int* triangles); - - static int IsAmbiguous(int mcIndex,int faceIndex); - static int HasRoots(int mcIndex); - static int HasFaceRoots(int mcIndex,int faceIndex); - static int HasEdgeRoots(int mcIndex,int edgeIndex); - }; - } -} - - -#endif //MARCHING_CUBES_INCLUDED diff --git a/plugins/probe/3rd/poisson4/mat.h b/plugins/probe/3rd/poisson4/mat.h deleted file mode 100644 index 102482cfe5..0000000000 --- a/plugins/probe/3rd/poisson4/mat.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright (c) 2007, Michael Kazhdan -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -#ifndef MAT_INCLUDED -#define MAT_INCLUDED -#include "geometry.h" - - -namespace pcl -{ - namespace poisson - { - - template - class MinimalAreaTriangulation - { - Real* bestTriangulation; - int* midPoint; - Real GetArea(const size_t& i,const size_t& j,const std::vector >& vertices); - void GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles); - public: - MinimalAreaTriangulation(void); - ~MinimalAreaTriangulation(void); - Real GetArea(const std::vector >& vertices); - void GetTriangulation(const std::vector >& vertices,std::vector& triangles); - }; - - } -} - -#include "mat.hpp" - - - -#endif // MAT_INCLUDED diff --git a/plugins/probe/3rd/poisson4/mat.hpp b/plugins/probe/3rd/poisson4/mat.hpp deleted file mode 100644 index 400d387d9a..0000000000 --- a/plugins/probe/3rd/poisson4/mat.hpp +++ /dev/null @@ -1,223 +0,0 @@ -/* -Copyright (c) 2007, Michael Kazhdan -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ -////////////////////////////// -// MinimalAreaTriangulation // -////////////////////////////// - -namespace pcl -{ - namespace poisson - { - - template - MinimalAreaTriangulation::MinimalAreaTriangulation(void) - { - bestTriangulation=NULL; - midPoint=NULL; - } - template - MinimalAreaTriangulation::~MinimalAreaTriangulation(void) - { - if(bestTriangulation) - delete[] bestTriangulation; - bestTriangulation=NULL; - if(midPoint) - delete[] midPoint; - midPoint=NULL; - } - template - void MinimalAreaTriangulation::GetTriangulation(const std::vector >& vertices,std::vector& triangles) - { - if(vertices.size()==3) - { - triangles.resize(1); - triangles[0].idx[0]=0; - triangles[0].idx[1]=1; - triangles[0].idx[2]=2; - return; - } - else if(vertices.size()==4) - { - TriangleIndex tIndex[2][2]; - Real area[2]; - - area[0]=area[1]=0; - triangles.resize(2); - - tIndex[0][0].idx[0]=0; - tIndex[0][0].idx[1]=1; - tIndex[0][0].idx[2]=2; - tIndex[0][1].idx[0]=2; - tIndex[0][1].idx[1]=3; - tIndex[0][1].idx[2]=0; - - tIndex[1][0].idx[0]=0; - tIndex[1][0].idx[1]=1; - tIndex[1][0].idx[2]=3; - tIndex[1][1].idx[0]=3; - tIndex[1][1].idx[1]=1; - tIndex[1][1].idx[2]=2; - - Point3D n,p1,p2; - for(int i=0;i<2;i++) - for(int j=0;j<2;j++) - { - p1=vertices[tIndex[i][j].idx[1]]-vertices[tIndex[i][j].idx[0]]; - p2=vertices[tIndex[i][j].idx[2]]-vertices[tIndex[i][j].idx[0]]; - CrossProduct(p1,p2,n); - area[i] += Real( Length(n) ); - } - if(area[0]>area[1]) - { - triangles[0]=tIndex[1][0]; - triangles[1]=tIndex[1][1]; - } - else - { - triangles[0]=tIndex[0][0]; - triangles[1]=tIndex[0][1]; - } - return; - } - if(bestTriangulation) - delete[] bestTriangulation; - if(midPoint) - delete[] midPoint; - bestTriangulation=NULL; - midPoint=NULL; - size_t eCount=vertices.size(); - bestTriangulation=new Real[eCount*eCount]; - midPoint=new int[eCount*eCount]; - for(size_t i=0;i - Real MinimalAreaTriangulation::GetArea(const std::vector >& vertices) - { - if(bestTriangulation) - delete[] bestTriangulation; - if(midPoint) - delete[] midPoint; - bestTriangulation=NULL; - midPoint=NULL; - int eCount=vertices.size(); - bestTriangulation=new double[eCount*eCount]; - midPoint=new int[eCount*eCount]; - for(int i=0;i - void MinimalAreaTriangulation::GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles) - { - TriangleIndex tIndex; - size_t eCount=vertices.size(); - size_t ii=i; - if(i=ii) - return; - ii=midPoint[i*eCount+j]; - if(ii>=0) - { - tIndex.idx[0] = int( i ); - tIndex.idx[1] = int( j ); - tIndex.idx[2] = int( ii ); - triangles.push_back(tIndex); - GetTriangulation(i,ii,vertices,triangles); - GetTriangulation(ii,j,vertices,triangles); - } - } - - template - Real MinimalAreaTriangulation::GetArea(const size_t& i,const size_t& j,const std::vector >& vertices) - { - Real a=FLT_MAX,temp; - size_t eCount=vertices.size(); - size_t idx=i*eCount+j; - size_t ii=i; - if(i=ii) - { - bestTriangulation[idx]=0; - return 0; - } - if(midPoint[idx]!=-1) - return bestTriangulation[idx]; - int mid=-1; - for(size_t r=j+1;r p,p1,p2; - p1=vertices[i]-vertices[rr]; - p2=vertices[j]-vertices[rr]; - CrossProduct(p1,p2,p); - temp = Real( Length(p) ); - if(bestTriangulation[idx1]>=0) - { - temp+=bestTriangulation[idx1]; - if(temp>a) - continue; - if(bestTriangulation[idx2]>0) - temp+=bestTriangulation[idx2]; - else - temp+=GetArea(rr,j,vertices); - } - else - { - if(bestTriangulation[idx2]>=0) - temp+=bestTriangulation[idx2]; - else - temp+=GetArea(rr,j,vertices); - if(temp>a) - continue; - temp+=GetArea(i,rr,vertices); - } - - if(temp -// b_1[i] = < \nabla B_i(p) , V(p) > -// 2] Formulate this as a Poisson equation: -// \sum_i x_i \Delta B_i(p) = \nabla \cdot V(p) -// which is solved by the system A_2x = b_2 where: -// A_2[i,j] = - < \Delta B_i(p) , B_j(p) > -// b_2[i] = - < B_i(p) , \nabla \cdot V(p) > -// Although the two system matrices should be the same (assuming that the B_i satisfy dirichlet/neumann boundary -// conditions) the constraint vectors can differ when V does not satisfy the Neumann boundary conditions: -// A_1[i,j] = \int_R < \nabla B_i(p) , \nabla B_j(p) > -// = \int_R [ \nabla \cdot ( B_i(p) \nabla B_j(p) ) - B_i(p) \Delta B_j(p) ] -// = \int_dR < N(p) , B_i(p) \nabla B_j(p) > + A_2[i,j] -// and the first integral is zero if either f_i is zero on the boundary dR or the derivative of B_i across the boundary -// is zero. However, for the constraints we have: -// b_1(i) = \int_R < \nabla B_i(p) , V(p) > -// = \int_R [ \nabla \cdot ( B_i(p) V(p) ) - B_i(p) \nabla \cdot V(p) ] -// = \int_dR < N(p) , B_i(p) V(p) > + b_2[i] -// In particular, this implies that if the B_i satisfy the Neumann boundary conditions (rather than Dirichlet), -// and V is not zero across the boundary, then the two constraints are different. -// Forcing the < V(p) , N(p) > = 0 on the boundary, by killing off the component of the vector-field in the normal -// direction (FORCE_NEUMANN_FIELD), makes the two systems equal, and the value of this flag should be immaterial. Note -// that under interpretation 1, we have: -// \sum_i b_1(i) = < \nabla \sum_ i B_i(p) , V(p) > = 0 -// because the B_i's sum to one. However, in general, we could have -// \sum_i b_2(i) \neq 0. -// This could cause trouble because the constant functions are in the kernel of the matrix A, so CG will misbehave if -// the constraint has a non-zero DC term. (Again, forcing < V(p) , N(p) > = 0 along the boundary resolves this problem.) - -#define FORCE_NEUMANN_FIELD 1 -// This flag forces the normal component across the boundary of the integration domain to be zero. -// This should be enabled if GRADIENT_DOMAIN_SOLUTION is not, so that CG doesn't run into trouble. - - -#include - -#include "poisson4/bspline_data.h" -#include "poisson4/octree_poisson.h" -#include "poisson4/sparse_matrix.h" - -#define DIMENSION 3 - - -namespace pcl { -namespace poisson { - -typedef float Real; -typedef float BSplineDataReal; - - -class TreeNodeData { -public: - inline static int UseIndex = 1; - int nodeIndex; - union { - int mcIndex; - struct { - Real centerWeightContribution; - int normalIndex; - }; - }; - Real constraint, solution; - int pointIndex; - - TreeNodeData(void); - ~TreeNodeData(void); -}; - -typedef pcl::poisson::OctNode TreeOctNode; - - -class RootInfo { -public: - const TreeOctNode* node; - int edgeIndex; - long long key; -}; - -class VertexData { -public: - static long long EdgeIndex(const TreeOctNode* node, int eIndex, int maxDepth, int index[DIMENSION]); - static long long EdgeIndex(const TreeOctNode* node, int eIndex, int maxDepth); - static long long FaceIndex(const TreeOctNode* node, int fIndex, int maxDepth, int index[DIMENSION]); - static long long FaceIndex(const TreeOctNode* node, int fIndex, int maxDepth); - static long long CornerIndex( - int depth, const int offSet[DIMENSION], int cIndex, int maxDepth, int index[DIMENSION]); - static long long CornerIndex(const TreeOctNode* node, int cIndex, int maxDepth, int index[DIMENSION]); - static long long CornerIndex(const TreeOctNode* node, int cIndex, int maxDepth); - static long long CenterIndex(int depth, const int offSet[DIMENSION], int maxDepth, int index[DIMENSION]); - static long long CenterIndex(const TreeOctNode* node, int maxDepth, int index[DIMENSION]); - static long long CenterIndex(const TreeOctNode* node, int maxDepth); - static long long CornerIndexKey(const int index[DIMENSION]); -}; -class SortedTreeNodes { -public: - TreeOctNode** treeNodes; - int* nodeCount; - int maxDepth; - SortedTreeNodes(void); - ~SortedTreeNodes(void); - void set(TreeOctNode& root); - struct CornerIndices { - int idx[pcl::poisson::Cube::CORNERS]; - CornerIndices(void) { memset(idx, -1, sizeof(int) * pcl::poisson::Cube::CORNERS); } - int& operator[](int i) { return idx[i]; } - const int& operator[](int i) const { return idx[i]; } - }; - struct CornerTableData { - CornerTableData(void) { cCount = 0; } - ~CornerTableData(void) { clear(); } - void clear(void) { - cTable.clear(); - cCount = 0; - } - CornerIndices& operator[](const TreeOctNode* node); - const CornerIndices& operator[](const TreeOctNode* node) const; - CornerIndices& cornerIndices(const TreeOctNode* node); - const CornerIndices& cornerIndices(const TreeOctNode* node) const; - int cCount; - std::vector cTable; - std::vector offsets; - }; - void setCornerTable(CornerTableData& cData, const TreeOctNode* rootNode, int depth, int threads) const; - void setCornerTable(CornerTableData& cData, const TreeOctNode* rootNode, int threads) const { - setCornerTable(cData, rootNode, maxDepth - 1, threads); - } - void setCornerTable(CornerTableData& cData, int threads) const { - setCornerTable(cData, treeNodes[0], maxDepth - 1, threads); - } - int getMaxCornerCount(const TreeOctNode* rootNode, int depth, int maxDepth, int threads) const; - struct EdgeIndices { - int idx[pcl::poisson::Cube::EDGES]; - EdgeIndices(void) { memset(idx, -1, sizeof(int) * pcl::poisson::Cube::EDGES); } - int& operator[](int i) { return idx[i]; } - const int& operator[](int i) const { return idx[i]; } - }; - struct EdgeTableData { - EdgeTableData(void) { eCount = 0; } - ~EdgeTableData(void) { clear(); } - void clear(void) { eTable.clear(), eCount = 0; } - EdgeIndices& operator[](const TreeOctNode* node); - const EdgeIndices& operator[](const TreeOctNode* node) const; - EdgeIndices& edgeIndices(const TreeOctNode* node); - const EdgeIndices& edgeIndices(const TreeOctNode* node) const; - int eCount; - std::vector eTable; - std::vector offsets; - }; - void setEdgeTable(EdgeTableData& eData, const TreeOctNode* rootNode, int depth, int threads); - void setEdgeTable(EdgeTableData& eData, const TreeOctNode* rootNode, int threads) { - setEdgeTable(eData, rootNode, maxDepth - 1, threads); - } - void setEdgeTable(EdgeTableData& eData, int threads) { setEdgeTable(eData, treeNodes[0], maxDepth - 1, threads); } - int getMaxEdgeCount(const TreeOctNode* rootNode, int depth, int threads) const; -}; - - -template class Octree { - SortedTreeNodes _sNodes; - int _minDepth; - bool _constrainValues; - std::vector _pointCount; - struct PointData { - pcl::poisson::Point3D position; - Real weight; - Real value; - PointData(pcl::poisson::Point3D p, Real w, Real v = 0) { position = p, weight = w, value = v; } - }; - std::vector _points; - TreeOctNode::NeighborKey3 neighborKey; - TreeOctNode::ConstNeighborKey3 neighborKey2; - - Real radius; - int width; - Real GetLaplacian(const int index[DIMENSION]) const; - // Note that this is a slight misnomer. We're only taking the diveregence/Laplacian in the weak sense, so there is a - // change of sign. - Real GetLaplacian(const TreeOctNode* node1, const TreeOctNode* node2) const; - Real GetDivergence( - const TreeOctNode* node1, const TreeOctNode* node2, const pcl::poisson::Point3D& normal1) const; - Real GetDivergenceMinusLaplacian(const TreeOctNode* node1, const TreeOctNode* node2, Real value1, - const pcl::poisson::Point3D& normal1) const; - struct PointInfo { - float splineValues[3][3]; - float weightedValue; - }; - Real GetValue(const PointInfo points[3][3][3], const bool hasPoints[3][3], const int d[3]) const; - - class AdjacencyCountFunction { - public: - int adjacencyCount; - void Function(const TreeOctNode* node1, const TreeOctNode* node2); - }; - class AdjacencySetFunction { - public: - int *adjacencies, adjacencyCount; - void Function(const TreeOctNode* node1, const TreeOctNode* node2); - }; - - class RefineFunction { - public: - int depth; - void Function(TreeOctNode* node1, const TreeOctNode* node2); - }; - class FaceEdgesFunction { - public: - int fIndex, maxDepth; - std::vector>* edges; - std::unordered_map>* vertexCount; - void Function(const TreeOctNode* node1, const TreeOctNode* node2); - }; - - int SolveFixedDepthMatrix(int depth, const SortedTreeNodes& sNodes, Real* subConstraints, bool showResidual, - int minIters, double accuracy); - int SolveFixedDepthMatrix(int depth, const SortedTreeNodes& sNodes, Real* subConstraints, int startingDepth, - bool showResidual, int minIters, double accuracy); - - void SetMatrixRowBounds(const TreeOctNode* node, int rDepth, const int rOff[3], int& xStart, int& xEnd, int& yStart, - int& yEnd, int& zStart, int& zEnd) const; - int GetMatrixRowSize(const TreeOctNode::Neighbors5& neighbors5) const; - int GetMatrixRowSize(const TreeOctNode::Neighbors5& neighbors5, int xStart, int xEnd, int yStart, int yEnd, - int zStart, int zEnd) const; - int SetMatrixRow(const TreeOctNode::Neighbors5& neighbors5, pcl::poisson::MatrixEntry* row, int offset, - const double stencil[5][5][5]) const; - int SetMatrixRow(const TreeOctNode::Neighbors5& neighbors5, pcl::poisson::MatrixEntry* row, int offset, - const double stencil[5][5][5], int xStart, int xEnd, int yStart, int yEnd, int zStart, int zEnd) const; - void SetDivergenceStencil(int depth, pcl::poisson::Point3D* stencil, bool scatter) const; - void SetLaplacianStencil(int depth, double stencil[5][5][5]) const; - template struct Stencil { C values[N][N][N]; }; - void SetLaplacianStencils(int depth, Stencil stencil[2][2][2]) const; - void SetDivergenceStencils( - int depth, Stencil, 5> stencil[2][2][2], bool scatter) const; - void SetEvaluationStencils(int depth, Stencil stencil1[8], Stencil stencil2[8][8]) const; - - static void UpdateCoarserSupportBounds( - const TreeOctNode* node, int& startX, int& endX, int& startY, int& endY, int& startZ, int& endZ); - void UpdateConstraintsFromCoarser(const TreeOctNode::NeighborKey5& neighborKey5, TreeOctNode* node, - Real* metSolution, const Stencil& stencil) const; - void SetCoarserPointValues(int depth, const SortedTreeNodes& sNodes, Real* metSolution); - Real WeightedCoarserFunctionValue( - const TreeOctNode::NeighborKey3& neighborKey3, const TreeOctNode* node, Real* metSolution) const; - void UpSampleCoarserSolution(int depth, const SortedTreeNodes& sNodes, pcl::poisson::Vector& solution) const; - void DownSampleFinerConstraints(int depth, SortedTreeNodes& sNodes) const; - template void DownSample(int depth, const SortedTreeNodes& sNodes, C* constraints) const; - template void UpSample(int depth, const SortedTreeNodes& sNodes, C* coefficients) const; - int GetFixedDepthLaplacian(pcl::poisson::SparseSymmetricMatrix& matrix, int depth, - const SortedTreeNodes& sNodes, Real* subConstraints); - int GetRestrictedFixedDepthLaplacian(pcl::poisson::SparseSymmetricMatrix& matrix, int depth, - const int* entries, int entryCount, const TreeOctNode* rNode, Real radius, const SortedTreeNodes& sNodes, - Real* subConstraints); - - void SetIsoCorners(Real isoValue, TreeOctNode* leaf, SortedTreeNodes::CornerTableData& cData, char* valuesSet, - Real* values, TreeOctNode::ConstNeighborKey3& nKey, const Real* metSolution, - const Stencil stencil1[8], const Stencil stencil2[8][8]); - static int IsBoundaryFace(const TreeOctNode* node, int faceIndex, int subdivideDepth); - static int IsBoundaryEdge(const TreeOctNode* node, int edgeIndex, int subdivideDepth); - static int IsBoundaryEdge(const TreeOctNode* node, int dir, int x, int y, int subidivideDepth); - - // For computing the iso-surface there is a lot of re-computation of information across shared geometry. - // For function values we don't care so much. - // For edges we need to be careful so that the mesh remains water-tight - struct RootData : public SortedTreeNodes::CornerTableData, public SortedTreeNodes::EdgeTableData { - // Edge to iso-vertex map - std::unordered_map boundaryRoots; - // Vertex to ( value , normal ) map - std::unordered_map>>* boundaryValues; - int* interiorRoots; - Real* cornerValues; - pcl::poisson::Point3D* cornerNormals; - char *cornerValuesSet, *cornerNormalsSet, *edgesSet; - }; - - int SetBoundaryMCRootPositions( - int sDepth, Real isoValue, RootData& rootData, pcl::poisson::CoredMeshData* mesh, int nonLinearFit); - int SetMCRootPositions(TreeOctNode* node, int sDepth, Real isoValue, TreeOctNode::ConstNeighborKey5& neighborKey5, - RootData& rootData, std::vector>* interiorPositions, - pcl::poisson::CoredMeshData* mesh, const Real* metSolution, int nonLinearFit); -#if MISHA_DEBUG - int GetMCIsoTriangles(TreeOctNode* node, pcl::poisson::CoredMeshData* mesh, RootData& rootData, - std::vector>* interiorPositions, int offSet, int sDepth, bool polygonMesh, - std::vector>* barycenters); - static int AddTriangles(pcl::poisson::CoredMeshData* mesh, std::vector& edges, - std::vector>* interiorPositions, int offSet, bool polygonMesh, - std::vector>* barycenters); -#else // !MISHA_DEBUG - int GetMCIsoTriangles(TreeOctNode* node, pcl::poisson::CoredMeshData* mesh, RootData& rootData, - std::vector>* interiorPositions, int offSet, int sDepth, bool addBarycenter, - bool polygonMesh); - static int AddTriangles(pcl::poisson::CoredMeshData* mesh, std::vector& edges, - std::vector>* interiorPositions, int offSet, bool addBarycenter, bool polygonMesh); -#endif // MISHA_DEBUG - - - void GetMCIsoEdges(TreeOctNode* node, int sDepth, std::vector>& edges); - static int GetEdgeLoops(std::vector>& edges, - std::vector>>& loops); - static int InteriorFaceRootCount(const TreeOctNode* node, const int& faceIndex, int maxDepth); - static int EdgeRootCount(const TreeOctNode* node, int edgeIndex, int maxDepth); - static void GetRootSpan(const RootInfo& ri, pcl::poisson::Point3D& start, pcl::poisson::Point3D& end); - int GetRoot(const RootInfo& ri, Real isoValue, TreeOctNode::ConstNeighborKey5& neighborKey5, - pcl::poisson::Point3D& position, RootData& rootData, int sDepth, const Real* metSolution, - int nonLinearFit); - static int GetRootIndex(const TreeOctNode* node, int edgeIndex, int maxDepth, RootInfo& ri); - static int GetRootIndex(const TreeOctNode* node, int edgeIndex, int maxDepth, int sDepth, RootInfo& ri); - static int GetRootIndex(const RootInfo& ri, RootData& rootData, pcl::poisson::CoredPointIndex& index); - static int GetRootPair(const RootInfo& root, int maxDepth, RootInfo& pair); - - int NonLinearUpdateWeightContribution( - TreeOctNode* node, const pcl::poisson::Point3D& position, Real weight = Real(1.0)); - Real NonLinearGetSampleWeight(TreeOctNode* node, const pcl::poisson::Point3D& position); - void NonLinearGetSampleDepthAndWeight( - TreeOctNode* node, const pcl::poisson::Point3D& position, Real samplesPerNode, Real& depth, Real& weight); - int NonLinearSplatOrientedPoint( - TreeOctNode* node, const pcl::poisson::Point3D& point, const pcl::poisson::Point3D& normal); - Real NonLinearSplatOrientedPoint(const pcl::poisson::Point3D& point, - const pcl::poisson::Point3D& normal, int kernelDepth, Real samplesPerNode, int minDepth, int maxDepth); - - int HasNormals(TreeOctNode* node, Real epsilon); - Real getCornerValue(const TreeOctNode::ConstNeighborKey3& neighborKey3, const TreeOctNode* node, int corner, - const Real* metSolution); - pcl::poisson::Point3D getCornerNormal(const TreeOctNode::ConstNeighborKey5& neighborKey5, - const TreeOctNode* node, int corner, const Real* metSolution); - Real getCornerValue(const TreeOctNode::ConstNeighborKey3& neighborKey3, const TreeOctNode* node, int corner, - const Real* metSolution, const double stencil1[3][3][3], const double stencil2[3][3][3]); - Real getCenterValue(const TreeOctNode::ConstNeighborKey3& neighborKey3, const TreeOctNode* node); - -public: - int threads; - static double maxMemoryUsage; - static double MemoryUsage(void); - std::vector>* normals; - Real postNormalSmooth; - TreeOctNode tree; - pcl::poisson::BSplineData fData; - Octree(void); - - void setBSplineData(int maxDepth, Real normalSmooth = -1, bool reflectBoundary = false); - void finalize(void); - void RefineBoundary(int subdivisionDepth); - Real* GetWeightGrid(int& res, int depth = -1); - Real* GetSolutionGrid(int& res, float isoValue = 0.f, int depth = -1); - - template - int setTree(typename pcl::PointCloud::ConstPtr input_, int maxDepth, int minDepth, int kernelDepth, - Real samplesPerNode, Real scaleFactor, Point3D& center, Real& scale, int useConfidence, - Real constraintWeight, bool adaptiveWeights); - - void SetLaplacianConstraints(void); - void ClipTree(void); - int LaplacianMatrixIteration(int subdivideDepth, bool showResidual, int minIters, double accuracy); - - Real GetIsoValue(void); - void GetMCIsoTriangles(Real isoValue, int subdivideDepth, pcl::poisson::CoredMeshData* mesh, int fullDepthIso = 0, - int nonLinearFit = 1, bool addBarycenter = false, bool polygonMesh = false); -}; - - -} // namespace poisson -} // namespace pcl - - -#include "poisson4/multi_grid_octree_data.hpp" -#endif // MULTI_GRID_OCTREE_DATA_INCLUDED diff --git a/plugins/probe/3rd/poisson4/multi_grid_octree_data.hpp b/plugins/probe/3rd/poisson4/multi_grid_octree_data.hpp deleted file mode 100644 index e4ef55598d..0000000000 --- a/plugins/probe/3rd/poisson4/multi_grid_octree_data.hpp +++ /dev/null @@ -1,3898 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include - -#include "poisson4/mat.h" -#include "poisson4/octree_poisson.h" -#include "poisson4/poisson_exceptions.h" -#include "poisson4/sparse_matrix.h" - -#if defined WIN32 || defined _WIN32 -# if !defined __MINGW32__ -# include -# endif -#endif - - -#define ITERATION_POWER 1.0 / 3 -#define MEMORY_ALLOCATOR_BLOCK_SIZE 1 << 12 -#define SPLAT_ORDER 2 - -namespace pcl { -namespace poisson { - -const Real MATRIX_ENTRY_EPSILON = Real(0); -const Real EPSILON = Real(1e-6); -const Real ROUND_EPS = Real(1e-5); - -inline void atomicOr(volatile int& dest, int value) { -#if defined _WIN32 && !defined __MINGW32__ -# if defined(_M_IX86) - _InterlockedOr((long volatile*)&dest, value); -# else - InterlockedOr((long volatile*)&dest, value); -# endif -#else // !_WIN32 || __MINGW32__ -# pragma omp atomic - dest |= value; -#endif // _WIN32 && !__MINGW32__ -} - - -///////////////////// -// SortedTreeNodes // -///////////////////// -inline SortedTreeNodes::SortedTreeNodes(void) { - nodeCount = NULL; - treeNodes = NULL; - maxDepth = 0; -} -inline SortedTreeNodes::~SortedTreeNodes(void) { - if (nodeCount) delete[] nodeCount; - if (treeNodes) delete[] treeNodes; - nodeCount = NULL; - treeNodes = NULL; -} - -inline void SortedTreeNodes::set(TreeOctNode& root) { - if (nodeCount) delete[] nodeCount; - if (treeNodes) delete[] treeNodes; - maxDepth = root.maxDepth() + 1; - nodeCount = new int[maxDepth + 1]; - treeNodes = new TreeOctNode*[root.nodes()]; - - nodeCount[0] = 0, nodeCount[1] = 1; - treeNodes[0] = &root; - for (int d = 1; d < maxDepth; d++) { - nodeCount[d + 1] = nodeCount[d]; - for (int i = nodeCount[d - 1]; i < nodeCount[d]; i++) { - TreeOctNode* temp = treeNodes[i]; - if (temp->children) - for (int c = 0; c < 8; c++) treeNodes[nodeCount[d + 1]++] = temp->children + c; - } - } - for (int i = 0; i < nodeCount[maxDepth]; i++) treeNodes[i]->nodeData.nodeIndex = i; -} -inline SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::operator[](const TreeOctNode* node) { - return cTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline const SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::operator[]( - const TreeOctNode* node) const { - return cTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::cornerIndices(const TreeOctNode* node) { - return cTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline const SortedTreeNodes::CornerIndices& SortedTreeNodes::CornerTableData::cornerIndices( - const TreeOctNode* node) const { - return cTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline void SortedTreeNodes::setCornerTable( - CornerTableData& cData, const TreeOctNode* rootNode, int maxDepth, int threads) const { - if (threads <= 0) threads = 1; - // The vector of per-depth node spans - std::vector> spans(this->maxDepth, std::pair(-1, -1)); - int minDepth, off[3]; - rootNode->depthAndOffset(minDepth, off); - cData.offsets.resize(this->maxDepth, -1); - int nodeCount = 0; - { - int start = rootNode->nodeData.nodeIndex, end = start; - for (int d = minDepth; d <= maxDepth; d++) { - spans[d] = std::pair(start, end + 1); - cData.offsets[d] = nodeCount - spans[d].first; - nodeCount += spans[d].second - spans[d].first; - if (d < maxDepth) { - while (start < end && !treeNodes[start]->children) start++; - while (end > start && !treeNodes[end]->children) end--; - if (start == end && !treeNodes[start]->children) break; - start = treeNodes[start]->children[0].nodeData.nodeIndex; - end = treeNodes[end]->children[7].nodeData.nodeIndex; - } - } - } - cData.cTable.resize(nodeCount); - std::vector count(threads); -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::ConstNeighborKey3 neighborKey; - neighborKey.set(maxDepth); - int offset = nodeCount * t * Cube::CORNERS; - count[t] = 0; - for (int d = minDepth; d <= maxDepth; d++) { - int start = spans[d].first, end = spans[d].second, width = end - start; - for (int i = start + (width * t) / threads; i < start + (width * (t + 1)) / threads; i++) { - TreeOctNode* node = treeNodes[i]; - if (d < maxDepth && node->children) continue; - const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors(node, minDepth); - for (int c = 0; c < Cube::CORNERS; c++) // Iterate over the cell's corners - { - bool cornerOwner = true; - int x, y, z; - int ac = Cube::AntipodalCornerIndex(c); // The index of the node relative to the corner - Cube::FactorCornerIndex(c, x, y, z); - for (int cc = 0; cc < Cube::CORNERS; cc++) // Iterate over the corner's cells - { - int xx, yy, zz; - Cube::FactorCornerIndex(cc, xx, yy, zz); - xx += x, yy += y, zz += z; - if (neighbors.neighbors[xx][yy][zz]) - if (cc < ac || (d < maxDepth && neighbors.neighbors[xx][yy][zz]->children)) { - int _d, _off[3]; - neighbors.neighbors[xx][yy][zz]->depthAndOffset(_d, _off); - _off[0] >>= (d - minDepth), _off[1] >>= (d - minDepth), _off[2] >>= (d - minDepth); - if (_off[0] == off[0] && _off[1] == off[1] && _off[2] == off[2]) { - cornerOwner = false; - break; - } else - fprintf(stderr, "[WARNING] How did we leave the subtree?\n"); - } - } - if (cornerOwner) { - const TreeOctNode* n = node; - int d = n->depth(); - do { - const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.neighbors[d]; - // Set all the corner indices at the current depth - for (int cc = 0; cc < Cube::CORNERS; cc++) { - int xx, yy, zz; - Cube::FactorCornerIndex(cc, xx, yy, zz); - xx += x, yy += y, zz += z; - if (neighborKey.neighbors[d].neighbors[xx][yy][zz]) - cData[neighbors.neighbors[xx][yy][zz]][Cube::AntipodalCornerIndex(cc)] = - count[t] + offset; - } - // If we are not at the root and the parent also has the corner - if (d == minDepth || n != (n->parent->children + c)) break; - n = n->parent; - d--; - } while (1); - count[t]++; - } - } - } - } - } - cData.cCount = 0; - std::vector offsets(threads + 1); - offsets[0] = 0; - for (int t = 0; t < threads; t++) { - cData.cCount += count[t]; - offsets[t + 1] = offsets[t] + count[t]; - } - - unsigned int paralellExceptionCount = 0; -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - for (int d = minDepth; d <= maxDepth; d++) { - int start = spans[d].first, end = spans[d].second, width = end - start; - for (int i = start + (width * t) / threads; i < start + (width * (t + 1)) / threads; i++) { - for (int c = 0; c < Cube::CORNERS; c++) { - int& idx = cData[treeNodes[i]][c]; - if (idx < 0) { -#pragma omp critical - { - // found unindexed corner - ++paralellExceptionCount; - } - } else { - int div = idx / (nodeCount * Cube::CORNERS); - int rem = idx % (nodeCount * Cube::CORNERS); - idx = rem + offsets[div]; - } - } - } - } - } - - if (paralellExceptionCount > 0) - POISSON_THROW_EXCEPTION(pcl::poisson::PoissonOpenMPException, - "Found " << paralellExceptionCount << " unindexed corner nodes during openMP loop execution."); -} -inline int SortedTreeNodes::getMaxCornerCount(const TreeOctNode* rootNode, int depth, int maxDepth, int threads) const { - if (threads <= 0) threads = 1; - int res = 1 << depth; - std::vector> cornerCount(threads); - for (int t = 0; t < threads; t++) cornerCount[t].resize(res * res * res, 0); - -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - std::vector& _cornerCount = cornerCount[t]; - TreeOctNode::ConstNeighborKey3 neighborKey; - neighborKey.set(maxDepth); - int start = nodeCount[depth], end = nodeCount[maxDepth + 1], range = end - start; - for (int i = (range * t) / threads; i < (range * (t + 1)) / threads; i++) { - TreeOctNode* node = treeNodes[start + i]; - int d, off[3]; - node->depthAndOffset(d, off); - if (d < maxDepth && node->children) continue; - - const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors(node, depth); - for (int c = 0; c < Cube::CORNERS; c++) // Iterate over the cell's corners - { - bool cornerOwner = true; - int x, y, z; - int ac = Cube::AntipodalCornerIndex(c); // The index of the node relative to the corner - Cube::FactorCornerIndex(c, x, y, z); - for (int cc = 0; cc < Cube::CORNERS; cc++) // Iterate over the corner's cells - { - int xx, yy, zz; - Cube::FactorCornerIndex(cc, xx, yy, zz); - xx += x, yy += y, zz += z; - if (neighbors.neighbors[xx][yy][zz]) - if (cc < ac || (d < maxDepth && neighbors.neighbors[xx][yy][zz]->children)) { - cornerOwner = false; - break; - } - } - if (cornerOwner) - _cornerCount[((off[0] >> (d - depth)) * res * res) + ((off[1] >> (d - depth)) * res) + - (off[2] >> (d - depth))]++; - } - } - } - int maxCount = 0; - for (int i = 0; i < res * res * res; i++) { - int c = 0; - for (int t = 0; t < threads; t++) c += cornerCount[t][i]; - maxCount = std::max(maxCount, c); - } - return maxCount; -} -inline SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::operator[](const TreeOctNode* node) { - return eTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline const SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::operator[](const TreeOctNode* node) const { - return eTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::edgeIndices(const TreeOctNode* node) { - return eTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline const SortedTreeNodes::EdgeIndices& SortedTreeNodes::EdgeTableData::edgeIndices(const TreeOctNode* node) const { - return eTable[node->nodeData.nodeIndex + offsets[node->d]]; -} -inline void SortedTreeNodes::setEdgeTable( - EdgeTableData& eData, const TreeOctNode* rootNode, int maxDepth, int threads) { - if (threads <= 0) threads = 1; - std::vector> spans(this->maxDepth, std::pair(-1, -1)); - - int minDepth, off[3]; - rootNode->depthAndOffset(minDepth, off); - eData.offsets.resize(this->maxDepth, -1); - int nodeCount = 0; - { - int start = rootNode->nodeData.nodeIndex, end = start; - for (int d = minDepth; d <= maxDepth; d++) { - spans[d] = std::pair(start, end + 1); - eData.offsets[d] = nodeCount - spans[d].first; - nodeCount += spans[d].second - spans[d].first; - if (d < maxDepth) { - while (start < end && !treeNodes[start]->children) start++; - while (end > start && !treeNodes[end]->children) end--; - if (start == end && !treeNodes[start]->children) break; - start = treeNodes[start]->children[0].nodeData.nodeIndex; - end = treeNodes[end]->children[7].nodeData.nodeIndex; - } - } - } - eData.eTable.resize(nodeCount); - std::vector count(threads); -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::ConstNeighborKey3 neighborKey; - neighborKey.set(maxDepth); - int offset = nodeCount * t * Cube::EDGES; - count[t] = 0; - for (int d = minDepth; d <= maxDepth; d++) { - int start = spans[d].first, end = spans[d].second, width = end - start; - for (int i = start + (width * t) / threads; i < start + (width * (t + 1)) / threads; i++) { - TreeOctNode* node = treeNodes[i]; - const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors(node, minDepth); - - for (int e = 0; e < Cube::EDGES; e++) { - bool edgeOwner = true; - int o, i, j; - Cube::FactorEdgeIndex(e, o, i, j); - int ac = Square::AntipodalCornerIndex(Square::CornerIndex(i, j)); - for (int cc = 0; cc < Square::CORNERS; cc++) { - int ii, jj, x, y, z; - Square::FactorCornerIndex(cc, ii, jj); - ii += i, jj += j; - switch (o) { - case 0: - y = ii, z = jj, x = 1; - break; - case 1: - x = ii, z = jj, y = 1; - break; - case 2: - x = ii, y = jj, z = 1; - break; - } - if (neighbors.neighbors[x][y][z] && cc < ac) { - edgeOwner = false; - break; - } - } - if (edgeOwner) { - // Set all edge indices - for (int cc = 0; cc < Square::CORNERS; cc++) { - int ii, jj, aii, ajj, x, y, z; - Square::FactorCornerIndex(cc, ii, jj); - Square::FactorCornerIndex(Square::AntipodalCornerIndex(cc), aii, ajj); - ii += i, jj += j; - switch (o) { - case 0: - y = ii, z = jj, x = 1; - break; - case 1: - x = ii, z = jj, y = 1; - break; - case 2: - x = ii, y = jj, z = 1; - break; - } - if (neighbors.neighbors[x][y][z]) - eData[neighbors.neighbors[x][y][z]][Cube::EdgeIndex(o, aii, ajj)] = count[t] + offset; - } - count[t]++; - } - } - } - } - } - eData.eCount = 0; - std::vector offsets(threads + 1); - offsets[0] = 0; - for (int t = 0; t < threads; t++) { - eData.eCount += count[t]; - offsets[t + 1] = offsets[t] + count[t]; - } - - unsigned int paralellExceptionCount = 0; -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - for (int d = minDepth; d <= maxDepth; d++) { - int start = spans[d].first, end = spans[d].second, width = end - start; - for (int i = start + (width * t) / threads; i < start + (width * (t + 1)) / threads; i++) { - for (int e = 0; e < Cube::EDGES; e++) { - int& idx = eData[treeNodes[i]][e]; - if (idx < 0) { -#pragma omp critical - { - // found unindexed edge - ++paralellExceptionCount; - } - } else { - int div = idx / (nodeCount * Cube::EDGES); - int rem = idx % (nodeCount * Cube::EDGES); - idx = rem + offsets[div]; - } - } - } - } - } - - if (paralellExceptionCount > 0) - POISSON_THROW_EXCEPTION(pcl::poisson::PoissonOpenMPException, - "Found " << paralellExceptionCount << " unindexed edges during openMP loop execution."); -} -inline int SortedTreeNodes::getMaxEdgeCount(const TreeOctNode* rootNode, int depth, int threads) const { - if (threads <= 0) threads = 1; - int res = 1 << depth; - std::vector> edgeCount(threads); - for (int t = 0; t < threads; t++) edgeCount[t].resize(res * res * res, 0); - -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - std::vector& _edgeCount = edgeCount[t]; - TreeOctNode::ConstNeighborKey3 neighborKey; - neighborKey.set(maxDepth - 1); - int start = nodeCount[depth], end = nodeCount[maxDepth], range = end - start; - for (int i = (range * t) / threads; i < (range * (t + 1)) / threads; i++) { - TreeOctNode* node = treeNodes[start + i]; - const TreeOctNode::ConstNeighbors3& neighbors = neighborKey.getNeighbors(node, depth); - int d, off[3]; - node->depthAndOffset(d, off); - - for (int e = 0; e < Cube::EDGES; e++) { - bool edgeOwner = true; - int o, i, j; - Cube::FactorEdgeIndex(e, o, i, j); - int ac = Square::AntipodalCornerIndex(Square::CornerIndex(i, j)); - for (int cc = 0; cc < Square::CORNERS; cc++) { - int ii, jj, x, y, z; - Square::FactorCornerIndex(cc, ii, jj); - ii += i, jj += j; - switch (o) { - case 0: - y = ii, z = jj, x = 1; - break; - case 1: - x = ii, z = jj, y = 1; - break; - case 2: - x = ii, y = jj, z = 1; - break; - } - if (neighbors.neighbors[x][y][z] && cc < ac) { - edgeOwner = false; - break; - } - } - if (edgeOwner) - _edgeCount[((off[0] >> (d - depth)) * res * res) + ((off[1] >> (d - depth)) * res) + - (off[2] >> (d - depth))]++; - } - } - } - int maxCount = 0; - for (int i = 0; i < res * res * res; i++) { - int c = 0; - for (int t = 0; t < threads; t++) c += edgeCount[t][i]; - maxCount = std::max(maxCount, c); - } - return maxCount; -} - - -////////////////// -// TreeNodeData // -////////////////// -inline TreeNodeData::TreeNodeData(void) { - if (UseIndex) { - nodeIndex = -1; - centerWeightContribution = 0; - } else - mcIndex = 0; - normalIndex = -1; - constraint = solution = 0; - pointIndex = -1; -} -//int TreeNodeData::UseIndex = 1; -inline TreeNodeData::~TreeNodeData(void) {} - - -//////////// -// Octree // -//////////// -template double Octree::maxMemoryUsage = 0; - - -template double Octree::MemoryUsage(void) { - double mem = 0; // double( MemoryInfo::Usage() ) / (1<<20); - if (mem > maxMemoryUsage) { - maxMemoryUsage = mem; - } - return mem; -} - -template Octree::Octree(void) { - threads = 1; - radius = 0; - width = 0; - postNormalSmooth = 0; - _constrainValues = false; -} - -template -int Octree::NonLinearSplatOrientedPoint( - TreeOctNode* node, const Point3D& position, const Point3D& normal) { - double x, dxdy, dxdydz, dx[DIMENSION][SPLAT_ORDER + 1]; - int off[3]; - TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors(node); - double width; - Point3D center; - Real w; - node->centerAndWidth(center, w); - width = w; - for (int i = 0; i < 3; i++) { -#if SPLAT_ORDER == 2 - off[i] = 0; - x = (center[i] - position[i] - width) / width; - dx[i][0] = 1.125 + 1.500 * x + 0.500 * x * x; - x = (center[i] - position[i]) / width; - dx[i][1] = 0.750 - x * x; - - dx[i][2] = 1. - dx[i][1] - dx[i][0]; -#elif SPLAT_ORDER == 1 - x = (position[i] - center[i]) / width; - if (x < 0) { - off[i] = 0; - dx[i][0] = -x; - } else { - off[i] = 1; - dx[i][0] = 1. - x; - } - dx[i][1] = 1. - dx[i][0]; -#elif SPLAT_ORDER == 0 - off[i] = 1; - dx[i][0] = 1.; -#else -# error Splat order not supported -#endif // SPLAT_ORDER - } - for (int i = off[0]; i <= off[0] + SPLAT_ORDER; i++) - for (int j = off[1]; j <= off[1] + SPLAT_ORDER; j++) { - dxdy = dx[0][i] * dx[1][j]; - for (int k = off[2]; k <= off[2] + SPLAT_ORDER; k++) - if (neighbors.neighbors[i][j][k]) { - dxdydz = dxdy * dx[2][k]; - TreeOctNode* _node = neighbors.neighbors[i][j][k]; - int idx = _node->nodeData.normalIndex; - if (idx < 0) { - Point3D n; - n[0] = n[1] = n[2] = 0; - _node->nodeData.nodeIndex = 0; - idx = _node->nodeData.normalIndex = int(normals->size()); - normals->push_back(n); - } - (*normals)[idx] += normal * Real(dxdydz); - } - } - return 0; -} -template -Real Octree::NonLinearSplatOrientedPoint(const Point3D& position, const Point3D& normal, - int splatDepth, Real samplesPerNode, int minDepth, int maxDepth) { - double dx; - Point3D n; - TreeOctNode* temp; - int cnt = 0; - double width; - Point3D myCenter; - Real myWidth; - myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5); - myWidth = Real(1.0); - - temp = &tree; - while (temp->depth() < splatDepth) { - if (!temp->children) { - fprintf(stderr, "Octree::NonLinearSplatOrientedPoint error\n"); - return -1; - } - int cIndex = TreeOctNode::CornerIndex(myCenter, position); - temp = &temp->children[cIndex]; - myWidth /= 2; - if (cIndex & 1) - myCenter[0] += myWidth / 2; - else - myCenter[0] -= myWidth / 2; - if (cIndex & 2) - myCenter[1] += myWidth / 2; - else - myCenter[1] -= myWidth / 2; - if (cIndex & 4) - myCenter[2] += myWidth / 2; - else - myCenter[2] -= myWidth / 2; - } - Real alpha, newDepth; - NonLinearGetSampleDepthAndWeight(temp, position, samplesPerNode, newDepth, alpha); - - if (newDepth < minDepth) newDepth = Real(minDepth); - if (newDepth > maxDepth) newDepth = Real(maxDepth); - int topDepth = int(ceil(newDepth)); - - dx = 1.0 - (topDepth - newDepth); - if (topDepth <= minDepth) { - topDepth = minDepth; - dx = 1; - } else if (topDepth > maxDepth) { - topDepth = maxDepth; - dx = 1; - } - while (temp->depth() > topDepth) temp = temp->parent; - while (temp->depth() < topDepth) { - if (!temp->children) temp->initChildren(); - int cIndex = TreeOctNode::CornerIndex(myCenter, position); - temp = &temp->children[cIndex]; - myWidth /= 2; - if (cIndex & 1) - myCenter[0] += myWidth / 2; - else - myCenter[0] -= myWidth / 2; - if (cIndex & 2) - myCenter[1] += myWidth / 2; - else - myCenter[1] -= myWidth / 2; - if (cIndex & 4) - myCenter[2] += myWidth / 2; - else - myCenter[2] -= myWidth / 2; - } - width = 1.0 / (1 << temp->depth()); - n = normal * alpha / Real(pow(width, 3)) * Real(dx); - NonLinearSplatOrientedPoint(temp, position, n); - if (fabs(1.0 - dx) > EPSILON) { - dx = Real(1.0 - dx); - temp = temp->parent; - width = 1.0 / (1 << temp->depth()); - - n = normal * alpha / Real(pow(width, 3)) * Real(dx); - NonLinearSplatOrientedPoint(temp, position, n); - } - return alpha; -} -template -void Octree::NonLinearGetSampleDepthAndWeight( - TreeOctNode* node, const Point3D& position, Real samplesPerNode, Real& depth, Real& weight) { - TreeOctNode* temp = node; - weight = Real(1.0) / NonLinearGetSampleWeight(temp, position); - if (weight >= samplesPerNode) - depth = Real(temp->depth() + log(weight / samplesPerNode) / log(double(1 << (DIMENSION - 1)))); - else { - Real oldAlpha, newAlpha; - oldAlpha = newAlpha = weight; - while (newAlpha < samplesPerNode && temp->parent) { - temp = temp->parent; - oldAlpha = newAlpha; - newAlpha = Real(1.0) / NonLinearGetSampleWeight(temp, position); - } - depth = Real(temp->depth() + log(newAlpha / samplesPerNode) / log(newAlpha / oldAlpha)); - } - weight = Real(pow(double(1 << (DIMENSION - 1)), -double(depth))); -} - -template Real Octree::NonLinearGetSampleWeight(TreeOctNode* node, const Point3D& position) { - Real weight = 0; - double x, dxdy, dx[DIMENSION][3]; - TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors(node); - double width; - Point3D center; - Real w; - node->centerAndWidth(center, w); - width = w; - - for (int i = 0; i < DIMENSION; i++) { - x = (center[i] - position[i] - width) / width; - dx[i][0] = 1.125 + 1.500 * x + 0.500 * x * x; - x = (center[i] - position[i]) / width; - dx[i][1] = 0.750 - x * x; - - dx[i][2] = 1.0 - dx[i][1] - dx[i][0]; - } - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) { - dxdy = dx[0][i] * dx[1][j]; - for (int k = 0; k < 3; k++) - if (neighbors.neighbors[i][j][k]) - weight += Real(dxdy * dx[2][k] * neighbors.neighbors[i][j][k]->nodeData.centerWeightContribution); - } - return Real(1.0 / weight); -} - -template -int Octree::NonLinearUpdateWeightContribution(TreeOctNode* node, const Point3D& position, Real weight) { - TreeOctNode::Neighbors3& neighbors = neighborKey.setNeighbors(node); - double x, dxdy, dx[DIMENSION][3]; - double width; - Point3D center; - Real w; - node->centerAndWidth(center, w); - width = w; - const double SAMPLE_SCALE = 1. / (0.125 * 0.125 + 0.75 * 0.75 + 0.125 * 0.125); - - for (int i = 0; i < DIMENSION; i++) { - x = (center[i] - position[i] - width) / width; - dx[i][0] = 1.125 + 1.500 * x + 0.500 * x * x; - x = (center[i] - position[i]) / width; - dx[i][1] = 0.750 - x * x; - dx[i][2] = 1. - dx[i][1] - dx[i][0]; - // Note that we are splatting along a co-dimension one manifold, so uniform point samples - // do not generate a unit sample weight. - dx[i][0] *= SAMPLE_SCALE; - } - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) { - dxdy = dx[0][i] * dx[1][j] * weight; - for (int k = 0; k < 3; k++) - if (neighbors.neighbors[i][j][k]) - neighbors.neighbors[i][j][k]->nodeData.centerWeightContribution += Real(dxdy * dx[2][k]); - } - return 0; -} - -template -template -int Octree::setTree(typename pcl::PointCloud::ConstPtr input_, int maxDepth, int minDepth, - int kernelDepth, Real samplesPerNode, Real scaleFactor, Point3D& center, Real& scale, int useConfidence, - Real constraintWeight, bool adaptiveWeights) { - _minDepth = std::min(std::max(0, minDepth), maxDepth); - _constrainValues = (constraintWeight > 0); - double pointWeightSum = 0; - Point3D min, max, position, normal, myCenter; - Real myWidth; - int i, cnt = 0; - TreeOctNode* temp; - int splatDepth = 0; - - TreeNodeData::UseIndex = 1; - neighborKey.set(maxDepth); - splatDepth = kernelDepth; - if (splatDepth < 0) splatDepth = 0; - - - tree.setFullDepth(_minDepth); - // Read through once to get the center and scale - while (cnt != input_->points.size()) { - Point3D p; - p[0] = input_->points[cnt].x; - p[1] = input_->points[cnt].y; - p[2] = input_->points[cnt].z; - - for (i = 0; i < DIMENSION; i++) { - if (!cnt || p[i] < min[i]) min[i] = p[i]; - if (!cnt || p[i] > max[i]) max[i] = p[i]; - } - cnt++; - } - - scale = std::max(max[0] - min[0], std::max(max[1] - min[1], max[2] - min[2])); - center = (max + min) / 2; - - scale *= scaleFactor; - for (i = 0; i < DIMENSION; i++) center[i] -= scale / 2; - if (splatDepth > 0) { - cnt = 0; - while (cnt != input_->points.size()) { - position[0] = input_->points[cnt].x; - position[1] = input_->points[cnt].y; - position[2] = input_->points[cnt].z; - normal[0] = input_->points[cnt].normal_x; - normal[1] = input_->points[cnt].normal_y; - normal[2] = input_->points[cnt].normal_z; - - for (i = 0; i < DIMENSION; i++) position[i] = (position[i] - center[i]) / scale; - myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5); - myWidth = Real(1.0); - for (i = 0; i < DIMENSION; i++) - if (position[i] < myCenter[i] - myWidth / 2 || position[i] > myCenter[i] + myWidth / 2) break; - if (i != DIMENSION) continue; - Real weight = Real(1.); - if (useConfidence) weight = Real(Length(normal)); - temp = &tree; - int d = 0; - while (d < splatDepth) { - NonLinearUpdateWeightContribution(temp, position, weight); - if (!temp->children) temp->initChildren(); - int cIndex = TreeOctNode::CornerIndex(myCenter, position); - temp = &temp->children[cIndex]; - myWidth /= 2; - if (cIndex & 1) - myCenter[0] += myWidth / 2; - else - myCenter[0] -= myWidth / 2; - if (cIndex & 2) - myCenter[1] += myWidth / 2; - else - myCenter[1] -= myWidth / 2; - if (cIndex & 4) - myCenter[2] += myWidth / 2; - else - myCenter[2] -= myWidth / 2; - d++; - } - NonLinearUpdateWeightContribution(temp, position, weight); - cnt++; - } - } - - normals = new std::vector>(); - cnt = 0; - while (cnt != input_->points.size()) { - position[0] = input_->points[cnt].x; - position[1] = input_->points[cnt].y; - position[2] = input_->points[cnt].z; - normal[0] = input_->points[cnt].normal_x; - normal[1] = input_->points[cnt].normal_y; - normal[2] = input_->points[cnt].normal_z; - cnt++; - for (i = 0; i < DIMENSION; i++) position[i] = (position[i] - center[i]) / scale; - myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5); - myWidth = Real(1.0); - for (i = 0; i < DIMENSION; i++) - if (position[i] < myCenter[i] - myWidth / 2 || position[i] > myCenter[i] + myWidth / 2) break; - if (i != DIMENSION) continue; - Real l = Real(Length(normal)); - if (l != l || l <= EPSILON) continue; - if (!useConfidence) normal /= l; - - l = Real(1.); - Real pointWeight = Real(1.f); - if (samplesPerNode > 0 && splatDepth) { - pointWeight = - NonLinearSplatOrientedPoint(position, normal, splatDepth, samplesPerNode, _minDepth, maxDepth); - } else { - Real alpha = 1; - temp = &tree; - int d = 0; - if (splatDepth) { - while (d < splatDepth) { - int cIndex = TreeOctNode::CornerIndex(myCenter, position); - temp = &temp->children[cIndex]; - myWidth /= 2; - if (cIndex & 1) - myCenter[0] += myWidth / 2; - else - myCenter[0] -= myWidth / 2; - if (cIndex & 2) - myCenter[1] += myWidth / 2; - else - myCenter[1] -= myWidth / 2; - if (cIndex & 4) - myCenter[2] += myWidth / 2; - else - myCenter[2] -= myWidth / 2; - d++; - } - alpha = NonLinearGetSampleWeight(temp, position); - } - for (i = 0; i < DIMENSION; i++) normal[i] *= alpha; - while (d < maxDepth) { - if (!temp->children) { - temp->initChildren(); - } - int cIndex = TreeOctNode::CornerIndex(myCenter, position); - temp = &temp->children[cIndex]; - myWidth /= 2; - if (cIndex & 1) - myCenter[0] += myWidth / 2; - else - myCenter[0] -= myWidth / 2; - if (cIndex & 2) - myCenter[1] += myWidth / 2; - else - myCenter[1] -= myWidth / 2; - if (cIndex & 4) - myCenter[2] += myWidth / 2; - else - myCenter[2] -= myWidth / 2; - d++; - } - NonLinearSplatOrientedPoint(temp, position, normal); - pointWeight = alpha; - } - pointWeight = 1; - pointWeightSum += pointWeight; - if (_constrainValues) { - int d = 0; - TreeOctNode* temp = &tree; - myCenter[0] = myCenter[1] = myCenter[2] = Real(0.5); - myWidth = Real(1.0); - while (1) { - int idx = temp->nodeData.pointIndex; - if (idx == -1) { - Point3D p; - p[0] = p[1] = p[2] = 0; - idx = int(_points.size()); - _points.push_back(PointData(position * pointWeight, pointWeight)); - temp->nodeData.pointIndex = idx; - } else { - _points[idx].weight += pointWeight; - _points[idx].position += position * pointWeight; - } - - int cIndex = TreeOctNode::CornerIndex(myCenter, position); - if (!temp->children) break; - temp = &temp->children[cIndex]; - myWidth /= 2; - if (cIndex & 1) - myCenter[0] += myWidth / 2; - else - myCenter[0] -= myWidth / 2; - if (cIndex & 2) - myCenter[1] += myWidth / 2; - else - myCenter[1] -= myWidth / 2; - if (cIndex & 4) - myCenter[2] += myWidth / 2; - else - myCenter[2] -= myWidth / 2; - d++; - } - } - } - - - if (_constrainValues) - for (TreeOctNode* n = tree.nextNode(); n; n = tree.nextNode(n)) - if (n->nodeData.pointIndex != -1) { - int idx = n->nodeData.pointIndex; - _points[idx].position /= _points[idx].weight; - if (adaptiveWeights) - _points[idx].weight *= (1 << n->d); - else - _points[idx].weight *= (1 << maxDepth); - _points[idx].weight *= Real(constraintWeight / pointWeightSum); - } -#if FORCE_NEUMANN_FIELD - for (TreeOctNode* node = tree.nextNode(); node; node = tree.nextNode(node)) { - int d, off[3], res; - node->depthAndOffset(d, off); - res = 1 << d; - if (node->nodeData.normalIndex < 0) continue; - Point3D& normal = (*normals)[node->nodeData.normalIndex]; - for (int d = 0; d < 3; d++) - if (off[d] == 0 || off[d] == res - 1) normal[d] = 0; - } -#endif // FORCE_NEUMANN_FIELD - _sNodes.set(tree); - - - return cnt; -} - - -template void Octree::setBSplineData(int maxDepth, Real normalSmooth, bool reflectBoundary) { - radius = 0.5 + 0.5 * Degree; - width = int(double(radius + 0.5 - EPSILON) * 2); - if (normalSmooth > 0) postNormalSmooth = normalSmooth; - fData.set(maxDepth, true, reflectBoundary); -} - -template void Octree::finalize(void) { - int maxDepth = tree.maxDepth(); - TreeOctNode::NeighborKey5 nKey; - nKey.set(maxDepth); - for (int d = maxDepth; d > 0; d--) - for (TreeOctNode* node = tree.nextNode(); node; node = tree.nextNode(node)) - if (node->d == d) { - int xStart = 0, xEnd = 5, yStart = 0, yEnd = 5, zStart = 0, zEnd = 5; - int c = int(node - node->parent->children); - int x, y, z; - Cube::FactorCornerIndex(c, x, y, z); - if (x) - xStart = 1; - else - xEnd = 4; - if (y) - yStart = 1; - else - yEnd = 4; - if (z) - zStart = 1; - else - zEnd = 4; - nKey.setNeighbors(node->parent, xStart, xEnd, yStart, yEnd, zStart, zEnd); - } - _sNodes.set(tree); - MemoryUsage(); -} -template -Real Octree::GetValue(const PointInfo points[3][3][3], const bool hasPoints[3][3], const int d[3]) const { - double v = 0.; - const int min[] = {std::max(0, d[0] + 0), std::max(0, d[1] + 0), std::max(0, d[2] + 0)}; - const int max[] = {std::min(2, d[0] + 2), std::min(2, d[1] + 2), std::min(2, d[2] + 2)}; - for (int i = min[0]; i <= max[0]; i++) - for (int j = min[1]; j <= max[1]; j++) { - if (!hasPoints[i][j]) continue; - const PointInfo* pInfo = points[i][j]; - int ii = -d[0] + i; - int jj = -d[1] + j; - for (int k = min[2]; k <= max[2]; k++) - if (pInfo[k].weightedValue) - v += pInfo[k].splineValues[0][ii] * pInfo[k].splineValues[1][jj] * - pInfo[k].splineValues[2][-d[2] + k]; - } - return Real(v); -} -template Real Octree::GetLaplacian(const int idx[DIMENSION]) const { - return Real(fData.vvDotTable[idx[0]] * fData.vvDotTable[idx[1]] * fData.vvDotTable[idx[2]] * - (fData.ddDotTable[idx[0]] + fData.ddDotTable[idx[1]] + fData.ddDotTable[idx[2]])); -} -template Real Octree::GetLaplacian(const TreeOctNode* node1, const TreeOctNode* node2) const { - int symIndex[] = {BSplineData::SymmetricIndex(node1->off[0], node2->off[0]), - BSplineData::SymmetricIndex(node1->off[1], node2->off[1]), - BSplineData::SymmetricIndex(node1->off[2], node2->off[2])}; - return GetLaplacian(symIndex); -} -template -Real Octree::GetDivergence( - const TreeOctNode* node1, const TreeOctNode* node2, const Point3D& normal1) const { - int symIndex[] = { - BSplineData::SymmetricIndex(node1->off[0], node2->off[0]), - BSplineData::SymmetricIndex(node1->off[1], node2->off[1]), - BSplineData::SymmetricIndex(node1->off[2], node2->off[2]), - }; - int aSymIndex[] = { -#if GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the vector-field with the gradient of the basis function - fData.Index(node2->off[0], node1->off[0]), - fData.Index(node2->off[1], node1->off[1]), - fData.Index(node2->off[2], node1->off[2]) -#else // !GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the divergence of the vector-field with the basis function - fData.Index(node1->off[0], node2->off[0]), - fData.Index(node1->off[1], node2->off[1]), - fData.Index(node1->off[2], node2->off[2]) -#endif // GRADIENT_DOMAIN_SOLUTION - }; - double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]]; -#if GRADIENT_DOMAIN_SOLUTION - return Real(dot * (fData.dvDotTable[aSymIndex[0]] * normal1[0] + fData.dvDotTable[aSymIndex[1]] * normal1[1] + - fData.dvDotTable[aSymIndex[2]] * normal1[2])); -#else // !GRADIENT_DOMAIN_SOLUTION - return -Real(dot * (fData.dvDotTable[aSymIndex[0]] * normal1[0] + fData.dvDotTable[aSymIndex[1]] * normal1[1] + - fData.dvDotTable[aSymIndex[2]] * normal1[2])); -#endif // GRADIENT_DOMAIN_SOLUTION -} -template -Real Octree::GetDivergenceMinusLaplacian( - const TreeOctNode* node1, const TreeOctNode* node2, Real value1, const Point3D& normal1) const { - int symIndex[] = {BSplineData::SymmetricIndex(node1->off[0], node2->off[0]), - BSplineData::SymmetricIndex(node1->off[1], node2->off[1]), - BSplineData::SymmetricIndex(node1->off[2], node2->off[2])}; - int aSymIndex[] = { -#if GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the vector-field with the gradient of the basis function - fData.Index(node2->off[0], node1->off[0]), - fData.Index(node2->off[1], node1->off[1]), - fData.Index(node2->off[2], node1->off[2]) -#else // !GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the divergence of the vector-field with the basis function - fData.Index(node1->off[0], node2->off[0]), - fData.Index(node1->off[1], node2->off[1]), - fData.Index(node1->off[2], node2->off[2]) -#endif // GRADIENT_DOMAIN_SOLUTION - }; - double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]]; - return Real( - dot * - ( -#if GRADIENT_DOMAIN_SOLUTION - -(fData.ddDotTable[symIndex[0]] + fData.ddDotTable[symIndex[1]] + fData.ddDotTable[symIndex[2]]) * value1 + - (fData.dvDotTable[aSymIndex[0]] * normal1[0] + fData.dvDotTable[aSymIndex[1]] * normal1[1] + - fData.dvDotTable[aSymIndex[2]] * normal1[2]) -#else // !GRADIENT_DOMAIN_SOLUTION - -(fData.ddDotTable[symIndex[0]] + fData.ddDotTable[symIndex[1]] + fData.ddDotTable[symIndex[2]]) * value1 - - (fData.dvDotTable[aSymIndex[0]] * normal1[0] + fData.dvDotTable[aSymIndex[1]] * normal1[1] + - fData.dvDotTable[aSymIndex[2]] * normal1[2]) -#endif // GRADIENT_DOMAIN_SOLUTION - )); -} -template -void Octree::SetMatrixRowBounds(const TreeOctNode* node, int rDepth, const int rOff[3], int& xStart, int& xEnd, - int& yStart, int& yEnd, int& zStart, int& zEnd) const { - xStart = 0, yStart = 0, zStart = 0, xEnd = 5, yEnd = 5, zEnd = 5; - int depth, off[3]; - node->depthAndOffset(depth, off); - int width = 1 << (depth - rDepth); - off[0] -= rOff[0] << (depth - rDepth), off[1] -= rOff[1] << (depth - rDepth), off[2] -= rOff[2] << (depth - rDepth); - if (off[0] < 0) xStart = -off[0]; - if (off[1] < 0) yStart = -off[1]; - if (off[2] < 0) zStart = -off[2]; - if (off[0] >= width) xEnd = 4 - (off[0] - width); - if (off[1] >= width) yEnd = 4 - (off[1] - width); - if (off[2] >= width) zEnd = 4 - (off[2] - width); -} -template -int Octree::GetMatrixRowSize(const OctNode::Neighbors5& neighbors5) const { - return GetMatrixRowSize(neighbors5, 0, 5, 0, 5, 0, 5); -} -template -int Octree::GetMatrixRowSize(const OctNode::Neighbors5& neighbors5, int xStart, int xEnd, - int yStart, int yEnd, int zStart, int zEnd) const { - int count = 0; - for (int x = xStart; x <= 2; x++) - for (int y = yStart; y < yEnd; y++) - if (x == 2 && y > 2) - continue; - else - for (int z = zStart; z < zEnd; z++) - if (x == 2 && y == 2 && z > 2) - continue; - else if (neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex >= 0) - count++; - return count; -} -template -int Octree::SetMatrixRow(const OctNode::Neighbors5& neighbors5, MatrixEntry* row, - int offset, const double stencil[5][5][5]) const { - return SetMatrixRow(neighbors5, row, offset, stencil, 0, 5, 0, 5, 0, 5); -} -template -int Octree::SetMatrixRow(const OctNode::Neighbors5& neighbors5, MatrixEntry* row, - int offset, const double stencil[5][5][5], int xStart, int xEnd, int yStart, int yEnd, int zStart, int zEnd) const { - bool hasPoints[3][3]; - Real diagonal = 0; - PointInfo samples[3][3][3]; - - int count = 0; - const TreeOctNode* node = neighbors5.neighbors[2][2][2]; - int index[] = {int(node->off[0]), int(node->off[1]), int(node->off[2])}; - - if (_constrainValues) { - int d, idx[3]; - node->depthAndOffset(d, idx); - idx[0] = BinaryNode::CenterIndex(d, idx[0]); - idx[1] = BinaryNode::CenterIndex(d, idx[1]); - idx[2] = BinaryNode::CenterIndex(d, idx[2]); - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - hasPoints[j][k] = false; - for (int l = 0; l < 3; l++) { - const TreeOctNode* _node = neighbors5.neighbors[j + 1][k + 1][l + 1]; - if (_node && _node->nodeData.pointIndex != -1) { - const PointData& pData = _points[_node->nodeData.pointIndex]; - PointInfo& pointInfo = samples[j][k][l]; - Real weight = pData.weight; - Point3D p = pData.position; - for (int s = 0; s < 3; s++) { - pointInfo.splineValues[0][s] = float(fData.baseBSplines[idx[0] + j - s][s](p[0])); - pointInfo.splineValues[1][s] = float(fData.baseBSplines[idx[1] + k - s][s](p[1])); - pointInfo.splineValues[2][s] = float(fData.baseBSplines[idx[2] + l - s][s](p[2])); - } - float value = - pointInfo.splineValues[0][j] * pointInfo.splineValues[1][k] * pointInfo.splineValues[2][l]; - diagonal += value * value * weight; - pointInfo.weightedValue = value * weight; - for (int s = 0; s < 3; s++) pointInfo.splineValues[0][s] *= pointInfo.weightedValue; - hasPoints[j][k] = true; - } else - samples[j][k][l].weightedValue = 0; - } - } - } - - bool isInterior; - int d, off[3]; - neighbors5.neighbors[2][2][2]->depthAndOffset(d, off); - int mn = 2, mx = (1 << d) - 2; - isInterior = (off[0] >= mn && off[0] < mx && off[1] >= mn && off[1] < mx && off[2] >= mn && off[2] < mx); - for (int x = xStart; x <= 2; x++) - for (int y = yStart; y < yEnd; y++) - if (x == 2 && y > 2) - continue; - else - for (int z = zStart; z < zEnd; z++) - if (x == 2 && y == 2 && z > 2) - continue; - else if (neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex >= 0) { - const TreeOctNode* _node = neighbors5.neighbors[x][y][z]; - int _index[] = {int(_node->off[0]), int(_node->off[1]), int(_node->off[2])}; - Real temp; - if (isInterior) - temp = Real(stencil[x][y][z]); - else - temp = GetLaplacian(node, _node); - if (_constrainValues) { - int _d[] = {_index[0] - index[0], _index[1] - index[1], _index[2] - index[2]}; - if (x == 2 && y == 2 && z == 2) - temp += diagonal; - else - temp += GetValue(samples, hasPoints, _d); - } - if (x == 2 && y == 2 && z == 2) temp /= 2; - if (fabs(temp) > MATRIX_ENTRY_EPSILON) { - row[count].N = _node->nodeData.nodeIndex - offset; - row[count].Value = temp; - count++; - } - } - return count; -} -template -void Octree::SetDivergenceStencil(int depth, Point3D* stencil, bool scatter) const { - int offset[] = {2, 2, 2}; - short d, off[3]; - TreeOctNode::Index(depth, offset, d, off); - int index1[3], index2[3]; - if (scatter) - index2[0] = int(off[0]), index2[1] = int(off[1]), index2[2] = int(off[2]); - else - index1[0] = int(off[0]), index1[1] = int(off[1]), index1[2] = int(off[2]); - for (int x = 0; x < 5; x++) - for (int y = 0; y < 5; y++) - for (int z = 0; z < 5; z++) { - int _offset[] = {x, y, z}; - TreeOctNode::Index(depth, _offset, d, off); - if (scatter) - index1[0] = int(off[0]), index1[1] = int(off[1]), index1[2] = int(off[2]); - else - index2[0] = int(off[0]), index2[1] = int(off[1]), index2[2] = int(off[2]); - int symIndex[] = { - BSplineData::SymmetricIndex(index1[0], index2[0]), - BSplineData::SymmetricIndex(index1[1], index2[1]), - BSplineData::SymmetricIndex(index1[2], index2[2]), - }; - int aSymIndex[] = { -#if GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the vector-field with the gradient of the basis function - fData.Index(index1[0], index2[0]), - fData.Index(index1[1], index2[1]), - fData.Index(index1[2], index2[2]) -#else // !GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the divergence of the vector-field with the basis function - fData.Index(index2[0], index1[0]), - fData.Index(index2[1], index1[1]), - fData.Index(index2[2], index1[2]) -#endif // GRADIENT_DOMAIN_SOLUTION - }; - - double dot = - fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * fData.vvDotTable[symIndex[2]]; -#if GRADIENT_DOMAIN_SOLUTION - Point3D temp; - temp[0] = fData.dvDotTable[aSymIndex[0]] * dot; - temp[1] = fData.dvDotTable[aSymIndex[1]] * dot; - temp[2] = fData.dvDotTable[aSymIndex[2]] * dot; - stencil[25 * x + 5 * y + z] = temp; - // stencil[x][y][z][0] = fData.dvDotTable[aSymIndex[0]] * dot; - // stencil[x][y][z][1] = fData.dvDotTable[aSymIndex[1]] * dot; - // stencil[x][y][z][2] = fData.dvDotTable[aSymIndex[2]] * dot; -#else // !GRADIENT_DOMAIN_SOLUTION - Point3D temp; - temp[0] = -fData.dvDotTable[aSymIndex[0]] * dot; - temp[1] = -fData.dvDotTable[aSymIndex[1]] * dot; - temp[2] = -fData.dvDotTable[aSymIndex[2]] * dot; - stencil[25 * x + 5 * y + z] = temp; - // stencil[x][y][z][0] = -fData.dvDotTable[aSymIndex[0]] * dot; - // stencil[x][y][z][1] = -fData.dvDotTable[aSymIndex[1]] * dot; - // stencil[x][y][z][2] = -fData.dvDotTable[aSymIndex[2]] * dot; -#endif // GRADIENT_DOMAIN_SOLUTION - } -} -template void Octree::SetLaplacianStencil(int depth, double stencil[5][5][5]) const { - int offset[] = {2, 2, 2}; - short d, off[3]; - TreeOctNode::Index(depth, offset, d, off); - int index[] = {int(off[0]), int(off[1]), int(off[2])}; - for (int x = 0; x < 5; x++) - for (int y = 0; y < 5; y++) - for (int z = 0; z < 5; z++) { - int _offset[] = {x, y, z}; - short _d, _off[3]; - TreeOctNode::Index(depth, _offset, _d, _off); - int _index[] = {int(_off[0]), int(_off[1]), int(_off[2])}; - int symIndex[3]; - symIndex[0] = BSplineData::SymmetricIndex(index[0], _index[0]); - symIndex[1] = BSplineData::SymmetricIndex(index[1], _index[1]); - symIndex[2] = BSplineData::SymmetricIndex(index[2], _index[2]); - stencil[x][y][z] = GetLaplacian(symIndex); - } -} -template void Octree::SetLaplacianStencils(int depth, Stencil stencils[2][2][2]) const { - if (depth <= 1) return; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) - for (int k = 0; k < 2; k++) { - short d, off[3]; - int offset[] = {4 + i, 4 + j, 4 + k}; - TreeOctNode::Index(depth, offset, d, off); - int index[] = {int(off[0]), int(off[1]), int(off[2])}; - for (int x = 0; x < 5; x++) - for (int y = 0; y < 5; y++) - for (int z = 0; z < 5; z++) { - int _offset[] = {x, y, z}; - short _d, _off[3]; - TreeOctNode::Index(depth - 1, _offset, _d, _off); - int _index[] = {int(_off[0]), int(_off[1]), int(_off[2])}; - int symIndex[3]; - symIndex[0] = BSplineData::SymmetricIndex(index[0], _index[0]); - symIndex[1] = BSplineData::SymmetricIndex(index[1], _index[1]); - symIndex[2] = BSplineData::SymmetricIndex(index[2], _index[2]); - stencils[i][j][k].values[x][y][z] = GetLaplacian(symIndex); - } - } -} -template -void Octree::SetDivergenceStencils( - int depth, Stencil, 5> stencils[2][2][2], bool scatter) const { - if (depth <= 1) return; - int index1[3], index2[3]; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) - for (int k = 0; k < 2; k++) { - short d, off[3]; - int offset[] = {4 + i, 4 + j, 4 + k}; - TreeOctNode::Index(depth, offset, d, off); - if (scatter) - index2[0] = int(off[0]), index2[1] = int(off[1]), index2[2] = int(off[2]); - else - index1[0] = int(off[0]), index1[1] = int(off[1]), index1[2] = int(off[2]); - for (int x = 0; x < 5; x++) - for (int y = 0; y < 5; y++) - for (int z = 0; z < 5; z++) { - int _offset[] = {x, y, z}; - TreeOctNode::Index(depth - 1, _offset, d, off); - if (scatter) - index1[0] = int(off[0]), index1[1] = int(off[1]), index1[2] = int(off[2]); - else - index2[0] = int(off[0]), index2[1] = int(off[1]), index2[2] = int(off[2]); - - int symIndex[] = { - BSplineData::SymmetricIndex(index1[0], index2[0]), - BSplineData::SymmetricIndex(index1[1], index2[1]), - BSplineData::SymmetricIndex(index1[2], index2[2]), - }; - int aSymIndex[] = { -#if GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the vector-field with the gradient of the basis function - fData.Index(index1[0], index2[0]), - fData.Index(index1[1], index2[1]), - fData.Index(index1[2], index2[2]) -#else // !GRADIENT_DOMAIN_SOLUTION - // Take the dot-product of the divergence of the vector-field with the basis function - fData.Index(index2[0], index1[0]), - fData.Index(index2[1], index1[1]), - fData.Index(index2[2], index1[2]) -#endif // GRADIENT_DOMAIN_SOLUTION - }; - double dot = fData.vvDotTable[symIndex[0]] * fData.vvDotTable[symIndex[1]] * - fData.vvDotTable[symIndex[2]]; -#if GRADIENT_DOMAIN_SOLUTION - stencils[i][j][k].values[x][y][z][0] = fData.dvDotTable[aSymIndex[0]] * dot; - stencils[i][j][k].values[x][y][z][1] = fData.dvDotTable[aSymIndex[1]] * dot; - stencils[i][j][k].values[x][y][z][2] = fData.dvDotTable[aSymIndex[2]] * dot; -#else // !GRADIENT_DOMAIN_SOLUTION - stencils[i][j][k].values[x][y][z][0] = -fData.dvDotTable[aSymIndex[0]] * dot; - stencils[i][j][k].values[x][y][z][1] = -fData.dvDotTable[aSymIndex[1]] * dot; - stencils[i][j][k].values[x][y][z][2] = -fData.dvDotTable[aSymIndex[2]] * dot; -#endif // GRADIENT_DOMAIN_SOLUTION - } - } -} -template -void Octree::SetEvaluationStencils( - int depth, Stencil stencil1[8], Stencil stencil2[8][8]) const { - if (depth > 2) { - int idx[3]; - int off[] = {2, 2, 2}; - for (int c = 0; c < 8; c++) { - VertexData::CornerIndex(depth, off, c, fData.depth, idx); - idx[0] *= fData.functionCount, idx[1] *= fData.functionCount, idx[2] *= fData.functionCount; - for (int x = 0; x < 3; x++) - for (int y = 0; y < 3; y++) - for (int z = 0; z < 3; z++) { - short _d, _off[3]; - int _offset[] = {x + 1, y + 1, z + 1}; - TreeOctNode::Index(depth, _offset, _d, _off); - stencil1[c].values[x][y][z] = fData.valueTables[idx[0] + int(_off[0])] * - fData.valueTables[idx[1] + int(_off[1])] * - fData.valueTables[idx[2] + int(_off[2])]; - } - } - } - if (depth > 3) - for (int _c = 0; _c < 8; _c++) { - int idx[3]; - int _cx, _cy, _cz; - Cube::FactorCornerIndex(_c, _cx, _cy, _cz); - int off[] = {4 + _cx, 4 + _cy, 4 + _cz}; - for (int c = 0; c < 8; c++) { - VertexData::CornerIndex(depth, off, c, fData.depth, idx); - idx[0] *= fData.functionCount, idx[1] *= fData.functionCount, idx[2] *= fData.functionCount; - for (int x = 0; x < 3; x++) - for (int y = 0; y < 3; y++) - for (int z = 0; z < 3; z++) { - short _d, _off[3]; - int _offset[] = {x + 1, y + 1, z + 1}; - TreeOctNode::Index(depth - 1, _offset, _d, _off); - stencil2[_c][c].values[x][y][z] = fData.valueTables[idx[0] + int(_off[0])] * - fData.valueTables[idx[1] + int(_off[1])] * - fData.valueTables[idx[2] + int(_off[2])]; - } - } - } -} -template -void Octree::UpdateCoarserSupportBounds( - const TreeOctNode* node, int& startX, int& endX, int& startY, int& endY, int& startZ, int& endZ) { - if (node->parent) { - int x, y, z, c = int(node - node->parent->children); - Cube::FactorCornerIndex(c, x, y, z); - if (x == 0) - endX = 4; - else - startX = 1; - if (y == 0) - endY = 4; - else - startY = 1; - if (z == 0) - endZ = 4; - else - startZ = 1; - } -} - -template -void Octree::UpdateConstraintsFromCoarser(const OctNode::NeighborKey5& neighborKey5, - TreeOctNode* node, Real* metSolution, const Stencil& lapStencil) const { - bool isInterior; - { - int d, off[3]; - node->depthAndOffset(d, off); - int mn = 4, mx = (1 << d) - 4; - isInterior = (off[0] >= mn && off[0] < mx && off[1] >= mn && off[1] < mx && off[2] >= mn && off[2] < mx); - } - Real constraint = Real(0); - int depth = node->depth(); - if (depth <= _minDepth) return; - int i = node->nodeData.nodeIndex; - // Offset the constraints using the solution from lower resolutions. - int startX = 0, endX = 5, startY = 0, endY = 5, startZ = 0, endZ = 5; - UpdateCoarserSupportBounds(node, startX, endX, startY, endY, startZ, endZ); - - const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth - 1]; - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) - if (neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.nodeIndex >= 0) { - const TreeOctNode* _node = neighbors5.neighbors[x][y][z]; - Real _solution = metSolution[_node->nodeData.nodeIndex]; - { - if (isInterior) - node->nodeData.constraint -= Real(lapStencil.values[x][y][z] * _solution); - else - node->nodeData.constraint -= GetLaplacian(_node, node) * _solution; - } - } - if (_constrainValues) { - int d, idx[3]; - node->depthAndOffset(d, idx); - idx[0] = BinaryNode::CenterIndex(d, idx[0]); - idx[1] = BinaryNode::CenterIndex(d, idx[1]); - idx[2] = BinaryNode::CenterIndex(d, idx[2]); - const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth]; - for (int x = 1; x < 4; x++) - for (int y = 1; y < 4; y++) - for (int z = 1; z < 4; z++) - if (neighbors5.neighbors[x][y][z] && neighbors5.neighbors[x][y][z]->nodeData.pointIndex != -1) { - const PointData& pData = _points[neighbors5.neighbors[x][y][z]->nodeData.pointIndex]; - Real pointValue = pData.value; - Point3D p = pData.position; - node->nodeData.constraint -= - Real(fData.baseBSplines[idx[0]][x - 1](p[0]) * fData.baseBSplines[idx[1]][y - 1](p[1]) * - fData.baseBSplines[idx[2]][z - 1](p[2]) * pointValue); - } - } -} -struct UpSampleData { - int start; - double v[2]; - UpSampleData(void) { start = 0, v[0] = v[1] = 0.; } - UpSampleData(int s, double v1, double v2) { start = s, v[0] = v1, v[1] = v2; } -}; -template -void Octree::UpSampleCoarserSolution(int depth, const SortedTreeNodes& sNodes, Vector& Solution) const { - int start = sNodes.nodeCount[depth], end = sNodes.nodeCount[depth + 1], range = end - start; - Solution.Resize(range); - if (!depth) - return; - else if (depth == 1) - for (int i = start; i < end; i++) Solution[i - start] += sNodes.treeNodes[0]->nodeData.solution; - else { - // For every node at the current depth -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey3 neighborKey; - neighborKey.set(depth); - for (int i = start + (range * t) / threads; i < start + (range * (t + 1)) / threads; i++) { - int d, off[3]; - UpSampleData usData[3]; - sNodes.treeNodes[i]->depthAndOffset(d, off); - for (int d = 0; d < 3; d++) { - if (off[d] == 0) - usData[d] = UpSampleData(1, 1.00, 0.00); - else if (off[d] + 1 == (1 << depth)) - usData[d] = UpSampleData(0, 0.00, 1.00); - else if (off[d] % 2) - usData[d] = UpSampleData(1, 0.75, 0.25); - else - usData[d] = UpSampleData(0, 0.25, 0.75); - } - neighborKey.getNeighbors(sNodes.treeNodes[i]); - for (int ii = 0; ii < 2; ii++) { - int _ii = ii + usData[0].start; - double dx = usData[0].v[ii]; - for (int jj = 0; jj < 2; jj++) { - int _jj = jj + usData[1].start; - double dxy = dx * usData[1].v[jj]; - for (int kk = 0; kk < 2; kk++) { - int _kk = kk + usData[2].start; - double dxyz = dxy * usData[2].v[kk]; - Solution[i - start] += Real( - neighborKey.neighbors[depth - 1].neighbors[_ii][_jj][_kk]->nodeData.solution * dxyz); - } - } - } - } - } - } - // Clear the coarser solution - start = sNodes.nodeCount[depth - 1], end = sNodes.nodeCount[depth], range = end - start; -#pragma omp parallel for num_threads(threads) - for (int i = start; i < end; i++) sNodes.treeNodes[i]->nodeData.solution = Real(0.); -} -template void Octree::DownSampleFinerConstraints(int depth, SortedTreeNodes& sNodes) const { - if (!depth) return; -#pragma omp parallel for num_threads(threads) - for (int i = sNodes.nodeCount[depth - 1]; i < sNodes.nodeCount[depth]; i++) - sNodes.treeNodes[i]->nodeData.constraint = Real(0); - - if (depth == 1) { - sNodes.treeNodes[0]->nodeData.constraint = Real(0); - for (int i = sNodes.nodeCount[depth]; i < sNodes.nodeCount[depth + 1]; i++) - sNodes.treeNodes[0]->nodeData.constraint += sNodes.treeNodes[i]->nodeData.constraint; - return; - } - std::vector> constraints(threads); - for (int t = 0; t < threads; t++) - constraints[t].Resize(sNodes.nodeCount[depth] - sNodes.nodeCount[depth - 1]), constraints[t].SetZero(); - int start = sNodes.nodeCount[depth], end = sNodes.nodeCount[depth + 1], range = end - start; - int lStart = sNodes.nodeCount[depth - 1], lEnd = sNodes.nodeCount[depth]; - // For every node at the current depth -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey3 neighborKey; - neighborKey.set(depth); - for (int i = start + (range * t) / threads; i < start + (range * (t + 1)) / threads; i++) { - int d, off[3]; - UpSampleData usData[3]; - sNodes.treeNodes[i]->depthAndOffset(d, off); - for (int d = 0; d < 3; d++) { - if (off[d] == 0) - usData[d] = UpSampleData(1, 1.00, 0.00); - else if (off[d] + 1 == (1 << depth)) - usData[d] = UpSampleData(0, 0.00, 1.00); - else if (off[d] % 2) - usData[d] = UpSampleData(1, 0.75, 0.25); - else - usData[d] = UpSampleData(0, 0.25, 0.75); - } - neighborKey.getNeighbors(sNodes.treeNodes[i]); - TreeOctNode::Neighbors3& neighbors = neighborKey.neighbors[depth - 1]; - for (int ii = 0; ii < 2; ii++) { - int _ii = ii + usData[0].start; - double dx = usData[0].v[ii]; - for (int jj = 0; jj < 2; jj++) { - int _jj = jj + usData[1].start; - double dxy = dx * usData[1].v[jj]; - for (int kk = 0; kk < 2; kk++) { - int _kk = kk + usData[2].start; - double dxyz = dxy * usData[2].v[kk]; - constraints[t][neighbors.neighbors[_ii][_jj][_kk]->nodeData.nodeIndex - lStart] += - sNodes.treeNodes[i]->nodeData.constraint * dxyz; - } - } - } - } - } -#pragma omp parallel for num_threads(threads) - for (int i = lStart; i < lEnd; i++) { - Real cSum = Real(0.); - for (int t = 0; t < threads; t++) cSum += constraints[t][i - lStart]; - sNodes.treeNodes[i]->nodeData.constraint += cSum; - } -} -template -template -void Octree::DownSample(int depth, const SortedTreeNodes& sNodes, C* constraints) const { - if (depth == 0) return; - if (depth == 1) { - for (int i = sNodes.nodeCount[1]; i < sNodes.nodeCount[2]; i++) constraints[0] += constraints[i]; - return; - } - std::vector> _constraints(threads); - for (int t = 0; t < threads; t++) _constraints[t].Resize(sNodes.nodeCount[depth] - sNodes.nodeCount[depth - 1]); - int start = sNodes.nodeCount[depth], end = sNodes.nodeCount[depth + 1], range = end - start, - lStart = sNodes.nodeCount[depth - 1], lEnd = sNodes.nodeCount[depth]; - // For every node at the current depth -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey3 neighborKey; - neighborKey.set(depth); - for (int i = start + (range * t) / threads; i < start + (range * (t + 1)) / threads; i++) { - int d, off[3]; - UpSampleData usData[3]; - sNodes.treeNodes[i]->depthAndOffset(d, off); - for (int d = 0; d < 3; d++) { - if (off[d] == 0) - usData[d] = UpSampleData(1, 1.00, 0.00); - else if (off[d] + 1 == (1 << depth)) - usData[d] = UpSampleData(0, 0.00, 1.00); - else if (off[d] % 2) - usData[d] = UpSampleData(1, 0.75, 0.25); - else - usData[d] = UpSampleData(0, 0.25, 0.75); - } - TreeOctNode::Neighbors3& neighbors = neighborKey.getNeighbors(sNodes.treeNodes[i]->parent); - C c = constraints[i]; - for (int ii = 0; ii < 2; ii++) { - int _ii = ii + usData[0].start; - C cx = C(c * usData[0].v[ii]); - for (int jj = 0; jj < 2; jj++) { - int _jj = jj + usData[1].start; - C cxy = C(cx * usData[1].v[jj]); - for (int kk = 0; kk < 2; kk++) { - int _kk = kk + usData[2].start; - if (neighbors.neighbors[_ii][_jj][_kk]) - _constraints[t][neighbors.neighbors[_ii][_jj][_kk]->nodeData.nodeIndex - lStart] += - C(cxy * usData[2].v[kk]); - } - } - } - } - } -#pragma omp parallel for num_threads(threads) - for (int i = lStart; i < lEnd; i++) { - C cSum = C(0); - for (int t = 0; t < threads; t++) cSum += _constraints[t][i - lStart]; - constraints[i] += cSum; - } -} -template -template -void Octree::UpSample(int depth, const SortedTreeNodes& sNodes, C* coefficients) const { - if (depth == 0) - return; - else if (depth == 1) { - for (int i = sNodes.nodeCount[1]; i < sNodes.nodeCount[2]; i++) coefficients[i] += coefficients[0]; - return; - } - - int start = sNodes.nodeCount[depth], end = sNodes.nodeCount[depth + 1], range = end - start; - // For every node at the current depth -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey3 neighborKey; - neighborKey.set(depth - 1); - for (int i = start + (range * t) / threads; i < start + (range * (t + 1)) / threads; i++) { - TreeOctNode* node = sNodes.treeNodes[i]; - int d, off[3]; - UpSampleData usData[3]; - node->depthAndOffset(d, off); - for (int d = 0; d < 3; d++) { - if (off[d] == 0) - usData[d] = UpSampleData(1, 1.00, 0.00); - else if (off[d] + 1 == (1 << depth)) - usData[d] = UpSampleData(0, 0.00, 1.00); - else if (off[d] % 2) - usData[d] = UpSampleData(1, 0.75, 0.25); - else - usData[d] = UpSampleData(0, 0.25, 0.75); - } - TreeOctNode::Neighbors3& neighbors = neighborKey.getNeighbors(node->parent); - for (int ii = 0; ii < 2; ii++) { - int _ii = ii + usData[0].start; - double dx = usData[0].v[ii]; - for (int jj = 0; jj < 2; jj++) { - int _jj = jj + usData[1].start; - double dxy = dx * usData[1].v[jj]; - for (int kk = 0; kk < 2; kk++) { - int _kk = kk + usData[2].start; - if (neighbors.neighbors[_ii][_jj][_kk]) { - double dxyz = dxy * usData[2].v[kk]; - int _i = neighbors.neighbors[_ii][_jj][_kk]->nodeData.nodeIndex; - coefficients[i] += coefficients[_i] * Real(dxyz); - } - } - } - } - } - } -} -template -void Octree::SetCoarserPointValues(int depth, const SortedTreeNodes& sNodes, Real* metSolution) { - int start = sNodes.nodeCount[depth], end = sNodes.nodeCount[depth + 1], range = end - start; - // For every node at the current depth -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey3 neighborKey; - neighborKey.set(depth); - for (int i = start + (range * t) / threads; i < start + (range * (t + 1)) / threads; i++) { - int pIdx = sNodes.treeNodes[i]->nodeData.pointIndex; - if (pIdx != -1) { - neighborKey.getNeighbors(sNodes.treeNodes[i]); - _points[pIdx].value = WeightedCoarserFunctionValue(neighborKey, sNodes.treeNodes[i], metSolution); - } - } - } -} -template -Real Octree::WeightedCoarserFunctionValue(const OctNode::NeighborKey3& neighborKey, - const TreeOctNode* pointNode, Real* metSolution) const { - int depth = pointNode->depth(); - if (!depth || pointNode->nodeData.pointIndex == -1) return Real(0.); - double pointValue = 0; - - Real weight = _points[pointNode->nodeData.pointIndex].weight; - Point3D p = _points[pointNode->nodeData.pointIndex].position; - - // Iterate over all basis functions that overlap the point at the coarser resolutions - { - int d, _idx[3]; - const TreeOctNode::Neighbors3& neighbors = neighborKey.neighbors[depth - 1]; - neighbors.neighbors[1][1][1]->depthAndOffset(d, _idx); - _idx[0] = BinaryNode::CenterIndex(d, _idx[0] - 1); - _idx[1] = BinaryNode::CenterIndex(d, _idx[1] - 1); - _idx[2] = BinaryNode::CenterIndex(d, _idx[2] - 1); - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) - if (neighbors.neighbors[j][k][l] && neighbors.neighbors[j][k][l]->nodeData.nodeIndex >= 0) { - // Accumulate the contribution from these basis nodes - const TreeOctNode* basisNode = neighbors.neighbors[j][k][l]; - int idx[] = {_idx[0] + j, _idx[1] + k, _idx[2] + l}; - pointValue += - fData.baseBSplines[idx[0]][2 - j](p[0]) * fData.baseBSplines[idx[1]][2 - k](p[1]) * - fData.baseBSplines[idx[2]][2 - l](p[2]) * metSolution[basisNode->nodeData.nodeIndex]; - } - } - return Real(pointValue * weight); -} -template -int Octree::GetFixedDepthLaplacian( - SparseSymmetricMatrix& matrix, int depth, const SortedTreeNodes& sNodes, Real* metSolution) { - int start = sNodes.nodeCount[depth], end = sNodes.nodeCount[depth + 1], range = end - start; - double stencil[5][5][5]; - SetLaplacianStencil(depth, stencil); - Stencil stencils[2][2][2]; - SetLaplacianStencils(depth, stencils); - matrix.Resize(range); -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey5 neighborKey5; - neighborKey5.set(depth); - for (int i = (range * t) / threads; i < (range * (t + 1)) / threads; i++) { - TreeOctNode* node = sNodes.treeNodes[i + start]; - neighborKey5.getNeighbors(node); - - // Get the matrix row size - int count = GetMatrixRowSize(neighborKey5.neighbors[depth]); - - // Allocate memory for the row -#pragma omp critical(matrix_set_row_size) - { matrix.SetRowSize(i, count); } - - // Set the row entries - matrix.rowSizes[i] = SetMatrixRow(neighborKey5.neighbors[depth], matrix[i], start, stencil); - - // Offset the constraints using the solution from lower resolutions. - int x, y, z, c; - if (node->parent) { - c = int(node - node->parent->children); - Cube::FactorCornerIndex(c, x, y, z); - } else - x = y = z = 0; - UpdateConstraintsFromCoarser(neighborKey5, node, metSolution, stencils[x][y][z]); - } - } - return 1; -} -template -int Octree::GetRestrictedFixedDepthLaplacian(SparseSymmetricMatrix& matrix, int depth, const int* entries, - int entryCount, const TreeOctNode* rNode, Real radius, const SortedTreeNodes& sNodes, Real* metSolution) { - for (int i = 0; i < entryCount; i++) sNodes.treeNodes[entries[i]]->nodeData.nodeIndex = i; - double stencil[5][5][5]; - int rDepth, rOff[3]; - rNode->depthAndOffset(rDepth, rOff); - matrix.Resize(entryCount); - SetLaplacianStencil(depth, stencil); - Stencil stencils[2][2][2]; - SetLaplacianStencils(depth, stencils); -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey5 neighborKey5; - neighborKey5.set(depth); - for (int i = (entryCount * t) / threads; i < (entryCount * (t + 1)) / threads; i++) { - TreeOctNode* node = sNodes.treeNodes[entries[i]]; - int d, off[3]; - node->depthAndOffset(d, off); - off[0] >>= (depth - rDepth), off[1] >>= (depth - rDepth), off[2] >>= (depth - rDepth); - bool isInterior = (off[0] == rOff[0] && off[1] == rOff[1] && off[2] == rOff[2]); - - neighborKey5.getNeighbors(node); - - int xStart = 0, xEnd = 5, yStart = 0, yEnd = 5, zStart = 0, zEnd = 5; - if (!isInterior) - SetMatrixRowBounds(neighborKey5.neighbors[depth].neighbors[2][2][2], rDepth, rOff, xStart, xEnd, yStart, - yEnd, zStart, zEnd); - - // Get the matrix row size - int count = GetMatrixRowSize(neighborKey5.neighbors[depth], xStart, xEnd, yStart, yEnd, zStart, zEnd); - - // Allocate memory for the row -#pragma omp critical(matrix_set_row_size) - { matrix.SetRowSize(i, count); } - - // Set the matrix row entries - matrix.rowSizes[i] = SetMatrixRow( - neighborKey5.neighbors[depth], matrix[i], 0, stencil, xStart, xEnd, yStart, yEnd, zStart, zEnd); - // Adjust the system constraints - int x, y, z, c; - if (node->parent) { - c = int(node - node->parent->children); - Cube::FactorCornerIndex(c, x, y, z); - } else - x = y = z = 0; - UpdateConstraintsFromCoarser(neighborKey5, node, metSolution, stencils[x][y][z]); - } - } - for (int i = 0; i < entryCount; i++) sNodes.treeNodes[entries[i]]->nodeData.nodeIndex = entries[i]; - return 1; -} - -template -int Octree::LaplacianMatrixIteration(int subdivideDepth, bool showResidual, int minIters, double accuracy) { - int i, iter = 0; - double t = 0; - fData.setDotTables(fData.DD_DOT_FLAG | fData.DV_DOT_FLAG); - - SparseMatrix::SetAllocator(MEMORY_ALLOCATOR_BLOCK_SIZE); - _sNodes.treeNodes[0]->nodeData.solution = 0; - - std::vector metSolution(_sNodes.nodeCount[_sNodes.maxDepth], 0); - - for (i = 1; i < _sNodes.maxDepth; i++) { - if (subdivideDepth > 0) - iter += - SolveFixedDepthMatrix(i, _sNodes, &metSolution[0], subdivideDepth, showResidual, minIters, accuracy); - else - iter += SolveFixedDepthMatrix(i, _sNodes, &metSolution[0], showResidual, minIters, accuracy); - } - SparseMatrix::internalAllocator.reset(); - fData.clearDotTables(fData.VV_DOT_FLAG | fData.DV_DOT_FLAG | fData.DD_DOT_FLAG); - - return iter; -} - -template -int Octree::SolveFixedDepthMatrix( - int depth, const SortedTreeNodes& sNodes, Real* metSolution, bool showResidual, int minIters, double accuracy) { - int iter = 0; - Vector X, B; - SparseSymmetricMatrix M; - double systemTime = 0., solveTime = 0., updateTime = 0., evaluateTime = 0.; - - X.Resize(sNodes.nodeCount[depth + 1] - sNodes.nodeCount[depth]); - if (depth <= _minDepth) - UpSampleCoarserSolution(depth, sNodes, X); - else { - // Up-sample the cumulative solution into the previous depth - UpSample(depth - 1, sNodes, metSolution); - // Add in the solution from that depth - if (depth) -#pragma omp parallel for num_threads(threads) - for (int i = _sNodes.nodeCount[depth - 1]; i < _sNodes.nodeCount[depth]; i++) - metSolution[i] += _sNodes.treeNodes[i]->nodeData.solution; - } - if (_constrainValues) { - SetCoarserPointValues(depth, sNodes, metSolution); - } - - SparseSymmetricMatrix::internalAllocator.rollBack(); - { - int maxECount = ((2 * Degree + 1) * (2 * Degree + 1) * (2 * Degree + 1) + 1) / 2; - maxECount = ((maxECount + 15) / 16) * 16; - M.Resize(sNodes.nodeCount[depth + 1] - sNodes.nodeCount[depth]); - for (int i = 0; i < M.rows; i++) M.SetRowSize(i, maxECount); - } - - { - // Get the system matrix - SparseSymmetricMatrix::internalAllocator.rollBack(); - GetFixedDepthLaplacian(M, depth, sNodes, metSolution); - // Set the constraint vector - B.Resize(sNodes.nodeCount[depth + 1] - sNodes.nodeCount[depth]); - for (int i = sNodes.nodeCount[depth]; i < sNodes.nodeCount[depth + 1]; i++) - B[i - sNodes.nodeCount[depth]] = sNodes.treeNodes[i]->nodeData.constraint; - } - - // Solve the linear system - iter += SparseSymmetricMatrix::Solve(M, B, std::max(int(pow(M.rows, ITERATION_POWER)), minIters), X, - Real(accuracy), 0, threads, (depth <= _minDepth) && !_constrainValues); - - if (showResidual) { - double mNorm = 0; - for (int i = 0; i < M.rows; i++) - for (int j = 0; j < M.rowSizes[i]; j++) mNorm += M[i][j].Value * M[i][j].Value; - double bNorm = B.Norm(2), rNorm = (B - M * X).Norm(2); - printf("\tResidual: (%d %g) %g -> %g (%f) [%d]\n", M.Entries(), sqrt(mNorm), bNorm, rNorm, rNorm / bNorm, iter); - } - - // Copy the solution back into the tree (over-writing the constraints) - for (int i = sNodes.nodeCount[depth]; i < sNodes.nodeCount[depth + 1]; i++) - sNodes.treeNodes[i]->nodeData.solution = Real(X[i - sNodes.nodeCount[depth]]); - - return iter; -} -template -int Octree::SolveFixedDepthMatrix(int depth, const SortedTreeNodes& sNodes, Real* metSolution, - int startingDepth, bool showResidual, int minIters, double accuracy) { - if (startingDepth >= depth) - return SolveFixedDepthMatrix(depth, sNodes, metSolution, showResidual, minIters, accuracy); - - int i, j, d, tIter = 0; - SparseSymmetricMatrix _M; - Vector B, B_, X_; - AdjacencySetFunction asf; - AdjacencyCountFunction acf; - double systemTime = 0, solveTime = 0, memUsage = 0, evaluateTime = 0, gTime = 0, sTime = 0; - Real myRadius, myRadius2; - - if (depth > _minDepth) { - // Up-sample the cumulative solution into the previous depth - UpSample(depth - 1, sNodes, metSolution); - // Add in the solution from that depth - if (depth) -#pragma omp parallel for num_threads(threads) - for (int i = _sNodes.nodeCount[depth - 1]; i < _sNodes.nodeCount[depth]; i++) - metSolution[i] += _sNodes.treeNodes[i]->nodeData.solution; - } - - if (_constrainValues) { - SetCoarserPointValues(depth, sNodes, metSolution); - } - B.Resize(sNodes.nodeCount[depth + 1] - sNodes.nodeCount[depth]); - - // Back-up the constraints - for (i = sNodes.nodeCount[depth]; i < sNodes.nodeCount[depth + 1]; i++) { - B[i - sNodes.nodeCount[depth]] = sNodes.treeNodes[i]->nodeData.constraint; - sNodes.treeNodes[i]->nodeData.constraint = 0; - } - - myRadius = 2 * radius - Real(0.5); - myRadius = int(myRadius - ROUND_EPS) + ROUND_EPS; - myRadius2 = Real(radius + ROUND_EPS - 0.5); - d = depth - startingDepth; - std::vector subDimension(sNodes.nodeCount[d + 1] - sNodes.nodeCount[d]); - int maxDimension = 0; - for (i = sNodes.nodeCount[d]; i < sNodes.nodeCount[d + 1]; i++) { - // Count the number of nodes at depth "depth" that lie under sNodes.treeNodes[i] - acf.adjacencyCount = 0; - for (TreeOctNode* temp = sNodes.treeNodes[i]->nextNode(); temp;) { - if (temp->depth() == depth) - acf.adjacencyCount++, temp = sNodes.treeNodes[i]->nextBranch(temp); - else - temp = sNodes.treeNodes[i]->nextNode(temp); - } - for (j = sNodes.nodeCount[d]; j < sNodes.nodeCount[d + 1]; j++) { - if (i == j) continue; - TreeOctNode::ProcessFixedDepthNodeAdjacentNodes( - fData.depth, sNodes.treeNodes[i], 1, sNodes.treeNodes[j], 2 * width - 1, depth, &acf); - } - subDimension[i - sNodes.nodeCount[d]] = acf.adjacencyCount; - maxDimension = std::max(maxDimension, subDimension[i - sNodes.nodeCount[d]]); - } - asf.adjacencies = new int[maxDimension]; - MapReduceVector mrVector; - mrVector.resize(threads, maxDimension); - // Iterate through the coarse-level nodes - for (i = sNodes.nodeCount[d]; i < sNodes.nodeCount[d + 1]; i++) { - int iter = 0; - // Count the number of nodes at depth "depth" that lie under sNodes.treeNodes[i] - acf.adjacencyCount = subDimension[i - sNodes.nodeCount[d]]; - if (!acf.adjacencyCount) continue; - - // Set the indices for the nodes under, or near, sNodes.treeNodes[i]. - asf.adjacencyCount = 0; - for (TreeOctNode* temp = sNodes.treeNodes[i]->nextNode(); temp;) { - if (temp->depth() == depth) - asf.adjacencies[asf.adjacencyCount++] = temp->nodeData.nodeIndex, - temp = sNodes.treeNodes[i]->nextBranch(temp); - else - temp = sNodes.treeNodes[i]->nextNode(temp); - } - for (j = sNodes.nodeCount[d]; j < sNodes.nodeCount[d + 1]; j++) { - if (i == j) continue; - TreeOctNode::ProcessFixedDepthNodeAdjacentNodes( - fData.depth, sNodes.treeNodes[i], 1, sNodes.treeNodes[j], 2 * width - 1, depth, &asf); - } - - // Get the associated constraint vector - B_.Resize(asf.adjacencyCount); - for (j = 0; j < asf.adjacencyCount; j++) B_[j] = B[asf.adjacencies[j] - sNodes.nodeCount[depth]]; - - X_.Resize(asf.adjacencyCount); -#pragma omp parallel for num_threads(threads) schedule(static) - for (j = 0; j < asf.adjacencyCount; j++) { - X_[j] = sNodes.treeNodes[asf.adjacencies[j]]->nodeData.solution; - } - // Get the associated matrix - SparseSymmetricMatrix::internalAllocator.rollBack(); - GetRestrictedFixedDepthLaplacian( - _M, depth, asf.adjacencies, asf.adjacencyCount, sNodes.treeNodes[i], myRadius, sNodes, metSolution); -#pragma omp parallel for num_threads(threads) schedule(static) - for (j = 0; j < asf.adjacencyCount; j++) { - B_[j] += sNodes.treeNodes[asf.adjacencies[j]]->nodeData.constraint; - sNodes.treeNodes[asf.adjacencies[j]]->nodeData.constraint = 0; - } - - // Solve the matrix - // Since we don't have the full matrix, the system shouldn't be singular, so we shouldn't have to correct it - iter += SparseSymmetricMatrix::Solve( - _M, B_, std::max(int(pow(_M.rows, ITERATION_POWER)), minIters), X_, mrVector, Real(accuracy), 0); - - if (showResidual) { - double mNorm = 0; - for (int i = 0; i < _M.rows; i++) - for (int j = 0; j < _M.rowSizes[i]; j++) mNorm += _M[i][j].Value * _M[i][j].Value; - double bNorm = B_.Norm(2), rNorm = (B_ - _M * X_).Norm(2); - printf("\t\tResidual: (%d %g) %g -> %g (%f) [%d]\n", _M.Entries(), sqrt(mNorm), bNorm, rNorm, rNorm / bNorm, - iter); - } - - // Update the solution for all nodes in the sub-tree - for (j = 0; j < asf.adjacencyCount; j++) { - TreeOctNode* temp = sNodes.treeNodes[asf.adjacencies[j]]; - while (temp->depth() > sNodes.treeNodes[i]->depth()) temp = temp->parent; - if (temp->nodeData.nodeIndex >= sNodes.treeNodes[i]->nodeData.nodeIndex) - sNodes.treeNodes[asf.adjacencies[j]]->nodeData.solution = Real(X_[j]); - } - systemTime += gTime; - solveTime += sTime; - memUsage = std::max(MemoryUsage(), memUsage); - tIter += iter; - } - delete[] asf.adjacencies; - return tIter; -} -template int Octree::HasNormals(TreeOctNode* node, Real epsilon) { - int hasNormals = 0; - if (node->nodeData.normalIndex >= 0 && - ((*normals)[node->nodeData.normalIndex][0] != 0 || (*normals)[node->nodeData.normalIndex][1] != 0 || - (*normals)[node->nodeData.normalIndex][2] != 0)) - hasNormals = 1; - if (node->children) - for (int i = 0; i < Cube::CORNERS && !hasNormals; i++) hasNormals |= HasNormals(&node->children[i], epsilon); - - return hasNormals; -} -template void Octree::ClipTree(void) { - int maxDepth = tree.maxDepth(); - for (TreeOctNode* temp = tree.nextNode(); temp; temp = tree.nextNode(temp)) - if (temp->children && temp->d >= _minDepth) { - int hasNormals = 0; - for (int i = 0; i < Cube::CORNERS && !hasNormals; i++) - hasNormals = HasNormals(&temp->children[i], EPSILON / (1 << maxDepth)); - if (!hasNormals) temp->children = NULL; - } - MemoryUsage(); -} -template void Octree::SetLaplacianConstraints(void) { - // To set the Laplacian constraints, we iterate over the - // splatted normals and compute the dot-product of the - // divergence of the normal field with all the basis functions. - // Within the same depth: set directly as a gather - // Coarser depths - fData.setDotTables(fData.VV_DOT_FLAG | fData.DV_DOT_FLAG); - - int maxDepth = _sNodes.maxDepth - 1; - Point3D zeroPoint; - zeroPoint[0] = zeroPoint[1] = zeroPoint[2] = 0; - std::vector constraints(_sNodes.nodeCount[maxDepth], Real(0)); - std::vector> coefficients(_sNodes.nodeCount[maxDepth], zeroPoint); - - // Clear the constraints -#pragma omp parallel for num_threads(threads) - for (int i = 0; i < _sNodes.nodeCount[maxDepth + 1]; i++) _sNodes.treeNodes[i]->nodeData.constraint = Real(0.); - - // For the scattering part of the operation, we parallelize by duplicating the constraints and then summing at the - // end. - std::vector> _constraints(threads); - for (int t = 0; t < threads; t++) _constraints[t].resize(_sNodes.nodeCount[maxDepth], 0); - - for (int d = maxDepth; d >= 0; d--) { - Point3D stencil[5][5][5]; - SetDivergenceStencil(d, &stencil[0][0][0], false); - Stencil, 5> stencils[2][2][2]; - SetDivergenceStencils(d, stencils, true); -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey5 neighborKey5; - neighborKey5.set(fData.depth); - int start = _sNodes.nodeCount[d], end = _sNodes.nodeCount[d + 1], range = end - start; - for (int i = start + (range * t) / threads; i < start + (range * (t + 1)) / threads; i++) { - TreeOctNode* node = _sNodes.treeNodes[i]; - int startX = 0, endX = 5, startY = 0, endY = 5, startZ = 0, endZ = 5; - int depth = node->depth(); - neighborKey5.getNeighbors(node); - - bool isInterior, isInterior2; - { - int d, off[3]; - node->depthAndOffset(d, off); - int mn = 2, mx = (1 << d) - 2; - isInterior = - (off[0] >= mn && off[0] < mx && off[1] >= mn && off[1] < mx && off[2] >= mn && off[2] < mx); - mn += 2, mx -= 2; - isInterior2 = - (off[0] >= mn && off[0] < mx && off[1] >= mn && off[1] < mx && off[2] >= mn && off[2] < mx); - } - int cx, cy, cz; - if (d) { - int c = int(node - node->parent->children); - Cube::FactorCornerIndex(c, cx, cy, cz); - } else - cx = cy = cz = 0; - Stencil, 5>& _stencil = stencils[cx][cy][cz]; - - // Set constraints from current depth - { - const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth]; - - if (isInterior) - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) { - const TreeOctNode* _node = neighbors5.neighbors[x][y][z]; - if (_node && _node->nodeData.normalIndex >= 0) { - const Point3D& _normal = (*normals)[_node->nodeData.normalIndex]; - node->nodeData.constraint += - Real(stencil[x][y][z][0] * _normal[0] + stencil[x][y][z][1] * _normal[1] + - stencil[x][y][z][2] * _normal[2]); - } - } - else - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) { - const TreeOctNode* _node = neighbors5.neighbors[x][y][z]; - if (_node && _node->nodeData.normalIndex >= 0) { - const Point3D& _normal = (*normals)[_node->nodeData.normalIndex]; - node->nodeData.constraint += GetDivergence(_node, node, _normal); - } - } - UpdateCoarserSupportBounds(neighbors5.neighbors[2][2][2], startX, endX, startY, endY, startZ, endZ); - } - if (node->nodeData.nodeIndex < 0 || node->nodeData.normalIndex < 0) continue; - const Point3D& normal = (*normals)[node->nodeData.normalIndex]; - if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) continue; - if (depth < maxDepth) coefficients[i] += normal; - - if (depth) { - const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.neighbors[depth - 1]; - - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) - if (neighbors5.neighbors[x][y][z]) { - TreeOctNode* _node = neighbors5.neighbors[x][y][z]; - if (isInterior2) { - Point3D& div = _stencil.values[x][y][z]; - _constraints[t][_node->nodeData.nodeIndex] += - Real(div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2]); - } else - _constraints[t][_node->nodeData.nodeIndex] += - GetDivergence(node, _node, normal); - } - } - } - } - } -#pragma omp parallel for num_threads(threads) schedule(static) - for (int i = 0; i < _sNodes.nodeCount[maxDepth]; i++) { - Real cSum = Real(0.); - for (int t = 0; t < threads; t++) cSum += _constraints[t][i]; - constraints[i] = cSum; - } - // Fine-to-coarse down-sampling of constraints - for (int d = maxDepth - 1; d >= 0; d--) DownSample(d, _sNodes, &constraints[0]); - - // Coarse-to-fine up-sampling of coefficients - for (int d = 0; d < maxDepth; d++) UpSample(d, _sNodes, &coefficients[0]); - - // Add the accumulated constraints from all finer depths -#pragma omp parallel for num_threads(threads) - for (int i = 0; i < _sNodes.nodeCount[maxDepth]; i++) _sNodes.treeNodes[i]->nodeData.constraint += constraints[i]; - - // Compute the contribution from all coarser depths - for (int d = 0; d <= maxDepth; d++) { - int start = _sNodes.nodeCount[d], end = _sNodes.nodeCount[d + 1], range = end - start; - Stencil, 5> stencils[2][2][2]; - SetDivergenceStencils(d, stencils, false); -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) { - TreeOctNode::NeighborKey5 neighborKey5; - neighborKey5.set(maxDepth); - for (int i = start + (range * t) / threads; i < start + (range * (t + 1)) / threads; i++) { - TreeOctNode* node = _sNodes.treeNodes[i]; - int depth = node->depth(); - if (!depth) continue; - int startX = 0, endX = 5, startY = 0, endY = 5, startZ = 0, endZ = 5; - UpdateCoarserSupportBounds(node, startX, endX, startY, endY, startZ, endZ); - const TreeOctNode::Neighbors5& neighbors5 = neighborKey5.getNeighbors(node->parent); - - bool isInterior; - { - int d, off[3]; - node->depthAndOffset(d, off); - int mn = 4, mx = (1 << d) - 4; - isInterior = - (off[0] >= mn && off[0] < mx && off[1] >= mn && off[1] < mx && off[2] >= mn && off[2] < mx); - } - int cx, cy, cz; - if (d) { - int c = int(node - node->parent->children); - Cube::FactorCornerIndex(c, cx, cy, cz); - } else - cx = cy = cz = 0; - Stencil, 5>& _stencil = stencils[cx][cy][cz]; - - Real constraint = Real(0); - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) - if (neighbors5.neighbors[x][y][z]) { - TreeOctNode* _node = neighbors5.neighbors[x][y][z]; - int _i = _node->nodeData.nodeIndex; - if (isInterior) { - Point3D& div = _stencil.values[x][y][z]; - Point3D& normal = coefficients[_i]; - constraint += Real(div[0] * normal[0] + div[1] * normal[1] + div[2] * normal[2]); - } else - constraint += GetDivergence(_node, node, coefficients[_i]); - } - node->nodeData.constraint += constraint; - } - } - } - - fData.clearDotTables(fData.DV_DOT_FLAG); - - // Set the point weights for evaluating the iso-value -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) - for (int i = (_sNodes.nodeCount[maxDepth + 1] * t) / threads; - i < (_sNodes.nodeCount[maxDepth + 1] * (t + 1)) / threads; i++) { - TreeOctNode* temp = _sNodes.treeNodes[i]; - if (temp->nodeData.nodeIndex < 0 || temp->nodeData.normalIndex < 0) - temp->nodeData.centerWeightContribution = 0; - else - temp->nodeData.centerWeightContribution = Real(Length((*normals)[temp->nodeData.normalIndex])); - } - MemoryUsage(); - delete normals; - normals = NULL; -} -template -void Octree::AdjacencyCountFunction::Function(const TreeOctNode* node1, const TreeOctNode* node2) { - adjacencyCount++; -} -template -void Octree::AdjacencySetFunction::Function(const TreeOctNode* node1, const TreeOctNode* node2) { - adjacencies[adjacencyCount++] = node1->nodeData.nodeIndex; -} -template void Octree::RefineFunction::Function(TreeOctNode* node1, const TreeOctNode* node2) { - if (!node1->children && node1->depth() < depth) node1->initChildren(); -} -template -void Octree::FaceEdgesFunction::Function(const TreeOctNode* node1, const TreeOctNode* node2) { - if (!node1->children && MarchingCubes::HasRoots(node1->nodeData.mcIndex)) { - RootInfo ri1, ri2; - int isoTri[DIMENSION * MarchingCubes::MAX_TRIANGLES]; - int count = MarchingCubes::AddTriangleIndices(node1->nodeData.mcIndex, isoTri); - - for (int j = 0; j < count; j++) - for (int k = 0; k < 3; k++) - if (fIndex == Cube::FaceAdjacentToEdges(isoTri[j * 3 + k], isoTri[j * 3 + ((k + 1) % 3)])) - if (GetRootIndex(node1, isoTri[j * 3 + k], maxDepth, ri1) && - GetRootIndex(node1, isoTri[j * 3 + ((k + 1) % 3)], maxDepth, ri2)) { - long long key1 = ri1.key, key2 = ri2.key; - edges->push_back(std::pair(ri2, ri1)); - if (vertexCount->count(key1) == 0) { - (*vertexCount)[key1].first = ri1; - (*vertexCount)[key1].second = 0; - } - if (vertexCount->count(key2) == 0) { - (*vertexCount)[key2].first = ri2; - (*vertexCount)[key2].second = 0; - } - (*vertexCount)[key1].second--; - (*vertexCount)[key2].second++; - } else - fprintf(stderr, "Bad Edge 1: %d %d\n", ri1.key, ri2.key); - } -} - -template void Octree::RefineBoundary(int subdivideDepth) { - // This implementation is somewhat tricky. - // We would like to ensure that leaf-nodes across a subdivision boundary have the same depth. - // We do this by calling the setNeighbors function. - // The key is to implement this in a single pass through the leaves, ensuring that refinements don't propogate. - // To this end, we do the minimal refinement that ensures that a cross boundary neighbor, and any of its - // cross-boundary neighbors are all refined simultaneously. For this reason, the implementation can only support - // nodes deeper than sDepth. - bool flags[3][3][3]; - int maxDepth = tree.maxDepth(); - - int sDepth; - if (subdivideDepth <= 0) - sDepth = 0; - else - sDepth = maxDepth - subdivideDepth; - if (sDepth <= 0) return; - - // Ensure that face adjacent neighbors across the subdivision boundary exist to allow for - // a consistent definition of the iso-surface - TreeOctNode::NeighborKey3 nKey; - nKey.set(maxDepth); - for (TreeOctNode* leaf = tree.nextLeaf(); leaf; leaf = tree.nextLeaf(leaf)) - if (leaf->depth() > sDepth) { - int d, off[3], _off[3]; - leaf->depthAndOffset(d, off); - int res = (1 << d) - 1, _res = (1 << (d - sDepth)) - 1; - _off[0] = off[0] & _res, _off[1] = off[1] & _res, _off[2] = off[2] & _res; - bool boundary[3][2] = {{(off[0] != 0 && _off[0] == 0), (off[0] != res && _off[0] == _res)}, - {(off[1] != 0 && _off[1] == 0), (off[1] != res && _off[1] == _res)}, - {(off[2] != 0 && _off[2] == 0), (off[2] != res && _off[2] == _res)}}; - - if (boundary[0][0] || boundary[0][1] || boundary[1][0] || boundary[1][1] || boundary[2][0] || - boundary[2][1]) { - TreeOctNode::Neighbors3& neighbors = nKey.getNeighbors(leaf); - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) flags[i][j][k] = false; - int x = 0, y = 0, z = 0; - if (boundary[0][0] && !neighbors.neighbors[0][1][1]) - x = -1; - else if (boundary[0][1] && !neighbors.neighbors[2][1][1]) - x = 1; - if (boundary[1][0] && !neighbors.neighbors[1][0][1]) - y = -1; - else if (boundary[1][1] && !neighbors.neighbors[1][2][1]) - y = 1; - if (boundary[2][0] && !neighbors.neighbors[1][1][0]) - z = -1; - else if (boundary[2][1] && !neighbors.neighbors[1][1][2]) - z = 1; - - if (x || y || z) { - // Corner case - if (x && y && z) flags[1 + x][1 + y][1 + z] = true; - // Edge cases - if (x && y) flags[1 + x][1 + y][1] = true; - if (x && z) flags[1 + x][1][1 + z] = true; - if (y && z) flags[1][1 + y][1 + 1] = true; - // Face cases - if (x) flags[1 + x][1][1] = true; - if (y) flags[1][1 + y][1] = true; - if (z) flags[1][1][1 + z] = true; - nKey.setNeighbors(leaf, flags); - } - } - } - _sNodes.set(tree); - MemoryUsage(); -} -template -void Octree::GetMCIsoTriangles(Real isoValue, int subdivideDepth, CoredMeshData* mesh, int fullDepthIso, - int nonLinearFit, bool addBarycenter, bool polygonMesh) { - fData.setValueTables(fData.VALUE_FLAG | fData.D_VALUE_FLAG, 0, postNormalSmooth); - - // Ensure that the subtrees are self-contained - RefineBoundary(subdivideDepth); - - RootData rootData, coarseRootData; - std::vector>* interiorPoints; - int maxDepth = tree.maxDepth(); - - int sDepth = subdivideDepth <= 0 ? 0 : std::max(0, maxDepth - subdivideDepth); - - std::vector metSolution(_sNodes.nodeCount[maxDepth], 0); -#pragma omp parallel for num_threads(threads) - for (int i = _sNodes.nodeCount[_minDepth]; i < _sNodes.nodeCount[maxDepth]; i++) - metSolution[i] = _sNodes.treeNodes[i]->nodeData.solution; - for (int d = 0; d < maxDepth; d++) UpSample(d, _sNodes, &metSolution[0]); - - // Clear the marching cube indices -#pragma omp parallel for num_threads(threads) - for (int i = 0; i < _sNodes.nodeCount[maxDepth + 1]; i++) _sNodes.treeNodes[i]->nodeData.mcIndex = 0; - - rootData.boundaryValues = new std::unordered_map>>(); - int offSet = 0; - - int maxCCount = _sNodes.getMaxCornerCount(&tree, sDepth, maxDepth, threads); - int maxECount = _sNodes.getMaxEdgeCount(&tree, sDepth, threads); - rootData.cornerValues = new Real[maxCCount]; - rootData.cornerNormals = new Point3D[maxCCount]; - rootData.interiorRoots = new int[maxECount]; - rootData.cornerValuesSet = new char[maxCCount]; - rootData.cornerNormalsSet = new char[maxCCount]; - rootData.edgesSet = new char[maxECount]; - _sNodes.setCornerTable(coarseRootData, &tree, sDepth, threads); - coarseRootData.cornerValues = new Real[coarseRootData.cCount]; - coarseRootData.cornerNormals = new Point3D[coarseRootData.cCount]; - coarseRootData.cornerValuesSet = new char[coarseRootData.cCount]; - coarseRootData.cornerNormalsSet = new char[coarseRootData.cCount]; - memset(coarseRootData.cornerValuesSet, 0, sizeof(char) * coarseRootData.cCount); - memset(coarseRootData.cornerNormalsSet, 0, sizeof(char) * coarseRootData.cCount); - MemoryUsage(); - - std::vector nKeys(threads); - for (int t = 0; t < threads; t++) nKeys[t].set(maxDepth); - TreeOctNode::ConstNeighborKey3 nKey; - std::vector nKeys5(threads); - for (int t = 0; t < threads; t++) nKeys5[t].set(maxDepth); - TreeOctNode::ConstNeighborKey5 nKey5; - nKey5.set(maxDepth); - nKey.set(maxDepth); - // First process all leaf nodes at depths strictly finer than sDepth, one subtree at a time. - for (int i = _sNodes.nodeCount[sDepth]; i < _sNodes.nodeCount[sDepth + 1]; i++) { - if (!_sNodes.treeNodes[i]->children) continue; - - _sNodes.setCornerTable(rootData, _sNodes.treeNodes[i], threads); - _sNodes.setEdgeTable(rootData, _sNodes.treeNodes[i], threads); - memset(rootData.cornerValuesSet, 0, sizeof(char) * rootData.cCount); - memset(rootData.cornerNormalsSet, 0, sizeof(char) * rootData.cCount); - memset(rootData.edgesSet, 0, sizeof(char) * rootData.eCount); - interiorPoints = new std::vector>(); - for (int d = maxDepth; d > sDepth; d--) { - int leafNodeCount = 0; - std::vector leafNodes; - for (TreeOctNode* node = _sNodes.treeNodes[i]->nextLeaf(); node; - node = _sNodes.treeNodes[i]->nextLeaf(node)) - if (node->d == d) leafNodeCount++; - leafNodes.reserve(leafNodeCount); - for (TreeOctNode* node = _sNodes.treeNodes[i]->nextLeaf(); node; - node = _sNodes.treeNodes[i]->nextLeaf(node)) - if (node->d == d) leafNodes.push_back(node); - Stencil stencil1[8], stencil2[8][8]; - SetEvaluationStencils(d, stencil1, stencil2); - - // First set the corner values and associated marching-cube indices -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) - for (int i = (leafNodeCount * t) / threads; i < (leafNodeCount * (t + 1)) / threads; i++) { - TreeOctNode* leaf = leafNodes[i]; - SetIsoCorners(isoValue, leaf, rootData, rootData.cornerValuesSet, rootData.cornerValues, nKeys[t], - &metSolution[0], stencil1, stencil2); - - // If this node shares a vertex with a coarser node, set the vertex value - int d, off[3]; - leaf->depthAndOffset(d, off); - int res = 1 << (d - sDepth); - off[0] %= res, off[1] %= res, off[2] %= res; - res--; - if (!(off[0] % res) && !(off[1] % res) && !(off[2] % res)) { - const TreeOctNode* temp = leaf; - while (temp->d != sDepth) temp = temp->parent; - int x = off[0] == 0 ? 0 : 1, y = off[1] == 0 ? 0 : 1, z = off[2] == 0 ? 0 : 1; - int c = Cube::CornerIndex(x, y, z); - int idx = coarseRootData.cornerIndices(temp)[c]; - coarseRootData.cornerValues[idx] = rootData.cornerValues[rootData.cornerIndices(leaf)[c]]; - coarseRootData.cornerValuesSet[idx] = true; - } - - // Compute the iso-vertices - if (MarchingCubes::HasRoots(leaf->nodeData.mcIndex)) - SetMCRootPositions(leaf, sDepth, isoValue, nKeys5[t], rootData, interiorPoints, mesh, - &metSolution[0], nonLinearFit); - } - // Note that this should be broken off for multi-threading as - // the SetMCRootPositions writes to interiorPoints (with lockupdateing) - // while GetMCIsoTriangles reads from interiorPoints (without locking) -#if MISHA_DEBUG - std::vector> barycenters; - std::vector>* barycenterPtr = addBarycenter ? &barycenters : NULL; -#endif // MISHA_DEBUG -#pragma omp parallel for num_threads(threads) - for (int t = 0; t < threads; t++) - for (int i = (leafNodeCount * t) / threads; i < (leafNodeCount * (t + 1)) / threads; i++) { - TreeOctNode* leaf = leafNodes[i]; - if (MarchingCubes::HasRoots(leaf->nodeData.mcIndex)) -#if MISHA_DEBUG - GetMCIsoTriangles( - leaf, mesh, rootData, interiorPoints, offSet, sDepth, polygonMesh, barycenterPtr); -#else // !MISHA_DEBUG - GetMCIsoTriangles( - leaf, mesh, rootData, interiorPoints, offSet, sDepth, addBarycenter, polygonMesh); -#endif // MISHA_DEBUG - } -#if MISHA_DEBUG - for (int i = 0; i < barycenters.size(); i++) interiorPoints->push_back(barycenters[i]); -#endif // MISHA_DEBUG - } - offSet = mesh->outOfCorePointCount(); -#if 1 - delete interiorPoints; -#endif - } - MemoryUsage(); - delete[] rootData.cornerValues, delete[] rootData.cornerNormals, rootData.cornerValues = NULL, - rootData.cornerNormals = NULL; - delete[] rootData.cornerValuesSet, delete[] rootData.cornerNormalsSet, rootData.cornerValuesSet = NULL, - rootData.cornerNormalsSet = NULL; - delete[] rootData.interiorRoots; - rootData.interiorRoots = NULL; - delete[] rootData.edgesSet; - rootData.edgesSet = NULL; - coarseRootData.interiorRoots = NULL; - coarseRootData.boundaryValues = rootData.boundaryValues; - for (auto iter = rootData.boundaryRoots.cbegin(); iter != rootData.boundaryRoots.cend(); iter++) - coarseRootData.boundaryRoots[iter->first] = iter->second; - - for (int d = sDepth; d >= 0; d--) { - Stencil stencil1[8], stencil2[8][8]; - SetEvaluationStencils(d, stencil1, stencil2); -#if MISHA_DEBUG - std::vector> barycenters; - std::vector>* barycenterPtr = addBarycenter ? &barycenters : NULL; -#endif // MISHA_DEBUG - for (int i = _sNodes.nodeCount[d]; i < _sNodes.nodeCount[d + 1]; i++) { - TreeOctNode* leaf = _sNodes.treeNodes[i]; - if (leaf->children) continue; - - // First set the corner values and associated marching-cube indices - SetIsoCorners(isoValue, leaf, coarseRootData, coarseRootData.cornerValuesSet, coarseRootData.cornerValues, - nKey, &metSolution[0], stencil1, stencil2); - - // Now compute the iso-vertices - if (MarchingCubes::HasRoots(leaf->nodeData.mcIndex)) { - SetMCRootPositions(leaf, 0, isoValue, nKey5, coarseRootData, NULL, mesh, &metSolution[0], nonLinearFit); -#if MISHA_DEBUG - GetMCIsoTriangles(leaf, mesh, coarseRootData, NULL, 0, 0, polygonMesh, barycenterPtr); -#else // !MISHA_DEBUG - GetMCIsoTriangles(leaf, mesh, coarseRootData, NULL, 0, 0, addBarycenter, polygonMesh); -#endif // MISHA_DEBUG - } - } - } - MemoryUsage(); - - delete[] coarseRootData.cornerValues, delete[] coarseRootData.cornerNormals; - delete[] coarseRootData.cornerValuesSet, delete[] coarseRootData.cornerNormalsSet; - delete rootData.boundaryValues; -} -template -Real Octree::getCenterValue( - const OctNode::ConstNeighborKey3& neighborKey, const TreeOctNode* node) { - int idx[3]; - Real value = 0; - - VertexData::CenterIndex(node, fData.depth, idx); - idx[0] *= fData.functionCount; - idx[1] *= fData.functionCount; - idx[2] *= fData.functionCount; - int minDepth = std::max(0, std::min(_minDepth, node->depth() - 1)); - for (int i = minDepth; i <= node->depth(); i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) - for (int l = 0; l < 3; l++) { - const TreeOctNode* n = neighborKey.neighbors[i].neighbors[j][k][l]; - if (n) { - Real temp = n->nodeData.solution; - value += temp * Real(fData.valueTables[idx[0] + int(n->off[0])] * - fData.valueTables[idx[1] + int(n->off[1])] * - fData.valueTables[idx[2] + int(n->off[2])]); - } - } - if (node->children) { - for (int i = 0; i < Cube::CORNERS; i++) { - int ii = Cube::AntipodalCornerIndex(i); - const TreeOctNode* n = &node->children[i]; - while (1) { - value += n->nodeData.solution * - Real(fData.valueTables[idx[0] + int(n->off[0])] * fData.valueTables[idx[1] + int(n->off[1])] * - fData.valueTables[idx[2] + int(n->off[2])]); - if (n->children) - n = &n->children[ii]; - else - break; - } - } - } - return value; -} -template -Real Octree::getCornerValue(const OctNode::ConstNeighborKey3& neighborKey3, - const TreeOctNode* node, int corner, const Real* metSolution) { - int idx[3]; - double value = 0; - - VertexData::CornerIndex(node, corner, fData.depth, idx); - idx[0] *= fData.functionCount; - idx[1] *= fData.functionCount; - idx[2] *= fData.functionCount; - - int d = node->depth(); - int cx, cy, cz; - int startX = 0, endX = 3, startY = 0, endY = 3, startZ = 0, endZ = 3; - Cube::FactorCornerIndex(corner, cx, cy, cz); - { - TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d]; - if (cx == 0) - endX = 2; - else - startX = 1; - if (cy == 0) - endY = 2; - else - startY = 1; - if (cz == 0) - endZ = 2; - else - startZ = 1; - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) { - const TreeOctNode* n = neighbors.neighbors[x][y][z]; - if (n) { - double v = fData.valueTables[idx[0] + int(n->off[0])] * - fData.valueTables[idx[1] + int(n->off[1])] * - fData.valueTables[idx[2] + int(n->off[2])]; - value += n->nodeData.solution * v; - } - } - } - if (d > 0 && d > _minDepth) { - int _corner = int(node - node->parent->children); - int _cx, _cy, _cz; - Cube::FactorCornerIndex(_corner, _cx, _cy, _cz); - if (cx != _cx) startX = 0, endX = 3; - if (cy != _cy) startY = 0, endY = 3; - if (cz != _cz) startZ = 0, endZ = 3; - TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d - 1]; - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) { - const TreeOctNode* n = neighbors.neighbors[x][y][z]; - if (n) { - double v = fData.valueTables[idx[0] + int(n->off[0])] * - fData.valueTables[idx[1] + int(n->off[1])] * - fData.valueTables[idx[2] + int(n->off[2])]; - value += metSolution[n->nodeData.nodeIndex] * v; - } - } - } - return Real(value); -} -template -Real Octree::getCornerValue(const OctNode::ConstNeighborKey3& neighborKey3, - const TreeOctNode* node, int corner, const Real* metSolution, const double stencil1[3][3][3], - const double stencil2[3][3][3]) { - double value = 0; - int d = node->depth(); - int cx, cy, cz; - int startX = 0, endX = 3, startY = 0, endY = 3, startZ = 0, endZ = 3; - Cube::FactorCornerIndex(corner, cx, cy, cz); - { - TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d]; - if (cx == 0) - endX = 2; - else - startX = 1; - if (cy == 0) - endY = 2; - else - startY = 1; - if (cz == 0) - endZ = 2; - else - startZ = 1; - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) { - const TreeOctNode* n = neighbors.neighbors[x][y][z]; - if (n) value += n->nodeData.solution * stencil1[x][y][z]; - } - } - if (d > 0 && d > _minDepth) { - int _corner = int(node - node->parent->children); - int _cx, _cy, _cz; - Cube::FactorCornerIndex(_corner, _cx, _cy, _cz); - if (cx != _cx) startX = 0, endX = 3; - if (cy != _cy) startY = 0, endY = 3; - if (cz != _cz) startZ = 0, endZ = 3; - TreeOctNode::ConstNeighbors3& neighbors = neighborKey3.neighbors[d - 1]; - for (int x = startX; x < endX; x++) - for (int y = startY; y < endY; y++) - for (int z = startZ; z < endZ; z++) { - const TreeOctNode* n = neighbors.neighbors[x][y][z]; - if (n) value += metSolution[n->nodeData.nodeIndex] * stencil2[x][y][z]; - } - } - return Real(value); -} -template -Point3D Octree::getCornerNormal(const OctNode::ConstNeighborKey5& neighborKey5, - const TreeOctNode* node, int corner, const Real* metSolution) { - int idx[3]; - Point3D normal; - normal[0] = normal[1] = normal[2] = 0.; - - VertexData::CornerIndex(node, corner, fData.depth, idx); - idx[0] *= fData.functionCount; - idx[1] *= fData.functionCount; - idx[2] *= fData.functionCount; - - int d = node->depth(); - // Iterate over all ancestors that can overlap the corner - { - TreeOctNode::ConstNeighbors5& neighbors = neighborKey5.neighbors[d]; - for (int j = 0; j < 5; j++) - for (int k = 0; k < 5; k++) - for (int l = 0; l < 5; l++) { - const TreeOctNode* n = neighbors.neighbors[j][k][l]; - if (n) { - int _idx[] = {idx[0] + n->off[0], idx[1] + n->off[1], idx[2] + n->off[2]}; - double values[] = { - fData.valueTables[_idx[0]], fData.valueTables[_idx[1]], fData.valueTables[_idx[2]]}; - double dValues[] = { - fData.dValueTables[_idx[0]], fData.dValueTables[_idx[1]], fData.dValueTables[_idx[2]]}; - Real solution = n->nodeData.solution; - normal[0] += Real(dValues[0] * values[1] * values[2] * solution); - normal[1] += Real(values[0] * dValues[1] * values[2] * solution); - normal[2] += Real(values[0] * values[1] * dValues[2] * solution); - } - } - } - if (d > 0 && d > _minDepth) { - TreeOctNode::ConstNeighbors5& neighbors = neighborKey5.neighbors[d - 1]; - for (int j = 0; j < 5; j++) - for (int k = 0; k < 5; k++) - for (int l = 0; l < 5; l++) { - const TreeOctNode* n = neighbors.neighbors[j][k][l]; - if (n) { - int _idx[] = {idx[0] + n->off[0], idx[1] + n->off[1], idx[2] + n->off[2]}; - double values[] = { - fData.valueTables[_idx[0]], fData.valueTables[_idx[1]], fData.valueTables[_idx[2]]}; - double dValues[] = { - fData.dValueTables[_idx[0]], fData.dValueTables[_idx[1]], fData.dValueTables[_idx[2]]}; - Real solution = metSolution[n->nodeData.nodeIndex]; - normal[0] += Real(dValues[0] * values[1] * values[2] * solution); - normal[1] += Real(values[0] * dValues[1] * values[2] * solution); - normal[2] += Real(values[0] * values[1] * dValues[2] * solution); - } - } - } - return normal; -} -template Real Octree::GetIsoValue(void) { - Real isoValue, weightSum; - - neighborKey2.set(fData.depth); - fData.setValueTables(fData.VALUE_FLAG, 0); - - isoValue = weightSum = 0; -#pragma omp parallel for num_threads(threads) reduction(+ : isoValue, weightSum) - for (int t = 0; t < threads; t++) { - TreeOctNode::ConstNeighborKey3 nKey; - nKey.set(_sNodes.maxDepth - 1); - int nodeCount = _sNodes.nodeCount[_sNodes.maxDepth]; - for (int i = (nodeCount * t) / threads; i < (nodeCount * (t + 1)) / threads; i++) { - TreeOctNode* temp = _sNodes.treeNodes[i]; - nKey.getNeighbors(temp); - Real w = temp->nodeData.centerWeightContribution; - if (w != 0) { - isoValue += getCenterValue(nKey, temp) * w; - weightSum += w; - } - } - } - return isoValue / weightSum; -} - -template -void Octree::SetIsoCorners(Real isoValue, TreeOctNode* leaf, SortedTreeNodes::CornerTableData& cData, - char* valuesSet, Real* values, TreeOctNode::ConstNeighborKey3& nKey, const Real* metSolution, - const Stencil stencil1[8], const Stencil stencil2[8][8]) { - Real cornerValues[Cube::CORNERS]; - const SortedTreeNodes::CornerIndices& cIndices = cData[leaf]; - - bool isInterior; - int d, off[3]; - leaf->depthAndOffset(d, off); - int mn = 2, mx = (1 << d) - 2; - isInterior = (off[0] >= mn && off[0] < mx && off[1] >= mn && off[1] < mx && off[2] >= mn && off[2] < mx); - nKey.getNeighbors(leaf); - for (int c = 0; c < Cube::CORNERS; c++) { - int vIndex = cIndices[c]; - if (valuesSet[vIndex]) - cornerValues[c] = values[vIndex]; - else { - if (isInterior) - cornerValues[c] = getCornerValue(nKey, leaf, c, metSolution, stencil1[c].values, - stencil2[int(leaf - leaf->parent->children)][c].values); - else - cornerValues[c] = getCornerValue(nKey, leaf, c, metSolution); - values[vIndex] = cornerValues[c]; - valuesSet[vIndex] = 1; - } - } - - leaf->nodeData.mcIndex = MarchingCubes::GetIndex(cornerValues, isoValue); - - // Set the marching cube indices for all interior nodes. - if (leaf->parent) { - TreeOctNode* parent = leaf->parent; - int c = int(leaf - leaf->parent->children); - int mcid = leaf->nodeData.mcIndex & (1 << MarchingCubes::cornerMap()[c]); - - if (mcid) { - poisson::atomicOr(parent->nodeData.mcIndex, mcid); - - while (1) { - if (parent->parent && parent->parent->d >= _minDepth && (parent - parent->parent->children) == c) { - poisson::atomicOr(parent->parent->nodeData.mcIndex, mcid); - parent = parent->parent; - } else - break; - } - } - } -} - - -template -int Octree::InteriorFaceRootCount(const TreeOctNode* node, const int& faceIndex, int maxDepth) { - int c1, c2, e1, e2, dir, off, cnt = 0; - int corners[Cube::CORNERS / 2]; - if (node->children) { - Cube::FaceCorners(faceIndex, corners[0], corners[1], corners[2], corners[3]); - Cube::FactorFaceIndex(faceIndex, dir, off); - c1 = corners[0]; - c2 = corners[3]; - switch (dir) { - case 0: - e1 = Cube::EdgeIndex(1, off, 1); - e2 = Cube::EdgeIndex(2, off, 1); - break; - case 1: - e1 = Cube::EdgeIndex(0, off, 1); - e2 = Cube::EdgeIndex(2, 1, off); - break; - case 2: - e1 = Cube::EdgeIndex(0, 1, off); - e2 = Cube::EdgeIndex(1, 1, off); - break; - }; - cnt += EdgeRootCount(&node->children[c1], e1, maxDepth) + EdgeRootCount(&node->children[c1], e2, maxDepth); - switch (dir) { - case 0: - e1 = Cube::EdgeIndex(1, off, 0); - e2 = Cube::EdgeIndex(2, off, 0); - break; - case 1: - e1 = Cube::EdgeIndex(0, off, 0); - e2 = Cube::EdgeIndex(2, 0, off); - break; - case 2: - e1 = Cube::EdgeIndex(0, 0, off); - e2 = Cube::EdgeIndex(1, 0, off); - break; - }; - cnt += EdgeRootCount(&node->children[c2], e1, maxDepth) + EdgeRootCount(&node->children[c2], e2, maxDepth); - for (int i = 0; i < Cube::CORNERS / 2; i++) { - if (node->children[corners[i]].children) { - cnt += InteriorFaceRootCount(&node->children[corners[i]], faceIndex, maxDepth); - } - } - } - return cnt; -} - -template int Octree::EdgeRootCount(const TreeOctNode* node, int edgeIndex, int maxDepth) { - int f1, f2, c1, c2; - const TreeOctNode* temp; - Cube::FacesAdjacentToEdge(edgeIndex, f1, f2); - - int eIndex; - const TreeOctNode* finest = node; - eIndex = edgeIndex; - if (node->depth() < maxDepth) { - temp = node->faceNeighbor(f1); - if (temp && temp->children) { - finest = temp; - eIndex = Cube::FaceReflectEdgeIndex(edgeIndex, f1); - } else { - temp = node->faceNeighbor(f2); - if (temp && temp->children) { - finest = temp; - eIndex = Cube::FaceReflectEdgeIndex(edgeIndex, f2); - } else { - temp = node->edgeNeighbor(edgeIndex); - if (temp && temp->children) { - finest = temp; - eIndex = Cube::EdgeReflectEdgeIndex(edgeIndex); - } - } - } - } - - Cube::EdgeCorners(eIndex, c1, c2); - if (finest->children) - return EdgeRootCount(&finest->children[c1], eIndex, maxDepth) + - EdgeRootCount(&finest->children[c2], eIndex, maxDepth); - else - return MarchingCubes::HasEdgeRoots(finest->nodeData.mcIndex, eIndex); -} -template int Octree::IsBoundaryFace(const TreeOctNode* node, int faceIndex, int subdivideDepth) { - int dir, offset, d, o[3], idx; - - if (subdivideDepth < 0) { - return 0; - } - if (node->d <= subdivideDepth) { - return 1; - } - Cube::FactorFaceIndex(faceIndex, dir, offset); - node->depthAndOffset(d, o); - - idx = (int(o[dir]) << 1) + (offset << 1); - return !(idx % (2 << (int(node->d) - subdivideDepth))); -} -template int Octree::IsBoundaryEdge(const TreeOctNode* node, int edgeIndex, int subdivideDepth) { - int dir, x, y; - Cube::FactorEdgeIndex(edgeIndex, dir, x, y); - return IsBoundaryEdge(node, dir, x, y, subdivideDepth); -} -template -int Octree::IsBoundaryEdge(const TreeOctNode* node, int dir, int x, int y, int subdivideDepth) { - int d, o[3], idx1, idx2, mask; - - if (subdivideDepth < 0) return 0; - if (node->d <= subdivideDepth) return 1; - node->depthAndOffset(d, o); - - switch (dir) { - case 0: - idx1 = o[1] + x; - idx2 = o[2] + y; - break; - case 1: - idx1 = o[0] + x; - idx2 = o[2] + y; - break; - case 2: - idx1 = o[0] + x; - idx2 = o[1] + y; - break; - } - mask = 1 << (int(node->d) - subdivideDepth); - return !(idx1 % (mask)) || !(idx2 % (mask)); -} -template void Octree::GetRootSpan(const RootInfo& ri, Point3D& start, Point3D& end) { - int o, i1, i2; - Real width; - Point3D c; - - Cube::FactorEdgeIndex(ri.edgeIndex, o, i1, i2); - ri.node->centerAndWidth(c, width); - switch (o) { - case 0: - start[0] = c[0] - width / 2; - end[0] = c[0] + width / 2; - start[1] = end[1] = c[1] - width / 2 + width * i1; - start[2] = end[2] = c[2] - width / 2 + width * i2; - break; - case 1: - start[0] = end[0] = c[0] - width / 2 + width * i1; - start[1] = c[1] - width / 2; - end[1] = c[1] + width / 2; - start[2] = end[2] = c[2] - width / 2 + width * i2; - break; - case 2: - start[0] = end[0] = c[0] - width / 2 + width * i1; - start[1] = end[1] = c[1] - width / 2 + width * i2; - start[2] = c[2] - width / 2; - end[2] = c[2] + width / 2; - break; - } -} -////////////////////////////////////////////////////////////////////////////////////// -// The assumption made when calling this code is that the edge has at most one root // -////////////////////////////////////////////////////////////////////////////////////// -template -int Octree::GetRoot(const RootInfo& ri, Real isoValue, TreeOctNode::ConstNeighborKey5& neighborKey5, - Point3D& position, RootData& rootData, int sDepth, const Real* metSolution, int nonLinearFit) { - if (!MarchingCubes::HasRoots(ri.node->nodeData.mcIndex)) return 0; - int c1, c2; - Cube::EdgeCorners(ri.edgeIndex, c1, c2); - if (!MarchingCubes::HasEdgeRoots(ri.node->nodeData.mcIndex, ri.edgeIndex)) return 0; - - long long key1, key2; - Point3D n[2]; - - int i, o, i1, i2, rCount = 0; - Polynomial<2> P; - std::vector roots; - double x0, x1; - Real center, width; - Real averageRoot = 0; - Cube::FactorEdgeIndex(ri.edgeIndex, o, i1, i2); - int idx1[3], idx2[3]; - key1 = VertexData::CornerIndex(ri.node, c1, fData.depth, idx1); - key2 = VertexData::CornerIndex(ri.node, c2, fData.depth, idx2); - - bool isBoundary = (IsBoundaryEdge(ri.node, ri.edgeIndex, sDepth) != 0); - bool haveKey1, haveKey2; - std::pair> keyValue1, keyValue2; - int iter1, iter2; - { - iter1 = rootData.cornerIndices(ri.node)[c1]; - iter2 = rootData.cornerIndices(ri.node)[c2]; - keyValue1.first = rootData.cornerValues[iter1]; - keyValue2.first = rootData.cornerValues[iter2]; - if (isBoundary) { -#pragma omp critical(normal_hash_access) - { - haveKey1 = (rootData.boundaryValues->count(key1) > 0); - haveKey2 = (rootData.boundaryValues->count(key2) > 0); - if (haveKey1) keyValue1 = (*rootData.boundaryValues)[key1]; - if (haveKey2) keyValue2 = (*rootData.boundaryValues)[key2]; - } - } else { - haveKey1 = (rootData.cornerNormalsSet[iter1] != 0); - haveKey2 = (rootData.cornerNormalsSet[iter2] != 0); - keyValue1.first = rootData.cornerValues[iter1]; - keyValue2.first = rootData.cornerValues[iter2]; - if (haveKey1) keyValue1.second = rootData.cornerNormals[iter1]; - if (haveKey2) keyValue2.second = rootData.cornerNormals[iter2]; - } - } - if (!haveKey1 || !haveKey2) neighborKey5.getNeighbors(ri.node); - if (!haveKey1) keyValue1.second = getCornerNormal(neighborKey5, ri.node, c1, metSolution); - x0 = keyValue1.first; - n[0] = keyValue1.second; - - if (!haveKey2) keyValue2.second = getCornerNormal(neighborKey5, ri.node, c2, metSolution); - x1 = keyValue2.first; - n[1] = keyValue2.second; - - if (!haveKey1 || !haveKey2) { - if (isBoundary) { -#pragma omp critical(normal_hash_access) - { - if (!haveKey1) (*rootData.boundaryValues)[key1] = keyValue1; - if (!haveKey2) (*rootData.boundaryValues)[key2] = keyValue2; - } - } else { - if (!haveKey1) rootData.cornerNormals[iter1] = keyValue1.second, rootData.cornerNormalsSet[iter1] = 1; - if (!haveKey2) rootData.cornerNormals[iter2] = keyValue2.second, rootData.cornerNormalsSet[iter2] = 1; - } - } - - Point3D c; - ri.node->centerAndWidth(c, width); - center = c[o]; - for (i = 0; i < DIMENSION; i++) n[0][i] *= width, n[1][i] *= width; - - switch (o) { - case 0: - position[1] = c[1] - width / 2 + width * i1; - position[2] = c[2] - width / 2 + width * i2; - break; - case 1: - position[0] = c[0] - width / 2 + width * i1; - position[2] = c[2] - width / 2 + width * i2; - break; - case 2: - position[0] = c[0] - width / 2 + width * i1; - position[1] = c[1] - width / 2 + width * i2; - break; - } - double dx0, dx1; - dx0 = n[0][o]; - dx1 = n[1][o]; - - // The scaling will turn the Hermite Spline into a quadratic - double scl = (x1 - x0) / ((dx1 + dx0) / 2); - dx0 *= scl; - dx1 *= scl; - - // Hermite Spline - P.coefficients[0] = x0; - P.coefficients[1] = dx0; - P.coefficients[2] = 3 * (x1 - x0) - dx1 - 2 * dx0; - - P.getSolutions(isoValue, roots, EPSILON); - for (i = 0; i < int(roots.size()); i++) - if (roots[i] >= 0 && roots[i] <= 1) { - averageRoot += Real(roots[i]); - rCount++; - } - if (rCount && nonLinearFit) - averageRoot /= rCount; - else - averageRoot = Real((x0 - isoValue) / (x0 - x1)); - if (averageRoot < 0 || averageRoot > 1) { - fprintf(stderr, "[WARNING] Bad average root: %f\n", averageRoot); - fprintf(stderr, "\t(%f %f) , (%f %f) (%f)\n", x0, x1, dx0, dx1, isoValue); - if (averageRoot < 0) averageRoot = 0; - if (averageRoot > 1) averageRoot = 1; - } - position[o] = Real(center - width / 2 + width * averageRoot); - return 1; -} -template -int Octree::GetRootIndex(const TreeOctNode* node, int edgeIndex, int maxDepth, int sDepth, RootInfo& ri) { - int c1, c2, f1, f2; - const TreeOctNode *temp, *finest; - int finestIndex; - - Cube::FacesAdjacentToEdge(edgeIndex, f1, f2); - - finest = node; - finestIndex = edgeIndex; - if (node->depth() < maxDepth) { - if (IsBoundaryFace(node, f1, sDepth)) { - temp = NULL; - } else { - temp = node->faceNeighbor(f1); - } - if (temp && temp->children) { - finest = temp; - finestIndex = Cube::FaceReflectEdgeIndex(edgeIndex, f1); - } else { - if (IsBoundaryFace(node, f2, sDepth)) { - temp = NULL; - } else { - temp = node->faceNeighbor(f2); - } - if (temp && temp->children) { - finest = temp; - finestIndex = Cube::FaceReflectEdgeIndex(edgeIndex, f2); - } else { - if (IsBoundaryEdge(node, edgeIndex, sDepth)) { - temp = NULL; - } else { - temp = node->edgeNeighbor(edgeIndex); - } - if (temp && temp->children) { - finest = temp; - finestIndex = Cube::EdgeReflectEdgeIndex(edgeIndex); - } - } - } - } - - Cube::EdgeCorners(finestIndex, c1, c2); - if (finest->children) { - if (GetRootIndex(&finest->children[c1], finestIndex, maxDepth, sDepth, ri)) { - return 1; - } else if (GetRootIndex(&finest->children[c2], finestIndex, maxDepth, sDepth, ri)) { - return 1; - } else { - fprintf(stderr, "[WARNING] Couldn't find root index with either child\n"); - return 0; - } - } else { - if (!(MarchingCubes::edgeMask()[finest->nodeData.mcIndex] & (1 << finestIndex))) { - fprintf(stderr, "[WARNING] Finest node does not have iso-edge\n"); - return 0; - } - - int o, i1, i2; - Cube::FactorEdgeIndex(finestIndex, o, i1, i2); - int d, off[3]; - finest->depthAndOffset(d, off); - ri.node = finest; - ri.edgeIndex = finestIndex; - int eIndex[2], offset; - offset = BinaryNode::Index(d, off[o]); - switch (o) { - case 0: - eIndex[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[1], i1); - eIndex[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[2], i2); - break; - case 1: - eIndex[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[0], i1); - eIndex[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[2], i2); - break; - case 2: - eIndex[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[0], i1); - eIndex[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[1], i2); - break; - } - ri.key = - (long long)(o) | (long long)(eIndex[0]) << 5 | (long long)(eIndex[1]) << 25 | (long long)(offset) << 45; - return 1; - } -} -template -int Octree::GetRootIndex(const TreeOctNode* node, int edgeIndex, int maxDepth, RootInfo& ri) { - int c1, c2, f1, f2; - const TreeOctNode *temp, *finest; - int finestIndex; - - - // The assumption is that the super-edge has a root along it. - if (!(MarchingCubes::edgeMask()[node->nodeData.mcIndex] & (1 << edgeIndex))) { - return 0; - } - - Cube::FacesAdjacentToEdge(edgeIndex, f1, f2); - - finest = node; - finestIndex = edgeIndex; - if (node->depth() < maxDepth && !node->children) { - temp = node->faceNeighbor(f1); - if (temp && temp->children) - finest = temp, finestIndex = Cube::FaceReflectEdgeIndex(edgeIndex, f1); - else { - temp = node->faceNeighbor(f2); - if (temp && temp->children) - finest = temp, finestIndex = Cube::FaceReflectEdgeIndex(edgeIndex, f2); - else { - temp = node->edgeNeighbor(edgeIndex); - if (temp && temp->children) finest = temp, finestIndex = Cube::EdgeReflectEdgeIndex(edgeIndex); - } - } - } - - Cube::EdgeCorners(finestIndex, c1, c2); - if (finest->children) { - if (GetRootIndex(finest->children + c1, finestIndex, maxDepth, ri)) - return 1; - else if (GetRootIndex(finest->children + c2, finestIndex, maxDepth, ri)) - return 1; - else { - int d1, off1[3], d2, off2[3]; - node->depthAndOffset(d1, off1); - finest->depthAndOffset(d2, off2); - fprintf(stderr, - "[WARNING] Couldn't find root index with either child [%d] (%d %d %d) -> [%d] (%d %d %d) (%d %d)\n", d1, - off1[0], off1[1], off1[2], d2, off2[0], off2[1], off2[2], node->children != NULL, - finest->children != NULL); - printf("\t"); - for (int i = 0; i < 8; i++) - if (node->nodeData.mcIndex & (1 << i)) - printf("1"); - else - printf("0"); - printf("\t"); - for (int i = 0; i < 8; i++) - if (finest->nodeData.mcIndex & (1 << i)) - printf("1"); - else - printf("0"); - printf("\n"); - return 0; - } - } else { - int o, i1, i2; - Cube::FactorEdgeIndex(finestIndex, o, i1, i2); - int d, off[3]; - finest->depthAndOffset(d, off); - ri.node = finest; - ri.edgeIndex = finestIndex; - int offset, eIndex[2]; - offset = BinaryNode::CenterIndex(d, off[o]); - switch (o) { - case 0: - eIndex[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[1], i1); - eIndex[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[2], i2); - break; - case 1: - eIndex[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[0], i1); - eIndex[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[2], i2); - break; - case 2: - eIndex[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[0], i1); - eIndex[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[1], i2); - break; - } - ri.key = - (long long)(o) | (long long)(eIndex[0]) << 5 | (long long)(eIndex[1]) << 25 | (long long)(offset) << 45; - return 1; - } -} -template int Octree::GetRootPair(const RootInfo& ri, int maxDepth, RootInfo& pair) { - const TreeOctNode* node = ri.node; - int c1, c2, c; - Cube::EdgeCorners(ri.edgeIndex, c1, c2); - while (node->parent) { - c = int(node - node->parent->children); - if (c != c1 && c != c2) { - return 0; - } - if (!MarchingCubes::HasEdgeRoots(node->parent->nodeData.mcIndex, ri.edgeIndex)) { - if (c == c1) { - return GetRootIndex(&node->parent->children[c2], ri.edgeIndex, maxDepth, pair); - } else { - return GetRootIndex(&node->parent->children[c1], ri.edgeIndex, maxDepth, pair); - } - } - node = node->parent; - } - return 0; -} -template int Octree::GetRootIndex(const RootInfo& ri, RootData& rootData, CoredPointIndex& index) { - long long key = ri.key; - auto rootIter = rootData.boundaryRoots.find(key); - if (rootIter != rootData.boundaryRoots.end()) { - index.inCore = 1; - index.index = rootIter->second; - return 1; - } else if (rootData.interiorRoots) { - int eIndex = rootData.edgeIndices(ri.node)[ri.edgeIndex]; - if (rootData.edgesSet[eIndex]) { - index.inCore = 0; - index.index = rootData.interiorRoots[eIndex]; - return 1; - } - } - return 0; -} -template -int Octree::SetMCRootPositions(TreeOctNode* node, int sDepth, Real isoValue, - TreeOctNode::ConstNeighborKey5& neighborKey5, RootData& rootData, std::vector>* interiorPositions, - CoredMeshData* mesh, const Real* metSolution, int nonLinearFit) { - Point3D position; - int eIndex; - RootInfo ri; - int count = 0; - if (!MarchingCubes::HasRoots(node->nodeData.mcIndex)) return 0; - for (int i = 0; i < DIMENSION; i++) - for (int j = 0; j < 2; j++) - for (int k = 0; k < 2; k++) { - long long key; - eIndex = Cube::EdgeIndex(i, j, k); - if (GetRootIndex(node, eIndex, fData.depth, ri)) { - key = ri.key; - if (!rootData.interiorRoots || IsBoundaryEdge(node, i, j, k, sDepth)) { - std::unordered_map::iterator iter, end; - // Check if the root has already been set -#pragma omp critical(boundary_roots_hash_access) - { - iter = rootData.boundaryRoots.find(key); - end = rootData.boundaryRoots.end(); - } - if (iter == end) { - // Get the root information - GetRoot(ri, isoValue, neighborKey5, position, rootData, sDepth, metSolution, nonLinearFit); - // Add the root if it hasn't been added already -#pragma omp critical(boundary_roots_hash_access) - { - iter = rootData.boundaryRoots.find(key); - end = rootData.boundaryRoots.end(); - if (iter == end) { - mesh->inCorePoints.push_back(position); - rootData.boundaryRoots[key] = int(mesh->inCorePoints.size()) - 1; - } - } - if (iter == end) count++; - } - } else { - int nodeEdgeIndex = rootData.edgeIndices(ri.node)[ri.edgeIndex]; - if (!rootData.edgesSet[nodeEdgeIndex]) { - // Get the root information - GetRoot(ri, isoValue, neighborKey5, position, rootData, sDepth, metSolution, nonLinearFit); - // Add the root if it hasn't been added already -#pragma omp critical(add_point_access) - { - if (!rootData.edgesSet[nodeEdgeIndex]) { - rootData.interiorRoots[nodeEdgeIndex] = mesh->addOutOfCorePoint(position); - interiorPositions->push_back(position); - rootData.edgesSet[nodeEdgeIndex] = 1; - count++; - } - } - } - } - } - } - return count; -} -template -int Octree::SetBoundaryMCRootPositions( - int sDepth, Real isoValue, RootData& rootData, CoredMeshData* mesh, int nonLinearFit) { - Point3D position; - int i, j, k, eIndex, hits = 0; - RootInfo ri; - int count = 0; - TreeOctNode* node; - - node = tree.nextLeaf(); - while (node) { - if (MarchingCubes::HasRoots(node->nodeData.mcIndex)) { - hits = 0; - for (i = 0; i < DIMENSION; i++) - for (j = 0; j < 2; j++) - for (k = 0; k < 2; k++) - if (IsBoundaryEdge(node, i, j, k, sDepth)) { - hits++; - long long key; - eIndex = Cube::EdgeIndex(i, j, k); - if (GetRootIndex(node, eIndex, fData.depth, ri)) { - key = ri.key; - if (rootData.boundaryRoots.find(key) == rootData.boundaryRoots.end()) { - GetRoot(ri, isoValue, position, rootData, sDepth, nonLinearFit); - mesh->inCorePoints.push_back(position); - rootData.boundaryRoots[key] = int(mesh->inCorePoints.size()) - 1; - count++; - } - } - } - } - if (hits) - node = tree.nextLeaf(node); - else - node = tree.nextBranch(node); - } - return count; -} -template -void Octree::GetMCIsoEdges(TreeOctNode* node, int sDepth, std::vector>& edges) { - TreeOctNode* temp; - int count = 0, tris = 0; - int isoTri[DIMENSION * MarchingCubes::MAX_TRIANGLES]; - FaceEdgesFunction fef; - int ref, fIndex; - std::unordered_map> vertexCount; - - fef.edges = &edges; - fef.maxDepth = fData.depth; - fef.vertexCount = &vertexCount; - count = MarchingCubes::AddTriangleIndices(node->nodeData.mcIndex, isoTri); - for (fIndex = 0; fIndex < Cube::NEIGHBORS; fIndex++) { - ref = Cube::FaceReflectFaceIndex(fIndex, fIndex); - fef.fIndex = ref; - temp = node->faceNeighbor(fIndex); - // If the face neighbor exists and has higher resolution than the current node, - // get the iso-curve from the neighbor - if (temp && temp->children && !IsBoundaryFace(node, fIndex, sDepth)) temp->processNodeFaces(temp, &fef, ref); - // Otherwise, get it from the node - else { - RootInfo ri1, ri2; - for (int j = 0; j < count; j++) - for (int k = 0; k < 3; k++) - if (fIndex == Cube::FaceAdjacentToEdges(isoTri[j * 3 + k], isoTri[j * 3 + ((k + 1) % 3)])) - if (GetRootIndex(node, isoTri[j * 3 + k], fData.depth, ri1) && - GetRootIndex(node, isoTri[j * 3 + ((k + 1) % 3)], fData.depth, ri2)) { - long long key1 = ri1.key, key2 = ri2.key; - edges.push_back(std::pair(ri1, ri2)); - if (vertexCount.count(key1) == 0) { - vertexCount[key1].first = ri1; - vertexCount[key1].second = 0; - } - if (vertexCount.count(key2) == 0) { - vertexCount[key2].first = ri2; - vertexCount[key2].second = 0; - } - vertexCount[key1].second++; - vertexCount[key2].second--; - } else { - int r1 = MarchingCubes::HasEdgeRoots(node->nodeData.mcIndex, isoTri[j * 3 + k]); - int r2 = MarchingCubes::HasEdgeRoots(node->nodeData.mcIndex, isoTri[j * 3 + ((k + 1) % 3)]); - fprintf(stderr, "Bad Edge 2: %d %d\t%d %d\n", ri1.key, ri2.key, r1, r2); - } - } - } - for (int i = 0; i < int(edges.size()); i++) { - if (vertexCount.count(edges[i].first.key) == 0) - printf("Could not find vertex: %lld\n", edges[i].first); - else if (vertexCount[edges[i].first.key].second) { - RootInfo ri; - GetRootPair(vertexCount[edges[i].first.key].first, fData.depth, ri); - long long key = ri.key; - if (vertexCount.count(key) == 0) { - int d, off[3]; - node->depthAndOffset(d, off); - printf("Vertex pair not in list 1 (%lld) %d\t[%d] (%d %d %d)\n", key, - IsBoundaryEdge(ri.node, ri.edgeIndex, sDepth), d, off[0], off[1], off[2]); - } else { - edges.push_back(std::pair(ri, edges[i].first)); - vertexCount[key].second++; - vertexCount[edges[i].first.key].second--; - } - } - - if (vertexCount.count(edges[i].second.key) == 0) - printf("Could not find vertex: %lld\n", edges[i].second); - else if (vertexCount[edges[i].second.key].second) { - RootInfo ri; - GetRootPair(vertexCount[edges[i].second.key].first, fData.depth, ri); - long long key = ri.key; - if (vertexCount.count(key)) { - int d, off[3]; - node->depthAndOffset(d, off); - printf("Vertex pair not in list 2\t[%d] (%d %d %d)\n", d, off[0], off[1], off[2]); - } else { - edges.push_back(std::pair(edges[i].second, ri)); - vertexCount[key].second--; - vertexCount[edges[i].second.key].second++; - } - } - } -} -template -#if MISHA_DEBUG -int Octree::GetMCIsoTriangles(TreeOctNode* node, CoredMeshData* mesh, RootData& rootData, - std::vector>* interiorPositions, int offSet, int sDepth, bool polygonMesh, - std::vector>* barycenters) -#else // !MISHA_DEBUG -int Octree::GetMCIsoTriangles(TreeOctNode* node, CoredMeshData* mesh, RootData& rootData, - std::vector>* interiorPositions, int offSet, int sDepth, bool addBarycenter, bool polygonMesh) -#endif // MISHA_DEBUG -{ - int tris = 0; - std::vector> edges; - std::vector>> edgeLoops; - GetMCIsoEdges(node, sDepth, edges); - - GetEdgeLoops(edges, edgeLoops); - for (int i = 0; i < int(edgeLoops.size()); i++) { - CoredPointIndex p; - std::vector edgeIndices; - for (int j = 0; j < int(edgeLoops[i].size()); j++) { - if (!GetRootIndex(edgeLoops[i][j].first, rootData, p)) - printf("Bad Point Index\n"); - else - edgeIndices.push_back(p); - } -#if MISHA_DEBUG - tris += AddTriangles(mesh, edgeIndices, interiorPositions, offSet, polygonMesh, barycenters); -#else // !MISHA_DEBUG - tris += AddTriangles(mesh, edgeIndices, interiorPositions, offSet, addBarycenter, polygonMesh); -#endif // MISHA_DEBUG - } - return tris; -} - -template -int Octree::GetEdgeLoops( - std::vector>& edges, std::vector>>& loops) { - int loopSize = 0; - long long frontIdx, backIdx; - std::pair e, temp; - loops.clear(); - - while (edges.size()) { - std::vector> front, back; - e = edges[0]; - loops.resize(loopSize + 1); - edges[0] = edges.back(); - edges.pop_back(); - frontIdx = e.second.key; - backIdx = e.first.key; - for (int j = int(edges.size()) - 1; j >= 0; j--) { - if (edges[j].first.key == frontIdx || edges[j].second.key == frontIdx) { - if (edges[j].first.key == frontIdx) - temp = edges[j]; - else - temp.first = edges[j].second, temp.second = edges[j].first; - frontIdx = temp.second.key; - front.push_back(temp); - edges[j] = edges.back(); - edges.pop_back(); - j = int(edges.size()); - } else if (edges[j].first.key == backIdx || edges[j].second.key == backIdx) { - if (edges[j].second.key == backIdx) - temp = edges[j]; - else - temp.first = edges[j].second, temp.second = edges[j].first; - backIdx = temp.first.key; - back.push_back(temp); - edges[j] = edges.back(); - edges.pop_back(); - j = int(edges.size()); - } - } - for (int j = int(back.size()) - 1; j >= 0; j--) loops[loopSize].push_back(back[j]); - loops[loopSize].push_back(e); - for (int j = 0; j < int(front.size()); j++) loops[loopSize].push_back(front[j]); - loopSize++; - } - return int(loops.size()); -} -template -#if MISHA_DEBUG -int Octree::AddTriangles(CoredMeshData* mesh, std::vector& edges, - std::vector>* interiorPositions, int offSet, bool polygonMesh, - std::vector>* barycenters) -#else // !MISHA_DEBUG -int Octree::AddTriangles(CoredMeshData* mesh, std::vector& edges, - std::vector>* interiorPositions, int offSet, bool addBarycenter, bool polygonMesh) -#endif // MISHA_DEBUG -{ - MinimalAreaTriangulation MAT; - std::vector> vertices; - std::vector triangles; - if (polygonMesh) { - std::vector vertices(edges.size()); - for (int i = 0; i < int(edges.size()); i++) { - vertices[i].idx = edges[i].index; - vertices[i].inCore = (edges[i].inCore != 0); - } -#pragma omp critical(add_polygon_access) - { mesh->addPolygon(vertices); } - return 1; - } - if (edges.size() > 3) { - bool isCoplanar = false; - -#if MISHA_DEBUG - if (barycenters) -#else // !MISHA_DEBUG - if (addBarycenter) -#endif // MISHA_DEBUG - for (int i = 0; i < int(edges.size()); i++) - for (int j = 0; j < i; j++) - if ((i + 1) % edges.size() != j && (j + 1) % edges.size() != i) { - Point3D v1, v2; - if (edges[i].inCore) - v1 = mesh->inCorePoints[edges[i].index]; - else - v1 = (*interiorPositions)[edges[i].index - offSet]; - if (edges[j].inCore) - v2 = mesh->inCorePoints[edges[j].index]; - else - v2 = (*interiorPositions)[edges[j].index - offSet]; - for (int k = 0; k < 3; k++) - if (v1[k] == v2[k]) isCoplanar = true; - } - if (isCoplanar) { - Point3D c; - c[0] = c[1] = c[2] = 0; - for (int i = 0; i < int(edges.size()); i++) { - Point3D p; - if (edges[i].inCore) - p = mesh->inCorePoints[edges[i].index]; - else - p = (*interiorPositions)[edges[i].index - offSet]; - c += p; - } - c /= Real(edges.size()); - int cIdx; -#pragma omp critical(add_point_access) - { - cIdx = mesh->addOutOfCorePoint(c); -#if MISHA_DEBUG - barycenters->push_back(c); -#else // !MISHA_DEBUG - interiorPositions->push_back(c); -#endif // MISHA_DEBUG - } - for (int i = 0; i < int(edges.size()); i++) { - std::vector vertices(3); - vertices[0].idx = edges[i].index; - vertices[1].idx = edges[(i + 1) % edges.size()].index; - vertices[2].idx = cIdx; - vertices[0].inCore = (edges[i].inCore != 0); - vertices[1].inCore = (edges[(i + 1) % edges.size()].inCore != 0); - vertices[2].inCore = 0; -#pragma omp critical(add_polygon_access) - { mesh->addPolygon(vertices); } - } - return int(edges.size()); - } else { - vertices.resize(edges.size()); - // Add the points - for (int i = 0; i < int(edges.size()); i++) { - Point3D p; - if (edges[i].inCore) - p = mesh->inCorePoints[edges[i].index]; - else - p = (*interiorPositions)[edges[i].index - offSet]; - vertices[i] = p; - } - MAT.GetTriangulation(vertices, triangles); - for (int i = 0; i < int(triangles.size()); i++) { - std::vector _vertices(3); - for (int j = 0; j < 3; j++) { - _vertices[j].idx = edges[triangles[i].idx[j]].index; - _vertices[j].inCore = (edges[triangles[i].idx[j]].inCore != 0); - } -#pragma omp critical(add_polygon_access) - { mesh->addPolygon(_vertices); } - } - } - } else if (edges.size() == 3) { - std::vector vertices(3); - for (int i = 0; i < 3; i++) { - vertices[i].idx = edges[i].index; - vertices[i].inCore = (edges[i].inCore != 0); - } -#pragma omp critical(add_polygon_access) - mesh->addPolygon(vertices); - } - return int(edges.size()) - 2; -} -template Real* Octree::GetSolutionGrid(int& res, float isoValue, int depth) { - if (depth <= 0 || depth > tree.maxDepth()) depth = tree.maxDepth(); - BSplineData fData; - fData.set(depth); - fData.setValueTables(fData.VALUE_FLAG); - res = 1 << depth; - Real* values = new float[res * res * res]; - memset(values, 0, sizeof(float) * res * res * res); - - for (TreeOctNode* n = tree.nextNode(); n; n = tree.nextNode(n)) { - if (n->d > depth) continue; - if (n->d < _minDepth) continue; - int d, idx[3], start[3], end[3]; - n->depthAndOffset(d, idx); - for (int i = 0; i < 3; i++) { - // Get the index of the functions - idx[i] = BinaryNode::CenterIndex(d, idx[i]); - // Figure out which samples fall into the range - fData.setSampleSpan(idx[i], start[i], end[i]); - // We only care about the odd indices - if (!(start[i] & 1)) start[i]++; - if (!(end[i] & 1)) end[i]--; - } - Real coefficient = n->nodeData.solution; - for (int x = start[0]; x <= end[0]; x += 2) - for (int y = start[1]; y <= end[1]; y += 2) - for (int z = start[2]; z <= end[2]; z += 2) { - int xx = (x - 1) >> 1, yy = (y - 1) >> 1, zz = (z - 1) >> 1; - values[zz * res * res + yy * res + xx] += coefficient * - fData.valueTables[idx[0] + x * fData.functionCount] * - fData.valueTables[idx[1] + y * fData.functionCount] * - fData.valueTables[idx[2] + z * fData.functionCount]; - } - } - for (int i = 0; i < res * res * res; i++) values[i] -= isoValue; - - return values; -} -template Real* Octree::GetWeightGrid(int& res, int depth) { - if (depth <= 0 || depth > tree.maxDepth()) depth = tree.maxDepth(); - res = 1 << tree.maxDepth(); - Real* values = new float[res * res * res]; - memset(values, 0, sizeof(float) * res * res * res); - - for (TreeOctNode* n = tree.nextNode(); n; n = tree.nextNode(n)) { - if (n->d > depth) continue; - int d, idx[3], start[3], end[3]; - n->depthAndOffset(d, idx); - for (int i = 0; i < 3; i++) { - // Get the index of the functions - idx[i] = BinaryNode::CenterIndex(d, idx[i]); - // Figure out which samples fall into the range - fData.setSampleSpan(idx[i], start[i], end[i]); - // We only care about the odd indices - if (!(start[i] & 1)) start[i]++; - if (!(end[i] & 1)) end[i]--; - } - for (int x = start[0]; x <= end[0]; x += 2) - for (int y = start[1]; y <= end[1]; y += 2) - for (int z = start[2]; z <= end[2]; z += 2) { - int xx = (x - 1) >> 1, yy = (y - 1) >> 1, zz = (z - 1) >> 1; - values[zz * res * res + yy * res + xx] += n->nodeData.centerWeightContribution * - fData.valueTables[idx[0] + x * fData.functionCount] * - fData.valueTables[idx[1] + y * fData.functionCount] * - fData.valueTables[idx[2] + z * fData.functionCount]; - } - } - return values; -} - -//////////////// -// VertexData // -//////////////// -inline long long VertexData::CenterIndex(const TreeOctNode* node, int maxDepth) { - int idx[DIMENSION]; - return CenterIndex(node, maxDepth, idx); -} -inline long long VertexData::CenterIndex(const TreeOctNode* node, int maxDepth, int idx[DIMENSION]) { - int d, o[3]; - node->depthAndOffset(d, o); - for (int i = 0; i < DIMENSION; i++) { - idx[i] = BinaryNode::CornerIndex(maxDepth + 1, d + 1, o[i] << 1, 1); - } - return (long long)(idx[0]) | (long long)(idx[1]) << 15 | (long long)(idx[2]) << 30; -} -inline long long VertexData::CenterIndex(int depth, const int offSet[DIMENSION], int maxDepth, int idx[DIMENSION]) { - for (int i = 0; i < DIMENSION; i++) { - idx[i] = BinaryNode::CornerIndex(maxDepth + 1, depth + 1, offSet[i] << 1, 1); - } - return (long long)(idx[0]) | (long long)(idx[1]) << 15 | (long long)(idx[2]) << 30; -} -inline long long VertexData::CornerIndex(const TreeOctNode* node, int cIndex, int maxDepth) { - int idx[DIMENSION]; - return CornerIndex(node, cIndex, maxDepth, idx); -} -inline long long VertexData::CornerIndex(const TreeOctNode* node, int cIndex, int maxDepth, int idx[DIMENSION]) { - int x[DIMENSION]; - Cube::FactorCornerIndex(cIndex, x[0], x[1], x[2]); - int d, o[3]; - node->depthAndOffset(d, o); - for (int i = 0; i < DIMENSION; i++) idx[i] = BinaryNode::CornerIndex(maxDepth + 1, d, o[i], x[i]); - return CornerIndexKey(idx); -} -inline long long VertexData::CornerIndex( - int depth, const int offSet[DIMENSION], int cIndex, int maxDepth, int idx[DIMENSION]) { - int x[DIMENSION]; - Cube::FactorCornerIndex(cIndex, x[0], x[1], x[2]); - for (int i = 0; i < DIMENSION; i++) idx[i] = BinaryNode::CornerIndex(maxDepth + 1, depth, offSet[i], x[i]); - return CornerIndexKey(idx); -} - -inline long long VertexData::CornerIndexKey(const int idx[DIMENSION]) { - return (long long)(idx[0]) | (long long)(idx[1]) << 15 | (long long)(idx[2]) << 30; -} - -inline long long VertexData::FaceIndex(const TreeOctNode* node, int fIndex, int maxDepth) { - int idx[DIMENSION]; - return FaceIndex(node, fIndex, maxDepth, idx); -} - -inline long long VertexData::FaceIndex(const TreeOctNode* node, int fIndex, int maxDepth, int idx[DIMENSION]) { - int dir, offset; - Cube::FactorFaceIndex(fIndex, dir, offset); - int d, o[3]; - node->depthAndOffset(d, o); - for (int i = 0; i < DIMENSION; i++) { - idx[i] = BinaryNode::CornerIndex(maxDepth + 1, d + 1, o[i] << 1, 1); - } - idx[dir] = BinaryNode::CornerIndex(maxDepth + 1, d, o[dir], offset); - return (long long)(idx[0]) | (long long)(idx[1]) << 15 | (long long)(idx[2]) << 30; -} - -inline long long VertexData::EdgeIndex(const TreeOctNode* node, int eIndex, int maxDepth) { - int idx[DIMENSION]; - return EdgeIndex(node, eIndex, maxDepth, idx); -} - -inline long long VertexData::EdgeIndex(const TreeOctNode* node, int eIndex, int maxDepth, int idx[DIMENSION]) { - int o, i1, i2; - int d, off[3]; - node->depthAndOffset(d, off); - for (int i = 0; i < DIMENSION; i++) { - idx[i] = BinaryNode::CornerIndex(maxDepth + 1, d + 1, off[i] << 1, 1); - } - Cube::FactorEdgeIndex(eIndex, o, i1, i2); - switch (o) { - case 0: - idx[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[1], i1); - idx[2] = BinaryNode::CornerIndex(maxDepth + 1, d, off[2], i2); - break; - case 1: - idx[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[0], i1); - idx[2] = BinaryNode::CornerIndex(maxDepth + 1, d, off[2], i2); - break; - case 2: - idx[0] = BinaryNode::CornerIndex(maxDepth + 1, d, off[0], i1); - idx[1] = BinaryNode::CornerIndex(maxDepth + 1, d, off[1], i2); - break; - }; - return (long long)(idx[0]) | (long long)(idx[1]) << 15 | (long long)(idx[2]) << 30; -} - - -} // namespace poisson -} // namespace pcl diff --git a/plugins/probe/3rd/poisson4/octree_poisson.h b/plugins/probe/3rd/poisson4/octree_poisson.h deleted file mode 100644 index 6d82d35c3a..0000000000 --- a/plugins/probe/3rd/poisson4/octree_poisson.h +++ /dev/null @@ -1,287 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef OCT_NODE_INCLUDED -#define OCT_NODE_INCLUDED - -#if defined __GNUC__ -# pragma GCC system_header -#endif - -#include "poisson4/allocator.h" -#include "poisson4/binary_node.h" -#include "poisson4/marching_cubes_poisson.h" - -#define DIMENSION 3 - -namespace pcl -{ - namespace poisson - { - - template< class NodeData , class Real=float > - class OctNode - { - private: - static int UseAlloc; - - class AdjacencyCountFunction - { - public: - int count; - void Function( const OctNode* node1 , const OctNode* node2 ); - }; - template - void __processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2,int cIndex3,int cIndex4); - template - void __processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2); - template - void __processNodeNodes(OctNode* node,NodeAdjacencyFunction* F); - template - static void __ProcessNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,NodeAdjacencyFunction* F); - template - static void __ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,TerminatingNodeAdjacencyFunction* F); - template - static void __ProcessPointAdjacentNodes(int dx,int dy,int dz,OctNode* node2,int radius2,int cWidth2,PointAdjacencyFunction* F); - template - static void __ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,int depth,NodeAdjacencyFunction* F); - template - static void __ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int cWidth2,int depth,NodeAdjacencyFunction* F); - - // This is made private because the division by two has been pulled out. - static inline int Overlap(int c1,int c2,int c3,int dWidth); - inline static int ChildOverlap(int dx,int dy,int dz,int d,int cRadius2); - - const OctNode* __faceNeighbor(int dir,int off) const; - const OctNode* __edgeNeighbor(int o,const int i[2],const int idx[2]) const; - OctNode* __faceNeighbor(int dir,int off,int forceChildren); - OctNode* __edgeNeighbor(int o,const int i[2],const int idx[2],int forceChildren); - public: - static const int DepthShift,OffsetShift,OffsetShift1,OffsetShift2,OffsetShift3; - static const int DepthMask,OffsetMask; - - static Allocator internalAllocator; - static int UseAllocator(void); - static void SetAllocator(int blockSize); - - OctNode* parent; - OctNode* children; - short d , off[DIMENSION]; - NodeData nodeData; - - OctNode(void); - ~OctNode(void); - int initChildren(void); - - void depthAndOffset(int& depth,int offset[DIMENSION]) const; - int depth(void) const; - static inline void DepthAndOffset(const long long& index,int& depth,int offset[DIMENSION]); - static inline void CenterAndWidth(const long long& index,Point3D& center,Real& width); - static inline int Depth(const long long& index); - static inline void Index(int depth,const int offset[3],short& d,short off[DIMENSION]); - void centerAndWidth( Point3D& center , Real& width ) const; - bool isInside( Point3D< Real > p ) const; - - int leaves(void) const; - int maxDepthLeaves(int maxDepth) const; - int nodes(void) const; - int maxDepth(void) const; - - const OctNode* root(void) const; - - const OctNode* nextLeaf(const OctNode* currentLeaf=NULL) const; - OctNode* nextLeaf(OctNode* currentLeaf=NULL); - const OctNode* nextNode(const OctNode* currentNode=NULL) const; - OctNode* nextNode(OctNode* currentNode=NULL); - const OctNode* nextBranch(const OctNode* current) const; - OctNode* nextBranch(OctNode* current); - const OctNode* prevBranch(const OctNode* current) const; - OctNode* prevBranch(OctNode* current); - - void setFullDepth(int maxDepth); - - void printLeaves(void) const; - void printRange(void) const; - - template - void processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int fIndex,int processCurrent=1); - template - void processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int eIndex,int processCurrent=1); - template - void processNodeCorners(OctNode* node,NodeAdjacencyFunction* F,int cIndex,int processCurrent=1); - template - void processNodeNodes(OctNode* node,NodeAdjacencyFunction* F,int processCurrent=1); - - template - static void ProcessNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessTerminatingNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,TerminatingNodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,TerminatingNodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessPointAdjacentNodes(int maxDepth,const int center1[3],OctNode* node2,int width2,PointAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessPointAdjacentNodes(int dx,int dy,int dz,OctNode* node2,int radius2,int width2,PointAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessFixedDepthNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessMaxDepthNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - template - static void ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz,OctNode* node1,int radius1,OctNode* node2,int radius2,int width2,int depth,NodeAdjacencyFunction* F,int processCurrent=1); - - static int CornerIndex(const Point3D& center,const Point3D &p); - - OctNode* faceNeighbor(int faceIndex,int forceChildren=0); - const OctNode* faceNeighbor(int faceIndex) const; - OctNode* edgeNeighbor(int edgeIndex,int forceChildren=0); - const OctNode* edgeNeighbor(int edgeIndex) const; - OctNode* cornerNeighbor(int cornerIndex,int forceChildren=0); - const OctNode* cornerNeighbor(int cornerIndex) const; - - OctNode* getNearestLeaf(const Point3D& p); - const OctNode* getNearestLeaf(const Point3D& p) const; - - static int CommonEdge(const OctNode* node1,int eIndex1,const OctNode* node2,int eIndex2); - static int CompareForwardDepths(const void* v1,const void* v2); - static int CompareByDepthAndXYZ( const void* v1 , const void* v2 ); - static int CompareByDepthAndZIndex( const void* v1 , const void* v2 ); - static int CompareForwardPointerDepths(const void* v1,const void* v2); - static int CompareBackwardDepths(const void* v1,const void* v2); - static int CompareBackwardPointerDepths(const void* v1,const void* v2); - - - template - OctNode& operator = (const OctNode& node); - - static inline int Overlap2(const int &depth1,const int offSet1[DIMENSION],const Real& multiplier1,const int &depth2,const int offSet2[DIMENSION],const Real& multiplier2); - - - int write(const char* fileName) const; - int write(FILE* fp) const; - int read(const char* fileName); - int read(FILE* fp); - - class Neighbors3 - { - public: - OctNode* neighbors[3][3][3]; - Neighbors3( void ); - void clear( void ); - }; - class NeighborKey3 - { - public: - Neighbors3* neighbors; - - NeighborKey3( void ); - ~NeighborKey3( void ); - - void set( int depth ); - Neighbors3& setNeighbors( OctNode* root , Point3D< Real > p , int d ); - Neighbors3& getNeighbors( OctNode* root , Point3D< Real > p , int d ); - Neighbors3& setNeighbors( OctNode* node , bool flags[3][3][3] ); - Neighbors3& setNeighbors( OctNode* node ); - Neighbors3& getNeighbors( OctNode* node ); - }; - class ConstNeighbors3 - { - public: - const OctNode* neighbors[3][3][3]; - ConstNeighbors3( void ); - void clear( void ); - }; - class ConstNeighborKey3 - { - public: - ConstNeighbors3* neighbors; - - ConstNeighborKey3(void); - ~ConstNeighborKey3(void); - - void set(int depth); - ConstNeighbors3& getNeighbors( const OctNode* node ); - ConstNeighbors3& getNeighbors( const OctNode* node , int minDepth ); - }; - class Neighbors5 - { - public: - OctNode* neighbors[5][5][5]; - Neighbors5( void ); - void clear( void ); - }; - class ConstNeighbors5 - { - public: - const OctNode* neighbors[5][5][5]; - ConstNeighbors5( void ); - void clear( void ); - }; - - class NeighborKey5 - { - int _depth; - public: - Neighbors5* neighbors; - - NeighborKey5( void ); - ~NeighborKey5( void ); - - void set( int depth ); - Neighbors5& getNeighbors( OctNode* node ); - Neighbors5& setNeighbors( OctNode* node , int xStart=0 , int xEnd=5 , int yStart=0 , int yEnd=5 , int zStart=0 , int zEnd=5 ); - }; - class ConstNeighborKey5 - { - int _depth; - public: - ConstNeighbors5* neighbors; - - ConstNeighborKey5( void ); - ~ConstNeighborKey5( void ); - - void set( int depth ); - ConstNeighbors5& getNeighbors( const OctNode* node ); - }; - - void centerIndex(int maxDepth,int index[DIMENSION]) const; - int width(int maxDepth) const; - }; - - - } -} - -#include "poisson4/octree_poisson.hpp" - - - -#endif // OCT_NODE diff --git a/plugins/probe/3rd/poisson4/octree_poisson.hpp b/plugins/probe/3rd/poisson4/octree_poisson.hpp deleted file mode 100644 index 3183f0629e..0000000000 --- a/plugins/probe/3rd/poisson4/octree_poisson.hpp +++ /dev/null @@ -1,1916 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -extern "C" { -#include -} -#include -#include - -#include "poisson4/poisson_exceptions.h" - -///////////// -// OctNode // -///////////// - -namespace pcl -{ - namespace poisson - { - - template const int OctNode::DepthShift=5; - template const int OctNode::OffsetShift=19; - template const int OctNode::DepthMask=(1< const int OctNode::OffsetMask=(1< const int OctNode::OffsetShift1=DepthShift; - template const int OctNode::OffsetShift2=OffsetShift1+OffsetShift; - template const int OctNode::OffsetShift3=OffsetShift2+OffsetShift; - - template int OctNode::UseAlloc=0; - template Allocator > OctNode::internalAllocator; - - template - void OctNode::SetAllocator(int blockSize) - { - if(blockSize>0) - { - UseAlloc=1; - internalAllocator.set(blockSize); - } - else{UseAlloc=0;} - } - template - int OctNode::UseAllocator(void){return UseAlloc;} - - template - OctNode::OctNode(void){ - parent=children=NULL; - d=off[0]=off[1]=off[2]=0; - } - - template - OctNode::~OctNode(void){ - if(!UseAlloc){if(children){delete[] children;}} - parent=children=NULL; - } - template - void OctNode::setFullDepth(int maxDepth){ - if( maxDepth ) - { - if( !children ) initChildren(); - for( int i=0 ; i<8 ; i++ ) children[i].setFullDepth( maxDepth-1 ); - } - } - - template - int OctNode::initChildren(void){ - int i,j,k; - - if(UseAlloc){children=internalAllocator.newElements(8);} - else{ - if(children){delete[] children;} - children=NULL; - children=new OctNode[Cube::CORNERS]; - } - if(!children){ - POISSON_THROW_EXCEPTION (pcl::poisson::PoissonBadInitException, "Failed to initialize OctNode children."); - } - int d,off[3]; - depthAndOffset(d,off); - for(i=0;i<2;i++){ - for(j=0;j<2;j++){ - for(k=0;k<2;k++){ - int idx=Cube::CornerIndex(i,j,k); - children[idx].parent=this; - children[idx].children=NULL; - int off2[3]; - off2[0]=(off[0]<<1)+i; - off2[1]=(off[1]<<1)+j; - off2[2]=(off[2]<<1)+k; - Index(d+1,off2,children[idx].d,children[idx].off); - } - } - } - return 1; - } - template - inline void OctNode::Index(int depth,const int offset[3],short& d,short off[3]){ - d=short(depth); - off[0]=short((1< - inline void OctNode::depthAndOffset(int& depth,int offset[3]) const { - depth=int(d); - offset[0]=(int(off[0])+1)&(~(1< - inline int OctNode::depth(void) const {return int(d);} - template - inline void OctNode::DepthAndOffset(const long long& index,int& depth,int offset[3]){ - depth=int(index&DepthMask); - offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< - inline int OctNode::Depth(const long long& index){return int(index&DepthMask);} - template - void OctNode::centerAndWidth(Point3D& center,Real& width) const{ - int depth,offset[3]; - depth=int(d); - offset[0]=(int(off[0])+1)&(~(1< - bool OctNode< NodeData , Real >::isInside( Point3D< Real > p ) const - { - Point3D< Real > c; - Real w; - centerAndWidth( c , w ); - w /= 2; - return (c[0]-w) - inline void OctNode::CenterAndWidth(const long long& index,Point3D& center,Real& width){ - int depth,offset[3]; - depth=index&DepthMask; - offset[0]=(int((index>>OffsetShift1)&OffsetMask)+1)&(~(1<>OffsetShift2)&OffsetMask)+1)&(~(1<>OffsetShift3)&OffsetMask)+1)&(~(1< - int OctNode::maxDepth(void) const{ - if(!children){return 0;} - else{ - int c,d; - for(int i=0;ic){c=d;} - } - return c+1; - } - } - template - int OctNode::nodes(void) const{ - if(!children){return 1;} - else{ - int c=0; - for(int i=0;i - int OctNode::leaves(void) const{ - if(!children){return 1;} - else{ - int c=0; - for(int i=0;i - int OctNode::maxDepthLeaves(int maxDepth) const{ - if(depth()>maxDepth){return 0;} - if(!children){return 1;} - else{ - int c=0; - for(int i=0;i - const OctNode* OctNode::root(void) const{ - const OctNode* temp=this; - while(temp->parent){temp=temp->parent;} - return temp; - } - - - template - const OctNode* OctNode::nextBranch( const OctNode* current ) const - { - if( !current->parent || current==this ) return NULL; - if(current-current->parent->children==Cube::CORNERS-1) return nextBranch( current->parent ); - else return current+1; - } - template - OctNode* OctNode::nextBranch(OctNode* current){ - if(!current->parent || current==this){return NULL;} - if(current-current->parent->children==Cube::CORNERS-1){return nextBranch(current->parent);} - else{return current+1;} - } - template< class NodeData , class Real > - const OctNode< NodeData , Real >* OctNode< NodeData , Real >::prevBranch( const OctNode* current ) const - { - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; - } - template< class NodeData , class Real > - OctNode< NodeData , Real >* OctNode< NodeData , Real >::prevBranch( OctNode* current ) - { - if( !current->parent || current==this ) return NULL; - if( current-current->parent->children==0 ) return prevBranch( current->parent ); - else return current-1; - } - template - const OctNode* OctNode::nextLeaf(const OctNode* current) const{ - if(!current){ - const OctNode* temp=this; - while(temp->children){temp=&temp->children[0];} - return temp; - } - if(current->children){return current->nextLeaf();} - const OctNode* temp=nextBranch(current); - if(!temp){return NULL;} - else{return temp->nextLeaf();} - } - template - OctNode* OctNode::nextLeaf(OctNode* current){ - if(!current){ - OctNode* temp=this; - while(temp->children){temp=&temp->children[0];} - return temp; - } - if(current->children){return current->nextLeaf();} - OctNode* temp=nextBranch(current); - if(!temp){return NULL;} - else{return temp->nextLeaf();} - } - - template - const OctNode* OctNode::nextNode( const OctNode* current ) const - { - if( !current ) return this; - else if( current->children ) return ¤t->children[0]; - else return nextBranch(current); - } - template - OctNode* OctNode::nextNode( OctNode* current ) - { - if( !current ) return this; - else if( current->children ) return ¤t->children[0]; - else return nextBranch( current ); - } - - template - void OctNode::printRange(void) const{ - Point3D center; - Real width; - centerAndWidth(center,width); - for(int dim=0;dim - void OctNode::AdjacencyCountFunction::Function(const OctNode* node1,const OctNode* node2){count++;} - - template - template - void OctNode::processNodeNodes(OctNode* node,NodeAdjacencyFunction* F,int processCurrent){ - if(processCurrent){F->Function(this,node);} - if(children){__processNodeNodes(node,F);} - } - template - template - void OctNode::processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int fIndex,int processCurrent){ - if(processCurrent){F->Function(this,node);} - if(children){ - int c1,c2,c3,c4; - Cube::FaceCorners(fIndex,c1,c2,c3,c4); - __processNodeFaces(node,F,c1,c2,c3,c4); - } - } - template - template - void OctNode::processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int eIndex,int processCurrent){ - if(processCurrent){F->Function(this,node);} - if(children){ - int c1,c2; - Cube::EdgeCorners(eIndex,c1,c2); - __processNodeEdges(node,F,c1,c2); - } - } - template - template - void OctNode::processNodeCorners(OctNode* node,NodeAdjacencyFunction* F,int cIndex,int processCurrent){ - if(processCurrent){F->Function(this,node);} - OctNode* temp=this; - while(temp->children){ - temp=&temp->children[cIndex]; - F->Function(temp,node); - } - } - template - template - void OctNode::__processNodeNodes(OctNode* node,NodeAdjacencyFunction* F){ - F->Function(&children[0],node); - F->Function(&children[1],node); - F->Function(&children[2],node); - F->Function(&children[3],node); - F->Function(&children[4],node); - F->Function(&children[5],node); - F->Function(&children[6],node); - F->Function(&children[7],node); - if(children[0].children){children[0].__processNodeNodes(node,F);} - if(children[1].children){children[1].__processNodeNodes(node,F);} - if(children[2].children){children[2].__processNodeNodes(node,F);} - if(children[3].children){children[3].__processNodeNodes(node,F);} - if(children[4].children){children[4].__processNodeNodes(node,F);} - if(children[5].children){children[5].__processNodeNodes(node,F);} - if(children[6].children){children[6].__processNodeNodes(node,F);} - if(children[7].children){children[7].__processNodeNodes(node,F);} - } - template - template - void OctNode::__processNodeEdges(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2){ - F->Function(&children[cIndex1],node); - F->Function(&children[cIndex2],node); - if(children[cIndex1].children){children[cIndex1].__processNodeEdges(node,F,cIndex1,cIndex2);} - if(children[cIndex2].children){children[cIndex2].__processNodeEdges(node,F,cIndex1,cIndex2);} - } - template - template - void OctNode::__processNodeFaces(OctNode* node,NodeAdjacencyFunction* F,int cIndex1,int cIndex2,int cIndex3,int cIndex4){ - F->Function(&children[cIndex1],node); - F->Function(&children[cIndex2],node); - F->Function(&children[cIndex3],node); - F->Function(&children[cIndex4],node); - if(children[cIndex1].children){children[cIndex1].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} - if(children[cIndex2].children){children[cIndex2].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} - if(children[cIndex3].children){children[cIndex3].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} - if(children[cIndex4].children){children[cIndex4].__processNodeFaces(node,F,cIndex1,cIndex2,cIndex3,cIndex4);} - } - template - template - void OctNode::ProcessNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,NodeAdjacencyFunction* F,int processCurrent){ - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - - ProcessNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,F,processCurrent); - } - template - template - void OctNode::ProcessNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int width2, - NodeAdjacencyFunction* F,int processCurrent){ - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(processCurrent){F->Function(node2,node1);} - if(!node2->children){return;} - __ProcessNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2/2,F); - } - template - template - void OctNode::ProcessTerminatingNodeAdjacentNodes(int maxDepth,OctNode* node1,int width1,OctNode* node2,int width2,TerminatingNodeAdjacencyFunction* F,int processCurrent){ - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - - ProcessTerminatingNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,F,processCurrent); - } - template - template - void OctNode::ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int width2, - TerminatingNodeAdjacencyFunction* F,int processCurrent) - { - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(processCurrent){F->Function(node2,node1);} - if(!node2->children){return;} - __ProcessTerminatingNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2/2,F); - } - template - template - void OctNode::ProcessPointAdjacentNodes( int maxDepth , const int c1[3] , OctNode* node2 , int width2 , PointAdjacencyFunction* F , int processCurrent ) - { - int c2[3] , w2; - node2->centerIndex( maxDepth+1 , c2 ); - w2 = node2->width( maxDepth+1 ); - ProcessPointAdjacentNodes( c1[0]-c2[0] , c1[1]-c2[1] , c1[2]-c2[2] , node2 , (width2*w2)>>1 , w2 , F , processCurrent ); - } - template - template - void OctNode::ProcessPointAdjacentNodes(int dx,int dy,int dz, - OctNode* node2,int radius2,int width2, - PointAdjacencyFunction* F,int processCurrent) - { - if( !Overlap(dx,dy,dz,radius2) ) return; - if( processCurrent ) F->Function(node2); - if( !node2->children ) return; - __ProcessPointAdjacentNodes( -dx , -dy , -dz , node2 , radius2 , width2>>1 , F ); - } - template - template - void OctNode::ProcessFixedDepthNodeAdjacentNodes(int maxDepth, - OctNode* node1,int width1, - OctNode* node2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) - { - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - - ProcessFixedDepthNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,depth,F,processCurrent); - } - template - template - void OctNode::ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) - { - int d=node2->depth(); - if(d>depth){return;} - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(d==depth){if(processCurrent){F->Function(node2,node1);}} - else{ - if(!node2->children){return;} - __ProcessFixedDepthNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2/2,depth-1,F); - } - } - template - template - void OctNode::ProcessMaxDepthNodeAdjacentNodes(int maxDepth, - OctNode* node1,int width1, - OctNode* node2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) - { - int c1[3],c2[3],w1,w2; - node1->centerIndex(maxDepth+1,c1); - node2->centerIndex(maxDepth+1,c2); - w1=node1->width(maxDepth+1); - w2=node2->width(maxDepth+1); - ProcessMaxDepthNodeAdjacentNodes(c1[0]-c2[0],c1[1]-c2[1],c1[2]-c2[2],node1,(width1*w1)>>1,node2,(width2*w2)>>1,w2,depth,F,processCurrent); - } - template - template - void OctNode::ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int width2, - int depth,NodeAdjacencyFunction* F,int processCurrent) - { - int d=node2->depth(); - if(d>depth){return;} - if(!Overlap(dx,dy,dz,radius1+radius2)){return;} - if(processCurrent){F->Function(node2,node1);} - if(dchildren){__ProcessMaxDepthNodeAdjacentNodes(-dx,-dy,-dz,node1,radius1,node2,radius2,width2>>1,depth-1,F);} - } - template - template - void OctNode::__ProcessNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - NodeAdjacencyFunction* F) - { - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(o& 1){F->Function(&node2->children[0],node1);if(node2->children[0].children){__ProcessNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,F);}} - if(o& 2){F->Function(&node2->children[1],node1);if(node2->children[1].children){__ProcessNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,F);}} - if(o& 4){F->Function(&node2->children[2],node1);if(node2->children[2].children){__ProcessNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,F);}} - if(o& 8){F->Function(&node2->children[3],node1);if(node2->children[3].children){__ProcessNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,F);}} - if(o& 16){F->Function(&node2->children[4],node1);if(node2->children[4].children){__ProcessNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,F);}} - if(o& 32){F->Function(&node2->children[5],node1);if(node2->children[5].children){__ProcessNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,F);}} - if(o& 64){F->Function(&node2->children[6],node1);if(node2->children[6].children){__ProcessNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,F);}} - if(o&128){F->Function(&node2->children[7],node1);if(node2->children[7].children){__ProcessNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,F);}} - } - } - template - template - void OctNode::__ProcessTerminatingNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - TerminatingNodeAdjacencyFunction* F) - { - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(o& 1){if(F->Function(&node2->children[0],node1) && node2->children[0].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,F);}} - if(o& 2){if(F->Function(&node2->children[1],node1) && node2->children[1].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,F);}} - if(o& 4){if(F->Function(&node2->children[2],node1) && node2->children[2].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,F);}} - if(o& 8){if(F->Function(&node2->children[3],node1) && node2->children[3].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,F);}} - if(o& 16){if(F->Function(&node2->children[4],node1) && node2->children[4].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,F);}} - if(o& 32){if(F->Function(&node2->children[5],node1) && node2->children[5].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,F);}} - if(o& 64){if(F->Function(&node2->children[6],node1) && node2->children[6].children){__ProcessTerminatingNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,F);}} - if(o&128){if(F->Function(&node2->children[7],node1) && node2->children[7].children){__ProcessTerminatingNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,F);}} - } - } - template - template - void OctNode::__ProcessPointAdjacentNodes(int dx,int dy,int dz, - OctNode* node2,int radius2,int cWidth2, - PointAdjacencyFunction* F) - { - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius,cWidth); - if( o ) - { - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(o& 1){F->Function(&node2->children[0]);if(node2->children[0].children){__ProcessPointAdjacentNodes(dx1,dy1,dz1,&node2->children[0],radius,cWidth,F);}} - if(o& 2){F->Function(&node2->children[1]);if(node2->children[1].children){__ProcessPointAdjacentNodes(dx2,dy1,dz1,&node2->children[1],radius,cWidth,F);}} - if(o& 4){F->Function(&node2->children[2]);if(node2->children[2].children){__ProcessPointAdjacentNodes(dx1,dy2,dz1,&node2->children[2],radius,cWidth,F);}} - if(o& 8){F->Function(&node2->children[3]);if(node2->children[3].children){__ProcessPointAdjacentNodes(dx2,dy2,dz1,&node2->children[3],radius,cWidth,F);}} - if(o& 16){F->Function(&node2->children[4]);if(node2->children[4].children){__ProcessPointAdjacentNodes(dx1,dy1,dz2,&node2->children[4],radius,cWidth,F);}} - if(o& 32){F->Function(&node2->children[5]);if(node2->children[5].children){__ProcessPointAdjacentNodes(dx2,dy1,dz2,&node2->children[5],radius,cWidth,F);}} - if(o& 64){F->Function(&node2->children[6]);if(node2->children[6].children){__ProcessPointAdjacentNodes(dx1,dy2,dz2,&node2->children[6],radius,cWidth,F);}} - if(o&128){F->Function(&node2->children[7]);if(node2->children[7].children){__ProcessPointAdjacentNodes(dx2,dy2,dz2,&node2->children[7],radius,cWidth,F);}} - } - } - template - template - void OctNode::__ProcessFixedDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - int depth,NodeAdjacencyFunction* F) - { - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(node2->depth()==depth){ - if(o& 1){F->Function(&node2->children[0],node1);} - if(o& 2){F->Function(&node2->children[1],node1);} - if(o& 4){F->Function(&node2->children[2],node1);} - if(o& 8){F->Function(&node2->children[3],node1);} - if(o& 16){F->Function(&node2->children[4],node1);} - if(o& 32){F->Function(&node2->children[5],node1);} - if(o& 64){F->Function(&node2->children[6],node1);} - if(o&128){F->Function(&node2->children[7],node1);} - } - else{ - if(o& 1){if(node2->children[0].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,depth,F);}} - if(o& 2){if(node2->children[1].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,depth,F);}} - if(o& 4){if(node2->children[2].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,depth,F);}} - if(o& 8){if(node2->children[3].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,depth,F);}} - if(o& 16){if(node2->children[4].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,depth,F);}} - if(o& 32){if(node2->children[5].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,depth,F);}} - if(o& 64){if(node2->children[6].children){__ProcessFixedDepthNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,depth,F);}} - if(o&128){if(node2->children[7].children){__ProcessFixedDepthNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,depth,F);}} - } - } - } - template - template - void OctNode::__ProcessMaxDepthNodeAdjacentNodes(int dx,int dy,int dz, - OctNode* node1,int radius1, - OctNode* node2,int radius2,int cWidth2, - int depth,NodeAdjacencyFunction* F) - { - int cWidth=cWidth2>>1; - int radius=radius2>>1; - int o=ChildOverlap(dx,dy,dz,radius1+radius,cWidth); - if(o){ - int dx1=dx-cWidth; - int dx2=dx+cWidth; - int dy1=dy-cWidth; - int dy2=dy+cWidth; - int dz1=dz-cWidth; - int dz2=dz+cWidth; - if(node2->depth()<=depth){ - if(o& 1){F->Function(&node2->children[0],node1);} - if(o& 2){F->Function(&node2->children[1],node1);} - if(o& 4){F->Function(&node2->children[2],node1);} - if(o& 8){F->Function(&node2->children[3],node1);} - if(o& 16){F->Function(&node2->children[4],node1);} - if(o& 32){F->Function(&node2->children[5],node1);} - if(o& 64){F->Function(&node2->children[6],node1);} - if(o&128){F->Function(&node2->children[7],node1);} - } - if(node2->depth()children[0].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy1,dz1,node1,radius1,&node2->children[0],radius,cWidth,depth,F);}} - if(o& 2){if(node2->children[1].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy1,dz1,node1,radius1,&node2->children[1],radius,cWidth,depth,F);}} - if(o& 4){if(node2->children[2].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy2,dz1,node1,radius1,&node2->children[2],radius,cWidth,depth,F);}} - if(o& 8){if(node2->children[3].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy2,dz1,node1,radius1,&node2->children[3],radius,cWidth,depth,F);}} - if(o& 16){if(node2->children[4].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy1,dz2,node1,radius1,&node2->children[4],radius,cWidth,depth,F);}} - if(o& 32){if(node2->children[5].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy1,dz2,node1,radius1,&node2->children[5],radius,cWidth,depth,F);}} - if(o& 64){if(node2->children[6].children){__ProcessMaxDepthNodeAdjacentNodes(dx1,dy2,dz2,node1,radius1,&node2->children[6],radius,cWidth,depth,F);}} - if(o&128){if(node2->children[7].children){__ProcessMaxDepthNodeAdjacentNodes(dx2,dy2,dz2,node1,radius1,&node2->children[7],radius,cWidth,depth,F);}} - } - } - } - template - inline int OctNode::ChildOverlap(int dx,int dy,int dz,int d,int cRadius2) - { - int w1=d-cRadius2; - int w2=d+cRadius2; - int overlap=0; - - int test=0,test1=0; - if(dx-w1){test =1;} - if(dx-w2){test|=2;} - - if(!test){return 0;} - if(dz-w1){test1 =test;} - if(dz-w2){test1|=test<<4;} - - if(!test1){return 0;} - if(dy-w1){overlap =test1;} - if(dy-w2){overlap|=test1<<2;} - return overlap; - } - - template - OctNode* OctNode::getNearestLeaf(const Point3D& p){ - Point3D center; - Real width; - OctNode* temp; - int cIndex; - if(!children){return this;} - centerAndWidth(center,width); - temp=this; - while(temp->children){ - cIndex=CornerIndex(center,p); - temp=&temp->children[cIndex]; - width/=2; - if(cIndex&1){center.coords[0]+=width/2;} - else {center.coords[0]-=width/2;} - if(cIndex&2){center.coords[1]+=width/2;} - else {center.coords[1]-=width/2;} - if(cIndex&4){center.coords[2]+=width/2;} - else {center.coords[2]-=width/2;} - } - return temp; - } - template - const OctNode* OctNode::getNearestLeaf(const Point3D& p) const{ - int nearest; - Real temp,dist2; - if(!children){return this;} - for(int i=0;i - int OctNode::CommonEdge(const OctNode* node1,int eIndex1,const OctNode* node2,int eIndex2){ - int o1,o2,i1,i2,j1,j2; - - Cube::FactorEdgeIndex(eIndex1,o1,i1,j1); - Cube::FactorEdgeIndex(eIndex2,o2,i2,j2); - if(o1!=o2){return 0;} - - int dir[2]; - int idx1[2]; - int idx2[2]; - switch(o1){ - case 0: dir[0]=1; dir[1]=2; break; - case 1: dir[0]=0; dir[1]=2; break; - case 1: dir[0]=0; dir[1]=2; break; - case 2: dir[0]=0; dir[1]=1; break; - }; - int d1,d2,off1[3],off2[3]; - node1->depthAndOffset(d1,off1); - node2->depthAndOffset(d2,off2); - idx1[0]=off1[dir[0]]+(1<d2){ - idx2[0]<<=(d1-d2); - idx2[1]<<=(d1-d2); - } - else{ - idx1[0]<<=(d2-d1); - idx1[1]<<=(d2-d1); - } - if(idx1[0]==idx2[0] && idx1[1]==idx2[1]){return 1;} - else {return 0;} - } - template - int OctNode::CornerIndex(const Point3D& center,const Point3D& p){ - int cIndex=0; - if(p.coords[0]>center.coords[0]){cIndex|=1;} - if(p.coords[1]>center.coords[1]){cIndex|=2;} - if(p.coords[2]>center.coords[2]){cIndex|=4;} - return cIndex; - } - template - template - OctNode& OctNode::operator = (const OctNode& node){ - int i; - if(children){delete[] children;} - children=NULL; - - d=node.depth (); - for(i=0;ioffset[i] = node.offset[i];} - if(node.children){ - initChildren(); - for(i=0;i - int OctNode::CompareForwardDepths(const void* v1,const void* v2){ - return ((const OctNode*)v1)->depth-((const OctNode*)v2)->depth; - } - template< class NodeData , class Real > - int OctNode< NodeData , Real >::CompareByDepthAndXYZ( const void* v1 , const void* v2 ) - { - const OctNode *n1 = (*(const OctNode< NodeData , Real >**)v1); - const OctNode *n2 = (*(const OctNode< NodeData , Real >**)v2); - if( n1->d!=n2->d ) return int(n1->d)-int(n2->d); - else if( n1->off[0]!=n2->off[0] ) return int(n1->off[0]) - int(n2->off[0]); - else if( n1->off[1]!=n2->off[1] ) return int(n1->off[1]) - int(n2->off[1]); - else if( n1->off[2]!=n2->off[2] ) return int(n1->off[2]) - int(n2->off[2]); - return 0; - } - - inline long long _InterleaveBits( int p[3] ) - { - long long key = 0; - for( int i=0 ; i<32 ; i++ ) key |= ( ( p[0] & (1< - int OctNode::CompareByDepthAndZIndex( const void* v1 , const void* v2 ) - { - const OctNode* n1 = (*(const OctNode**)v1); - const OctNode* n2 = (*(const OctNode**)v2); - int d1 , off1[3] , d2 , off2[3]; - n1->depthAndOffset( d1 , off1 ) , n2->depthAndOffset( d2 , off2 ); - if ( d1>d2 ) return 1; - else if( d1k2 ) return 1; - else if( k1 - int OctNode::CompareForwardPointerDepths( const void* v1 , const void* v2 ) - { - const OctNode* n1 = (*(const OctNode**)v1); - const OctNode* n2 = (*(const OctNode**)v2); - if(n1->d!=n2->d){return int(n1->d)-int(n2->d);} - while( n1->parent!=n2->parent ) - { - n1=n1->parent; - n2=n2->parent; - } - if(n1->off[0]!=n2->off[0]){return int(n1->off[0])-int(n2->off[0]);} - if(n1->off[1]!=n2->off[1]){return int(n1->off[1])-int(n2->off[1]);} - return int(n1->off[2])-int(n2->off[2]); - return 0; - } - template - int OctNode::CompareBackwardDepths(const void* v1,const void* v2){ - return ((const OctNode*)v2)->depth-((const OctNode*)v1)->depth; - } - template - int OctNode::CompareBackwardPointerDepths(const void* v1,const void* v2){ - return (*(const OctNode**)v2)->depth()-(*(const OctNode**)v1)->depth(); - } - template - inline int OctNode::Overlap2(const int &depth1,const int offSet1[DIMENSION],const Real& multiplier1,const int &depth2,const int offSet2[DIMENSION],const Real& multiplier2){ - int d=depth2-depth1; - Real w=multiplier2+multiplier1*(1<=w || - fabs(Real(offSet2[1]-(offSet1[1]<=w || - fabs(Real(offSet2[2]-(offSet1[2]<=w - ){return 0;} - return 1; - } - template - inline int OctNode::Overlap(int c1,int c2,int c3,int dWidth){ - if(c1>=dWidth || c1<=-dWidth || c2>=dWidth || c2<=-dWidth || c3>=dWidth || c3<=-dWidth){return 0;} - else{return 1;} - } - template - OctNode* OctNode::faceNeighbor(int faceIndex,int forceChildren){return __faceNeighbor(faceIndex>>1,faceIndex&1,forceChildren);} - template - const OctNode* OctNode::faceNeighbor(int faceIndex) const {return __faceNeighbor(faceIndex>>1,faceIndex&1);} - template - OctNode* OctNode::__faceNeighbor(int dir,int off,int forceChildren){ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - pIndex^=(1<children[pIndex];} - else{ - OctNode* temp=parent->__faceNeighbor(dir,off,forceChildren); - if(!temp){return NULL;} - if(!temp->children){ - if(forceChildren){temp->initChildren();} - else{return temp;} - } - return &temp->children[pIndex]; - } - } - template - const OctNode* OctNode::__faceNeighbor(int dir,int off) const { - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - pIndex^=(1<children[pIndex];} - else{ - const OctNode* temp=parent->__faceNeighbor(dir,off); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } - } - - template - OctNode* OctNode::edgeNeighbor(int edgeIndex,int forceChildren){ - int idx[2],o,i[2]; - Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); - switch(o){ - case 0: idx[0]=1; idx[1]=2; break; - case 1: idx[0]=0; idx[1]=2; break; - case 2: idx[0]=0; idx[1]=1; break; - }; - return __edgeNeighbor(o,i,idx,forceChildren); - } - template - const OctNode* OctNode::edgeNeighbor(int edgeIndex) const { - int idx[2],o,i[2]; - Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); - switch(o){ - case 0: idx[0]=1; idx[1]=2; break; - case 1: idx[0]=0; idx[1]=2; break; - case 2: idx[0]=0; idx[1]=1; break; - }; - return __edgeNeighbor(o,i,idx); - } - template - const OctNode* OctNode::__edgeNeighbor(int o,const int i[2],const int idx[2]) const{ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - int aIndex,x[DIMENSION]; - - Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); - aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; - pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0]); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor - const OctNode* temp=parent->__faceNeighbor(idx[1],i[1]); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==0) { // I can get the neighbor from the parent - return &parent->children[pIndex]; - } - else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor - const OctNode* temp=parent->__edgeNeighbor(o,i,idx); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } - else{return NULL;} - } - template - OctNode* OctNode::__edgeNeighbor(int o,const int i[2],const int idx[2],int forceChildren){ - if(!parent){return NULL;} - int pIndex=int(this-parent->children); - int aIndex,x[DIMENSION]; - - Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); - aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; - pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0],0); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor - OctNode* temp=parent->__faceNeighbor(idx[1],i[1],0); - if(!temp || !temp->children){return NULL;} - else{return &temp->children[pIndex];} - } - else if(aIndex==0) { // I can get the neighbor from the parent - return &parent->children[pIndex]; - } - else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor - OctNode* temp=parent->__edgeNeighbor(o,i,idx,forceChildren); - if(!temp){return NULL;} - if(!temp->children){ - if(forceChildren){temp->initChildren();} - else{return temp;} - } - return &temp->children[pIndex]; - } - else{return NULL;} - } - - template - const OctNode* OctNode::cornerNeighbor(int cornerIndex) const { - int pIndex,aIndex=0; - if(!parent){return NULL;} - - pIndex=int(this-parent->children); - aIndex=(cornerIndex ^ pIndex); // The disagreement bits - pIndex=(~pIndex)&7; // The antipodal point - if(aIndex==7){ // Agree on no bits - return &parent->children[pIndex]; - } - else if(aIndex==0){ // Agree on all bits - const OctNode* temp=((const OctNode*)parent)->cornerNeighbor(cornerIndex); - if(!temp || !temp->children){return temp;} - else{return &temp->children[pIndex];} - } - else if(aIndex==6){ // Agree on face 0 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==5){ // Agree on face 1 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==3){ // Agree on face 2 - const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==4){ // Agree on edge 2 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==2){ // Agree on edge 1 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==1){ // Agree on edge 0 - const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else{return NULL;} - } - template - OctNode* OctNode::cornerNeighbor(int cornerIndex,int forceChildren){ - int pIndex,aIndex=0; - if(!parent){return NULL;} - - pIndex=int(this-parent->children); - aIndex=(cornerIndex ^ pIndex); // The disagreement bits - pIndex=(~pIndex)&7; // The antipodal point - if(aIndex==7){ // Agree on no bits - return &parent->children[pIndex]; - } - else if(aIndex==0){ // Agree on all bits - OctNode* temp=((OctNode*)parent)->cornerNeighbor(cornerIndex,forceChildren); - if(!temp){return NULL;} - if(!temp->children){ - if(forceChildren){temp->initChildren();} - else{return temp;} - } - return &temp->children[pIndex]; - } - else if(aIndex==6){ // Agree on face 0 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==5){ // Agree on face 1 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==3){ // Agree on face 2 - OctNode* temp=((OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2,0); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==4){ // Agree on edge 2 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==2){ // Agree on edge 1 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else if(aIndex==1){ // Agree on edge 0 - OctNode* temp=((OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); - if(!temp || !temp->children){return NULL;} - else{return & temp->children[pIndex];} - } - else{return NULL;} - } - //////////////////////// - // OctNodeNeighborKey // - //////////////////////// - template - OctNode::Neighbors3::Neighbors3(void){clear();} - template - void OctNode::Neighbors3::clear(void){ - for(int i=0;i<3;i++){for(int j=0;j<3;j++){for(int k=0;k<3;k++){neighbors[i][j][k]=NULL;}}} - } - template - OctNode::NeighborKey3::NeighborKey3(void){ neighbors=NULL; } - template - OctNode::NeighborKey3::~NeighborKey3(void) - { - if( neighbors ) delete[] neighbors; - neighbors = NULL; - } - - template - void OctNode::NeighborKey3::set( int d ) - { - if( neighbors ) delete[] neighbors; - neighbors = NULL; - if( d<0 ) return; - neighbors = new Neighbors3[d+1]; - } - template< class NodeData , class Real > - typename OctNode::Neighbors3& OctNode::NeighborKey3::setNeighbors( OctNode* root , Point3D< Real > p , int d ) - { - if( !neighbors[d].neighbors[1][1][1] || !neighbors[d].neighbors[1][1][1]->isInside( p ) ) - { - neighbors[d].clear(); - - if( !d ) neighbors[d].neighbors[1][1][1] = root; - else - { - Neighbors3& temp = setNeighbors( root , p , d-1 ); - - int i , j , k , x1 , y1 , z1 , x2 , y2 , z2; - Point3D< Real > c; - Real w; - temp.neighbors[1][1][1]->centerAndWidth( c , w ); - int idx = CornerIndex( c , p ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - - if( !temp.neighbors[1][1][1]->children ) temp.neighbors[1][1][1]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = &temp.neighbors[1][1][1]->children[Cube::CornerIndex(i,j,k)]; - - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] ) - { - if( !temp.neighbors[i][1][1]->children ) temp.neighbors[i][1][1]->initChildren(); - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = &temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - } - j=y1<<1; - if( temp.neighbors[1][j][1] ) - { - if( !temp.neighbors[1][j][1]->children ) temp.neighbors[1][j][1]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = &temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - } - k=z1<<1; - if( temp.neighbors[1][1][k] ) - { - if( !temp.neighbors[1][1][k]->children ) temp.neighbors[1][1][k]->initChildren(); - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = &temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - } - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] ) - { - if( !temp.neighbors[i][j][1]->children ) temp.neighbors[i][j][1]->initChildren(); - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = &temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - } - i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] ) - { - if( !temp.neighbors[i][1][k]->children ) temp.neighbors[i][1][k]->initChildren(); - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = &temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - } - j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] ) - { - if( !temp.neighbors[1][j][k]->children ) temp.neighbors[1][j][k]->initChildren(); - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = &temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - } - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] ) - { - if( !temp.neighbors[i][j][k]->children ) temp.neighbors[i][j][k]->initChildren(); - neighbors[d].neighbors[i][j][k] = &temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - return neighbors[d]; - } - template< class NodeData , class Real > - typename OctNode::Neighbors3& OctNode::NeighborKey3::getNeighbors( OctNode* root , Point3D< Real > p , int d ) - { - if( !neighbors[d].neighbors[1][1][1] || !neighbors[d].neighbors[1][1][1]->isInside( p ) ) - { - neighbors[d].clear(); - - if( !d ) neighbors[d].neighbors[1][1][1] = root; - else - { - Neighbors3& temp = getNeighbors( root , p , d-1 ); - - int i , j , k , x1 , y1 , z1 , x2 , y2 , z2; - Point3D< Real > c; - Real w; - temp.neighbors[1][1][1]->centerAndWidth( c , w ); - int idx = CornerIndex( c , p ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - - if( !temp.neighbors[1][1][1] || !temp.neighbors[1][1][1]->children ) - { - POISSON_THROW_EXCEPTION (pcl::poisson::PoissonBadArgumentException, "Couldn't find node at appropriate depth"); - } - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = &temp.neighbors[1][1][1]->children[Cube::CornerIndex(i,j,k)]; - - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = &temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - j=y1<<1; - if( temp.neighbors[1][j][1] ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = &temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - k=z1<<1; - if( temp.neighbors[1][1][k] ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = &temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] ) - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = &temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] ) - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = &temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] ) - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = &temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] ) - neighbors[d].neighbors[i][j][k] = &temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - return neighbors[d]; - } - - template< class NodeData , class Real > - typename OctNode::Neighbors3& OctNode::NeighborKey3::setNeighbors( OctNode* node ) - { - int d = node->depth(); - if( node==neighbors[d].neighbors[1][1][1] ) - { - bool reset = false; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) if( !neighbors[d].neighbors[i][j][k] ) reset = true; - if( reset ) neighbors[d].neighbors[1][1][1] = NULL; - } - if( node!=neighbors[d].neighbors[1][1][1] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[1][1][1] = node; - else - { - int i,j,k,x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for(i=0;i<2;i++){ - for(j=0;j<2;j++){ - for(k=0;k<2;k++){ - neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; - } - } - } - Neighbors3& temp=setNeighbors(node->parent); - - // Set the neighbors from across the faces - i=x1<<1; - if(temp.neighbors[i][1][1]){ - if(!temp.neighbors[i][1][1]->children){temp.neighbors[i][1][1]->initChildren();} - for(j=0;j<2;j++){for(k=0;k<2;k++){neighbors[d].neighbors[i][y2+j][z2+k]=&temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)];}} - } - j=y1<<1; - if(temp.neighbors[1][j][1]){ - if(!temp.neighbors[1][j][1]->children){temp.neighbors[1][j][1]->initChildren();} - for(i=0;i<2;i++){for(k=0;k<2;k++){neighbors[d].neighbors[x2+i][j][z2+k]=&temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)];}} - } - k=z1<<1; - if(temp.neighbors[1][1][k]){ - if(!temp.neighbors[1][1][k]->children){temp.neighbors[1][1][k]->initChildren();} - for(i=0;i<2;i++){for(j=0;j<2;j++){neighbors[d].neighbors[x2+i][y2+j][k]=&temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)];}} - } - - // Set the neighbors from across the edges - i=x1<<1; j=y1<<1; - if(temp.neighbors[i][j][1]){ - if(!temp.neighbors[i][j][1]->children){temp.neighbors[i][j][1]->initChildren();} - for(k=0;k<2;k++){neighbors[d].neighbors[i][j][z2+k]=&temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)];} - } - i=x1<<1; k=z1<<1; - if(temp.neighbors[i][1][k]){ - if(!temp.neighbors[i][1][k]->children){temp.neighbors[i][1][k]->initChildren();} - for(j=0;j<2;j++){neighbors[d].neighbors[i][y2+j][k]=&temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)];} - } - j=y1<<1; k=z1<<1; - if(temp.neighbors[1][j][k]){ - if(!temp.neighbors[1][j][k]->children){temp.neighbors[1][j][k]->initChildren();} - for(i=0;i<2;i++){neighbors[d].neighbors[x2+i][j][k]=&temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)];} - } - - // Set the neighbor from across the corner - i=x1<<1; j=y1<<1; k=z1<<1; - if(temp.neighbors[i][j][k]){ - if(!temp.neighbors[i][j][k]->children){temp.neighbors[i][j][k]->initChildren();} - neighbors[d].neighbors[i][j][k]=&temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - return neighbors[d]; - } - // Note the assumption is that if you enable an edge, you also enable adjacent faces. - // And, if you enable a corner, you enable adjacent edges and faces. - template< class NodeData , class Real > - typename OctNode::Neighbors3& OctNode::NeighborKey3::setNeighbors( OctNode* node , bool flags[3][3][3] ) - { - int d = node->depth(); - if( node==neighbors[d].neighbors[1][1][1] ) - { - bool reset = false; - for( int i=0 ; i<3 ; i++ ) for( int j=0 ; j<3 ; j++ ) for( int k=0 ; k<3 ; k++ ) if( flags[i][j][k] && !neighbors[d].neighbors[i][j][k] ) reset = true; - if( reset ) neighbors[d].neighbors[1][1][1] = NULL; - } - if( node!=neighbors[d].neighbors[1][1][1] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[1][1][1] = node; - else - { - int x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for( int i=0 ; i<2 ; i++ ) - for( int j=0 ; j<2 ; j++ ) - for( int k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; - - Neighbors3& temp=setNeighbors( node->parent , flags ); - - // Set the neighbors from across the faces - { - int i=x1<<1; - if( temp.neighbors[i][1][1] ) - { - if( flags[i][1][1] && !temp.neighbors[i][1][1]->children ) temp.neighbors[i][1][1]->initChildren(); - if( temp.neighbors[i][1][1]->children ) for( int j=0 ; j<2 ; j++ ) for( int k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = &temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - } - } - { - int j = y1<<1; - if( temp.neighbors[1][j][1] ) - { - if( flags[1][j][1] && !temp.neighbors[1][j][1]->children ) temp.neighbors[1][j][1]->initChildren(); - if( temp.neighbors[1][j][1]->children ) for( int i=0 ; i<2 ; i++ ) for( int k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = &temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - } - } - { - int k = z1<<1; - if( temp.neighbors[1][1][k] ) - { - if( flags[1][1][k] && !temp.neighbors[1][1][k]->children ) temp.neighbors[1][1][k]->initChildren(); - if( temp.neighbors[1][1][k]->children ) for( int i=0 ; i<2 ; i++ ) for( int j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = &temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - } - } - - // Set the neighbors from across the edges - { - int i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] ) - { - if( flags[i][j][1] && !temp.neighbors[i][j][1]->children ) temp.neighbors[i][j][1]->initChildren(); - if( temp.neighbors[i][j][1]->children ) for( int k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = &temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - } - } - { - int i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] ) - { - if( flags[i][1][k] && !temp.neighbors[i][1][k]->children ) temp.neighbors[i][1][k]->initChildren(); - if( temp.neighbors[i][1][k]->children ) for( int j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = &temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - } - } - { - int j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] ) - { - if( flags[1][j][k] && !temp.neighbors[1][j][k]->children ) temp.neighbors[1][j][k]->initChildren(); - if( temp.neighbors[1][j][k]->children ) for( int i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = &temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - } - } - - // Set the neighbor from across the corner - { - int i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] ) - { - if( flags[i][j][k] && !temp.neighbors[i][j][k]->children ) temp.neighbors[i][j][k]->initChildren(); - if( temp.neighbors[i][j][k]->children ) neighbors[d].neighbors[i][j][k] = &temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - } - return neighbors[d]; - } - - template - typename OctNode::Neighbors3& OctNode::NeighborKey3::getNeighbors(OctNode* node){ - int d=node->depth(); - if(node!=neighbors[d].neighbors[1][1][1]){ - neighbors[d].clear(); - - if(!node->parent){neighbors[d].neighbors[1][1][1]=node;} - else{ - int i,j,k,x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for(i=0;i<2;i++){ - for(j=0;j<2;j++){ - for(k=0;k<2;k++){ - neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; - } - } - } - Neighbors3& temp=getNeighbors(node->parent); - - // Set the neighbors from across the faces - i=x1<<1; - if(temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children){ - for(j=0;j<2;j++){for(k=0;k<2;k++){neighbors[d].neighbors[i][y2+j][z2+k]=&temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)];}} - } - j=y1<<1; - if(temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children){ - for(i=0;i<2;i++){for(k=0;k<2;k++){neighbors[d].neighbors[x2+i][j][z2+k]=&temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)];}} - } - k=z1<<1; - if(temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children){ - for(i=0;i<2;i++){for(j=0;j<2;j++){neighbors[d].neighbors[x2+i][y2+j][k]=&temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)];}} - } - - // Set the neighbors from across the edges - i=x1<<1; j=y1<<1; - if(temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children){ - for(k=0;k<2;k++){neighbors[d].neighbors[i][j][z2+k]=&temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)];} - } - i=x1<<1; k=z1<<1; - if(temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children){ - for(j=0;j<2;j++){neighbors[d].neighbors[i][y2+j][k]=&temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)];} - } - j=y1<<1; k=z1<<1; - if(temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children){ - for(i=0;i<2;i++){neighbors[d].neighbors[x2+i][j][k]=&temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)];} - } - - // Set the neighbor from across the corner - i=x1<<1; j=y1<<1; k=z1<<1; - if(temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children){ - neighbors[d].neighbors[i][j][k]=&temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - return neighbors[node->depth()]; - } - - /////////////////////// - // ConstNeighborKey3 // - /////////////////////// - template - OctNode::ConstNeighbors3::ConstNeighbors3(void){clear();} - template - void OctNode::ConstNeighbors3::clear(void){ - for(int i=0;i<3;i++){for(int j=0;j<3;j++){for(int k=0;k<3;k++){neighbors[i][j][k]=NULL;}}} - } - template - OctNode::ConstNeighborKey3::ConstNeighborKey3(void){neighbors=NULL;} - template - OctNode::ConstNeighborKey3::~ConstNeighborKey3(void){ - if(neighbors){delete[] neighbors;} - neighbors=NULL; - } - - template - void OctNode::ConstNeighborKey3::set(int d){ - if(neighbors){delete[] neighbors;} - neighbors=NULL; - if(d<0){return;} - neighbors=new ConstNeighbors3[d+1]; - } - template - typename OctNode::ConstNeighbors3& OctNode::ConstNeighborKey3::getNeighbors(const OctNode* node){ - int d=node->depth(); - if(node!=neighbors[d].neighbors[1][1][1]){ - neighbors[d].clear(); - - if(!node->parent){neighbors[d].neighbors[1][1][1]=node;} - else{ - int i,j,k,x1,y1,z1,x2,y2,z2; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - for(i=0;i<2;i++){ - for(j=0;j<2;j++){ - for(k=0;k<2;k++){ - neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; - } - } - } - ConstNeighbors3& temp=getNeighbors(node->parent); - - // Set the neighbors from across the faces - i=x1<<1; - if(temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children){ - for(j=0;j<2;j++){for(k=0;k<2;k++){neighbors[d].neighbors[i][y2+j][z2+k]=&temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)];}} - } - j=y1<<1; - if(temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children){ - for(i=0;i<2;i++){for(k=0;k<2;k++){neighbors[d].neighbors[x2+i][j][z2+k]=&temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)];}} - } - k=z1<<1; - if(temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children){ - for(i=0;i<2;i++){for(j=0;j<2;j++){neighbors[d].neighbors[x2+i][y2+j][k]=&temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)];}} - } - - // Set the neighbors from across the edges - i=x1<<1; j=y1<<1; - if(temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children){ - for(k=0;k<2;k++){neighbors[d].neighbors[i][j][z2+k]=&temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)];} - } - i=x1<<1; k=z1<<1; - if(temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children){ - for(j=0;j<2;j++){neighbors[d].neighbors[i][y2+j][k]=&temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)];} - } - j=y1<<1; k=z1<<1; - if(temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children){ - for(i=0;i<2;i++){neighbors[d].neighbors[x2+i][j][k]=&temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)];} - } - - // Set the neighbor from across the corner - i=x1<<1; j=y1<<1; k=z1<<1; - if(temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children){ - neighbors[d].neighbors[i][j][k]=&temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - } - return neighbors[node->depth()]; - } - template - typename OctNode::ConstNeighbors3& OctNode::ConstNeighborKey3::getNeighbors( const OctNode* node , int minDepth ) - { - int d=node->depth(); - if (d < minDepth) - { - POISSON_THROW_EXCEPTION (pcl::poisson::PoissonBadArgumentException, "Node depth lower than min-depth: (actual)" << d << " < (minimum)" << minDepth); - } - if( node!=neighbors[d].neighbors[1][1][1] ) - { - neighbors[d].clear(); - - if( d==minDepth ) neighbors[d].neighbors[1][1][1]=node; - else - { - int i,j,k,x1,y1,z1,x2,y2,z2; - int idx = int(node-node->parent->children); - Cube::FactorCornerIndex( idx ,x1,y1,z1); - Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); - - ConstNeighbors3& temp=getNeighbors( node->parent , minDepth ); - - // Set the syblings - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - neighbors[d].neighbors[x2+i][y2+j][z2+k] = &node->parent->children[ Cube::CornerIndex(i,j,k) ]; - - // Set the neighbors from across the faces - i=x1<<1; - if( temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][y2+j][z2+k] = &temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)]; - - j=y1<<1; - if( temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[x2+i][j][z2+k] = &temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)]; - - k=z1<<1; - if( temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[x2+i][y2+j][k] = &temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)]; - - // Set the neighbors from across the edges - i=x1<<1 , j=y1<<1; - if( temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children ) - for( k=0 ; k<2 ; k++ ) neighbors[d].neighbors[i][j][z2+k] = &temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)]; - - i=x1<<1 , k=z1<<1; - if( temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children ) - for( j=0 ; j<2 ; j++ ) neighbors[d].neighbors[i][y2+j][k] = &temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)]; - - j=y1<<1 , k=z1<<1; - if( temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children ) - for( i=0 ; i<2 ; i++ ) neighbors[d].neighbors[x2+i][j][k] = &temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)]; - - // Set the neighbor from across the corner - i=x1<<1 , j=y1<<1 , k=z1<<1; - if( temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children ) - neighbors[d].neighbors[i][j][k] = &temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; - } - } - return neighbors[node->depth()]; - } - - template< class NodeData , class Real > OctNode< NodeData , Real >::Neighbors5::Neighbors5( void ){ clear(); } - template< class NodeData , class Real > OctNode< NodeData , Real >::ConstNeighbors5::ConstNeighbors5( void ){ clear(); } - template< class NodeData , class Real > - void OctNode< NodeData , Real >::Neighbors5::clear( void ) - { - for( int i=0 ; i<5 ; i++ ) for( int j=0 ; j<5 ; j++ ) for( int k=0 ; k<5 ; k++ ) neighbors[i][j][k] = NULL; - } - template< class NodeData , class Real > - void OctNode< NodeData , Real >::ConstNeighbors5::clear( void ) - { - for( int i=0 ; i<5 ; i++ ) for( int j=0 ; j<5 ; j++ ) for( int k=0 ; k<5 ; k++ ) neighbors[i][j][k] = NULL; - } - template< class NodeData , class Real > - OctNode< NodeData , Real >::NeighborKey5::NeighborKey5( void ) - { - _depth = -1; - neighbors = NULL; - } - template< class NodeData , class Real > - OctNode< NodeData , Real >::ConstNeighborKey5::ConstNeighborKey5( void ) - { - _depth = -1; - neighbors = NULL; - } - template< class NodeData , class Real > - OctNode< NodeData , Real >::NeighborKey5::~NeighborKey5( void ) - { - if( neighbors ) delete[] neighbors; - neighbors = NULL; - } - template< class NodeData , class Real > - OctNode< NodeData , Real >::ConstNeighborKey5::~ConstNeighborKey5( void ) - { - if( neighbors ) delete[] neighbors; - neighbors = NULL; - } - template< class NodeData , class Real > - void OctNode< NodeData , Real >::NeighborKey5::set( int d ) - { - if( neighbors ) delete[] neighbors; - neighbors = NULL; - if(d<0) return; - _depth = d; - neighbors=new Neighbors5[d+1]; - } - template< class NodeData , class Real > - void OctNode< NodeData , Real >::ConstNeighborKey5::set( int d ) - { - if( neighbors ) delete[] neighbors; - neighbors = NULL; - if(d<0) return; - _depth = d; - neighbors=new ConstNeighbors5[d+1]; - } - template< class NodeData , class Real > - typename OctNode< NodeData , Real >::Neighbors5& OctNode< NodeData , Real >::NeighborKey5::getNeighbors( OctNode* node ) - { - int d=node->depth(); - if( node!=neighbors[d].neighbors[2][2][2] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[2][2][2]=node; - else - { - getNeighbors( node->parent ); - Neighbors5& temp = neighbors[d-1]; - int x1 , y1 , z1 , x2 , y2 , z2; - int idx = int( node - node->parent->children ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - - Neighbors5& n = neighbors[d]; - Cube::FactorCornerIndex( (~idx)&7 , x2 , y2 , z2 ); - int i , j , k; - int fx0 = x2+1 , fy0 = y2+1 , fz0 = z2+1; // Indices of the bottom left corner of the parent within the 5x5x5 - int cx1 = x1*2+1 , cy1 = y1*2+1 , cz1 = z1*2+1; - int cx2 = x2*2+1 , cy2 = y2*2+1 , cz2 = z2*2+1; - int fx1 = x1*3 , fy1 = y1*3 , fz1 = z1*3; - int fx2 = x2*4 , fy2 = y2*4 , fz2 = z2*4; - - // Set the syblings - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy0+j][fz0+k] = node->parent->children + Cube::CornerIndex( i , j , k ); - - // Set the neighbors from across the faces - if( temp.neighbors[cx1][2][2] && temp.neighbors[cx1][2][2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy0+j][fz0+k] = temp.neighbors[cx1][2][2]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[2][cy1][2] && temp.neighbors[2][cy1][2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy1+j][fz0+k] = temp.neighbors[2][cy1][2]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[2][2][cz1] && temp.neighbors[2][2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy0+j][fz1+k] = temp.neighbors[2][2][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx2][2][2] && temp.neighbors[cx2][2][2]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy0+j][fz0+k] = temp.neighbors[cx2][2][2]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[2][cy2][2] && temp.neighbors[2][cy2][2]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy2 ][fz0+k] = temp.neighbors[2][cy2][2]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[2][2][cz2] && temp.neighbors[2][2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx0+i][fy0+j][fz2 ] = temp.neighbors[2][2][cz2]->children + Cube::CornerIndex( i , j , z1 ); - - // Set the neighbors from across the edges - if( temp.neighbors[cx1][cy1][2] && temp.neighbors[cx1][cy1][2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy1+j][fz0+k] = temp.neighbors[cx1][cy1][2]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx1][2][cz1] && temp.neighbors[cx1][2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy0+j][fz1+k] = temp.neighbors[cx1][2][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[2][cy1][cz1] && temp.neighbors[2][cy1][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy1+j][fz1+k] = temp.neighbors[2][cy1][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx1][cy2][2] && temp.neighbors[cx1][cy2][2]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy2 ][fz0+k] = temp.neighbors[cx1][cy2][2]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[cx1][2][cz2] && temp.neighbors[cx1][2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx1+i][fy0+j][fz2 ] = temp.neighbors[cx1][2][cz2]->children + Cube::CornerIndex( i , j , z1 ); - if( temp.neighbors[cx2][cy1][2] && temp.neighbors[cx2][cy1][2]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy1+j][fz0+k] = temp.neighbors[cx2][cy1][2]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[2][cy1][cz2] && temp.neighbors[2][cy1][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx0+i][fy1+j][fz2 ] = temp.neighbors[2][cy1][cz2]->children + Cube::CornerIndex( i , j , z1 ); - if( temp.neighbors[cx2][2][cz1] && temp.neighbors[cx2][2][cz1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy0+j][fz1+k] = temp.neighbors[cx2][2][cz1]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[2][cy2][cz1] && temp.neighbors[2][cy2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx0+i][fy2 ][fz1+k] = temp.neighbors[2][cy2][cz1]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[cx2][cy2][2] && temp.neighbors[cx2][cy2][2]->children ) - for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy2 ][fz0+k] = temp.neighbors[cx2][cy2][2]->children + Cube::CornerIndex( x1 , y1 , k ); - if( temp.neighbors[cx2][2][cz2] && temp.neighbors[cx2][2][cz2]->children ) - for( j=0 ; j<2 ; j++ ) - n.neighbors[fx2 ][fy0+j][fz2 ] = temp.neighbors[cx2][2][cz2]->children + Cube::CornerIndex( x1 , j , z1 ); - if( temp.neighbors[2][cy2][cz2] && temp.neighbors[2][cy2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) - n.neighbors[fx0+i][fy2 ][fz2 ] = temp.neighbors[2][cy2][cz2]->children + Cube::CornerIndex( i , y1 , z1 ); - - // Set the neighbor from across the corners - if( temp.neighbors[cx1][cy1][cz1] && temp.neighbors[cx1][cy1][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy1+j][fz1+k] = temp.neighbors[cx1][cy1][cz1]->children + Cube::CornerIndex( i , j , k ); - if( temp.neighbors[cx1][cy1][cz2] && temp.neighbors[cx1][cy1][cz2]->children ) - for( i=0 ; i<2 ; i++ ) for( j=0 ; j<2 ; j++ ) - n.neighbors[fx1+i][fy1+j][fz2 ] = temp.neighbors[cx1][cy1][cz2]->children + Cube::CornerIndex( i , j , z1 ); - if( temp.neighbors[cx1][cy2][cz1] && temp.neighbors[cx1][cy2][cz1]->children ) - for( i=0 ; i<2 ; i++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx1+i][fy2 ][fz1+k] = temp.neighbors[cx1][cy2][cz1]->children + Cube::CornerIndex( i , y1 , k ); - if( temp.neighbors[cx2][cy1][cz1] && temp.neighbors[cx2][cy1][cz1]->children ) - for( j=0 ; j<2 ; j++ ) for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy1+j][fz1+k] = temp.neighbors[cx2][cy1][cz1]->children + Cube::CornerIndex( x1 , j , k ); - if( temp.neighbors[cx1][cy2][cz2] && temp.neighbors[cx1][cy2][cz2]->children ) - for( i=0 ; i<2 ; i++ ) - n.neighbors[fx1+i][fy2 ][fz2 ] = temp.neighbors[cx1][cy2][cz2]->children + Cube::CornerIndex( i , y1 , z1 ); - if( temp.neighbors[cx2][cy1][cz2] && temp.neighbors[cx2][cy1][cz2]->children ) - for( j=0 ; j<2 ; j++ ) - n.neighbors[fx2 ][fy1+j][fz2 ] = temp.neighbors[cx2][cy1][cz2]->children + Cube::CornerIndex( x1 , j , z1 ); - if( temp.neighbors[cx2][cy2][cz1] && temp.neighbors[cx2][cy2][cz1]->children ) - for( k=0 ; k<2 ; k++ ) - n.neighbors[fx2 ][fy2 ][fz1+k] = temp.neighbors[cx2][cy2][cz1]->children + Cube::CornerIndex( x1 , y1 , k ); - if( temp.neighbors[cx2][cy2][cz2] && temp.neighbors[cx2][cy2][cz2]->children ) - n.neighbors[fx2 ][fy2 ][fz2 ] = temp.neighbors[cx2][cy2][cz2]->children + Cube::CornerIndex( x1 , y1 , z1 ); - } - } - return neighbors[d]; - } - template< class NodeData , class Real > - typename OctNode< NodeData , Real >::Neighbors5& OctNode< NodeData , Real >::NeighborKey5::setNeighbors( OctNode* node , int xStart , int xEnd , int yStart , int yEnd , int zStart , int zEnd ) - { - int d=node->depth(); - if( node!=neighbors[d].neighbors[2][2][2] ) - { - neighbors[d].clear(); - - if( !node->parent ) neighbors[d].neighbors[2][2][2]=node; - else - { - setNeighbors( node->parent , xStart , xEnd , yStart , yEnd , zStart , zEnd ); - Neighbors5& temp = neighbors[d-1]; - int x1 , y1 , z1 , x2 , y2 , z2 , ii , jj , kk; - int idx = int( node-node->parent->children ); - Cube::FactorCornerIndex( idx , x1 , y1 , z1 ); - - for( int i=xStart ; i>1); - for( int j=yStart ; j>1); - for( int k=zStart ; k>1); - if(temp.neighbors[x2][y2][z2] ) - { - if( !temp.neighbors[x2][y2][z2]->children ) temp.neighbors[x2][y2][z2]->initChildren(); - neighbors[d].neighbors[i][j][k] = temp.neighbors[x2][y2][z2]->children + Cube::CornerIndex(ii,jj,kk); - } - } - } - } - } - } - return neighbors[d]; - } - template< class NodeData , class Real > - typename OctNode< NodeData , Real >::ConstNeighbors5& OctNode< NodeData , Real >::ConstNeighborKey5::getNeighbors( const OctNode* node ) - { - int d=node->depth(); - if( node!=neighbors[d].neighbors[2][2][2] ) - { - neighbors[d].clear(); - - if(!node->parent) neighbors[d].neighbors[2][2][2]=node; - else - { - getNeighbors( node->parent ); - ConstNeighbors5& temp = neighbors[d-1]; - int x1,y1,z1,x2,y2,z2,ii,jj,kk; - int idx=int(node-node->parent->children); - Cube::FactorCornerIndex(idx,x1,y1,z1); - - for(int i=0;i<5;i++) - { - x2=i+x1; - ii=x2&1; - x2=1+(x2>>1); - for(int j=0;j<5;j++) - { - y2=j+y1; - jj=y2&1; - y2=1+(y2>>1); - for(int k=0;k<5;k++) - { - z2=k+z1; - kk=z2&1; - z2=1+(z2>>1); - if(temp.neighbors[x2][y2][z2] && temp.neighbors[x2][y2][z2]->children) - neighbors[d].neighbors[i][j][k] = temp.neighbors[x2][y2][z2]->children + Cube::CornerIndex(ii,jj,kk); - } - } - } - } - } - return neighbors[d]; - } - - - template - int OctNode::write(const char* fileName) const{ - FILE* fp=fopen(fileName,"wb"); - if(!fp){return 0;} - int ret=write(fp); - fclose(fp); - return ret; - } - template - int OctNode::write(FILE* fp) const{ - fwrite(this,sizeof(OctNode),1,fp); - if(children){for(int i=0;i - int OctNode::read(const char* fileName){ - FILE* fp=fopen(fileName,"rb"); - if(!fp){return 0;} - int ret=read(fp); - fclose(fp); - return ret; - } - template - int OctNode::read(FILE* fp){ - fread(this,sizeof(OctNode),1,fp); - parent=NULL; - if(children){ - children=NULL; - initChildren(); - for(int i=0;i - int OctNode::width(int maxDepth) const { - int d=depth(); - return 1<<(maxDepth-d); - } - template - void OctNode::centerIndex(int maxDepth,int index[DIMENSION]) const { - int d,o[3]; - depthAndOffset(d,o); - for(int i=0;i::CornerIndex(maxDepth,d+1,o[i]<<1,1);} - } - - } -} diff --git a/plugins/probe/3rd/poisson4/poisson_exceptions.h b/plugins/probe/3rd/poisson4/poisson_exceptions.h deleted file mode 100644 index 0bfa19b4ae..0000000000 --- a/plugins/probe/3rd/poisson4/poisson_exceptions.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2019-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#pragma once - -#include -#include - -/** POISSON_THROW_EXCEPTION is a helper macro to be used for throwing exceptions. e.g. - * POISSON_THROW_EXCEPTION (PoissonBadArgumentException, "[ERROR] B-spline up-sampling not supported for degree " << Degree); - * - * \note - * Adapted from PCL_THROW_EXCEPTION. We intentionally do not reuse PCL_THROW_EXCEPTION here - * to avoid introducing any dependencies on PCL in this 3rd party module. - */ -#define POISSON_THROW_EXCEPTION(ExceptionName, message) \ -{ \ - std::ostringstream s; \ - s << message; \ - throw ExceptionName(s.str(), __FILE__, __LINE__); \ -} - -namespace pcl -{ - namespace poisson - { - /** \class PoissonException - * \brief A base class for all poisson exceptions which inherits from std::runtime_error - * - * \note - * Adapted from PCLException. We intentionally do not reuse PCLException here - * to avoid introducing any dependencies on PCL in this 3rd party module. - */ - class PoissonException : public std::runtime_error - { - public: - PoissonException (const std::string& error_description, - const char* file_name = nullptr, - unsigned line_number = 0) - : std::runtime_error (createDetailedMessage (error_description, - file_name, - line_number)) - , file_name_ (file_name) - , line_number_ (line_number) - {} - - protected: - static std::string - createDetailedMessage (const std::string& error_description, - const char* file_name, - unsigned line_number) - { - std::ostringstream sstream; - - if (file_name) - { - sstream << "in " << file_name << ' '; - if (line_number) - sstream << "@ " << line_number << ' '; - } - sstream << ": " << error_description; - - return (sstream.str ()); - } - - const char* file_name_; - const char* function_name_; - unsigned line_number_; - }; - - /** \class PoissonBadArgumentException - * \brief An exception that is thrown when the arguments number or type is wrong/unhandled. - */ - class PoissonBadArgumentException : public PoissonException - { - public: - PoissonBadArgumentException (const std::string& error_description, - const char* file_name = nullptr, - unsigned line_number = 0) - : pcl::poisson::PoissonException (error_description, file_name, line_number) {} - }; - - /** \class PoissonOpenMPException - * \brief An exception that is thrown when something goes wrong inside an openMP for loop. - */ - class PoissonOpenMPException : public PoissonException - { - public: - PoissonOpenMPException (const std::string& error_description, - const char* file_name = nullptr, - unsigned line_number = 0) - : pcl::poisson::PoissonException (error_description, file_name, line_number) {} - }; - - /** \class PoissonBadInitException - * \brief An exception that is thrown when initialization fails. - */ - class PoissonBadInitException : public PoissonException - { - public: - PoissonBadInitException (const std::string& error_description, - const char* file_name = nullptr, - unsigned line_number = 0) - : pcl::poisson::PoissonException (error_description, file_name, line_number) {} - }; - } -} diff --git a/plugins/probe/3rd/poisson4/polynomial.h b/plugins/probe/3rd/poisson4/polynomial.h deleted file mode 100644 index f43f5dbe8e..0000000000 --- a/plugins/probe/3rd/poisson4/polynomial.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef POLYNOMIAL_INCLUDED -#define POLYNOMIAL_INCLUDED - -#include - -namespace pcl -{ - namespace poisson - { - - template< int Degree > - class Polynomial{ - public: - double coefficients[Degree+1]; - - Polynomial(void); - template - Polynomial(const Polynomial& P); - double operator()( double t ) const; - double integral( double tMin , double tMax ) const; - - int operator == (const Polynomial& p) const; - int operator != (const Polynomial& p) const; - int isZero(void) const; - void setZero(void); - - template - Polynomial& operator = (const Polynomial &p); - Polynomial& operator += (const Polynomial& p); - Polynomial& operator -= (const Polynomial& p); - Polynomial operator - (void) const; - Polynomial operator + (const Polynomial& p) const; - Polynomial operator - (const Polynomial& p) const; - template - Polynomial operator * (const Polynomial& p) const; - - Polynomial& operator += ( double s ); - Polynomial& operator -= ( double s ); - Polynomial& operator *= ( double s ); - Polynomial& operator /= ( double s ); - Polynomial operator + ( double s ) const; - Polynomial operator - ( double s ) const; - Polynomial operator * ( double s ) const; - Polynomial operator / ( double s ) const; - - Polynomial scale( double s ) const; - Polynomial shift( double t ) const; - - Polynomial derivative(void) const; - Polynomial integral(void) const; - - void printnl(void) const; - - Polynomial& addScaled(const Polynomial& p,double scale); - - static void Negate(const Polynomial& in,Polynomial& out); - static void Subtract(const Polynomial& p1,const Polynomial& p2,Polynomial& q); - static void Scale(const Polynomial& p,double w,Polynomial& q); - static void AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,double w2,Polynomial& q); - static void AddScaled(const Polynomial& p1,const Polynomial& p2,double w2,Polynomial& q); - static void AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,Polynomial& q); - - void getSolutions(double c,std::vector& roots,double EPS) const; - - static Polynomial BSplineComponent( int i ); - }; - - - } -} - - -#include "polynomial.hpp" -#endif // POLYNOMIAL_INCLUDED diff --git a/plugins/probe/3rd/poisson4/polynomial.hpp b/plugins/probe/3rd/poisson4/polynomial.hpp deleted file mode 100644 index a3f4223994..0000000000 --- a/plugins/probe/3rd/poisson4/polynomial.hpp +++ /dev/null @@ -1,324 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#include -#include -#include "factor.h" - -//////////////// -// Polynomial // -//////////////// - -namespace pcl -{ - namespace poisson - { - - - template - Polynomial::Polynomial(void){memset(coefficients,0,sizeof(double)*(Degree+1));} - template - template - Polynomial::Polynomial(const Polynomial& P){ - memset(coefficients,0,sizeof(double)*(Degree+1)); - for(int i=0;i<=Degree && i<=Degree2;i++){coefficients[i]=P.coefficients[i];} - } - - - template - template - Polynomial& Polynomial::operator = (const Polynomial &p){ - int d=Degree - Polynomial Polynomial::derivative(void) const{ - Polynomial p; - for(int i=0;i - Polynomial Polynomial::integral(void) const{ - Polynomial p; - p.coefficients[0]=0; - for(int i=0;i<=Degree;i++){p.coefficients[i+1]=coefficients[i]/(i+1);} - return p; - } - template<> inline double Polynomial< 0 >::operator() ( double t ) const { return coefficients[0]; } - template<> inline double Polynomial< 1 >::operator() ( double t ) const { return coefficients[0]+coefficients[1]*t; } - template<> inline double Polynomial< 2 >::operator() ( double t ) const { return coefficients[0]+(coefficients[1]+coefficients[2]*t)*t; } - template - inline double Polynomial::operator() ( double t ) const{ - double v=coefficients[Degree]; - for( int d=Degree-1 ; d>=0 ; d-- ) v = v*t + coefficients[d]; - return v; - } - template - double Polynomial::integral( double tMin , double tMax ) const - { - double v=0; - double t1,t2; - t1=tMin; - t2=tMax; - for(int i=0;i<=Degree;i++){ - v+=coefficients[i]*(t2-t1)/(i+1); - if(t1!=-DBL_MAX && t1!=DBL_MAX){t1*=tMin;} - if(t2!=-DBL_MAX && t2!=DBL_MAX){t2*=tMax;} - } - return v; - } - template - int Polynomial::operator == (const Polynomial& p) const{ - for(int i=0;i<=Degree;i++){if(coefficients[i]!=p.coefficients[i]){return 0;}} - return 1; - } - template - int Polynomial::operator != (const Polynomial& p) const{ - for(int i=0;i<=Degree;i++){if(coefficients[i]==p.coefficients[i]){return 0;}} - return 1; - } - template - int Polynomial::isZero(void) const{ - for(int i=0;i<=Degree;i++){if(coefficients[i]!=0){return 0;}} - return 1; - } - template - void Polynomial::setZero(void){memset(coefficients,0,sizeof(double)*(Degree+1));} - - template - Polynomial& Polynomial::addScaled(const Polynomial& p,double s){ - for(int i=0;i<=Degree;i++){coefficients[i]+=p.coefficients[i]*s;} - return *this; - } - template - Polynomial& Polynomial::operator += (const Polynomial& p){ - for(int i=0;i<=Degree;i++){coefficients[i]+=p.coefficients[i];} - return *this; - } - template - Polynomial& Polynomial::operator -= (const Polynomial& p){ - for(int i=0;i<=Degree;i++){coefficients[i]-=p.coefficients[i];} - return *this; - } - template - Polynomial Polynomial::operator + (const Polynomial& p) const{ - Polynomial q; - for(int i=0;i<=Degree;i++){q.coefficients[i]=(coefficients[i]+p.coefficients[i]);} - return q; - } - template - Polynomial Polynomial::operator - (const Polynomial& p) const{ - Polynomial q; - for(int i=0;i<=Degree;i++) {q.coefficients[i]=coefficients[i]-p.coefficients[i];} - return q; - } - template - void Polynomial::Scale(const Polynomial& p,double w,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p.coefficients[i]*w;} - } - template - void Polynomial::AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,double w2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]*w1+p2.coefficients[i]*w2;} - } - template - void Polynomial::AddScaled(const Polynomial& p1,double w1,const Polynomial& p2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]*w1+p2.coefficients[i];} - } - template - void Polynomial::AddScaled(const Polynomial& p1,const Polynomial& p2,double w2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]+p2.coefficients[i]*w2;} - } - - template - void Polynomial::Subtract(const Polynomial &p1,const Polynomial& p2,Polynomial& q){ - for(int i=0;i<=Degree;i++){q.coefficients[i]=p1.coefficients[i]-p2.coefficients[i];} - } - template - void Polynomial::Negate(const Polynomial& in,Polynomial& out){ - out=in; - for(int i=0;i<=Degree;i++){out.coefficients[i]=-out.coefficients[i];} - } - - template - Polynomial Polynomial::operator - (void) const{ - Polynomial q=*this; - for(int i=0;i<=Degree;i++){q.coefficients[i]=-q.coefficients[i];} - return q; - } - template - template - Polynomial Polynomial::operator * (const Polynomial& p) const{ - Polynomial q; - for(int i=0;i<=Degree;i++){for(int j=0;j<=Degree2;j++){q.coefficients[i+j]+=coefficients[i]*p.coefficients[j];}} - return q; - } - - template - Polynomial& Polynomial::operator += ( double s ) - { - coefficients[0]+=s; - return *this; - } - template - Polynomial& Polynomial::operator -= ( double s ) - { - coefficients[0]-=s; - return *this; - } - template - Polynomial& Polynomial::operator *= ( double s ) - { - for(int i=0;i<=Degree;i++){coefficients[i]*=s;} - return *this; - } - template - Polynomial& Polynomial::operator /= ( double s ) - { - for(int i=0;i<=Degree;i++){coefficients[i]/=s;} - return *this; - } - template - Polynomial Polynomial::operator + ( double s ) const - { - Polynomial q=*this; - q.coefficients[0]+=s; - return q; - } - template - Polynomial Polynomial::operator - ( double s ) const - { - Polynomial q=*this; - q.coefficients[0]-=s; - return q; - } - template - Polynomial Polynomial::operator * ( double s ) const - { - Polynomial q; - for(int i=0;i<=Degree;i++){q.coefficients[i]=coefficients[i]*s;} - return q; - } - template - Polynomial Polynomial::operator / ( double s ) const - { - Polynomial q; - for( int i=0 ; i<=Degree ; i++ ) q.coefficients[i] = coefficients[i]/s; - return q; - } - template - Polynomial Polynomial::scale( double s ) const - { - Polynomial q=*this; - double s2=1.0; - for(int i=0;i<=Degree;i++){ - q.coefficients[i]*=s2; - s2/=s; - } - return q; - } - template - Polynomial Polynomial::shift( double t ) const - { - Polynomial q; - for(int i=0;i<=Degree;i++){ - double temp=1; - for(int j=i;j>=0;j--){ - q.coefficients[j]+=coefficients[i]*temp; - temp*=-t*j; - temp/=(i-j+1); - } - } - return q; - } - template - void Polynomial::printnl(void) const{ - for(int j=0;j<=Degree;j++){ - printf("%6.4f x^%d ",coefficients[j],j); - if(j=0){printf("+");} - } - printf("\n"); - } - template - void Polynomial::getSolutions(double c,std::vector& roots,double EPS) const - { - double r[4][2]; - int rCount=0; - roots.clear(); - switch(Degree){ - case 1: - rCount=Factor(coefficients[1],coefficients[0]-c,r,EPS); - break; - case 2: - rCount=Factor(coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); - break; - case 3: - rCount=Factor(coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); - break; - // case 4: - // rCount=Factor(coefficients[4],coefficients[3],coefficients[2],coefficients[1],coefficients[0]-c,r,EPS); - // break; - default: - printf("Can't solve polynomial of degree: %d\n",Degree); - } - for(int i=0;i inline Polynomial< 0 > Polynomial< 0 >::BSplineComponent( int i ) - { - Polynomial p; - p.coefficients[0] = 1.; - return p; - } - template< int Degree > - Polynomial< Degree > Polynomial< Degree >::BSplineComponent( int i ) - { - Polynomial p; - if( i>0 ) - { - Polynomial< Degree > _p = Polynomial< Degree-1 >::BSplineComponent( i-1 ).integral(); - p -= _p; - p.coefficients[0] += _p(1); - } - if( i _p = Polynomial< Degree-1 >::BSplineComponent( i ).integral(); - p += _p; - } - return p; - } - - } -} diff --git a/plugins/probe/3rd/poisson4/ppolynomial.h b/plugins/probe/3rd/poisson4/ppolynomial.h deleted file mode 100644 index 0f7a4436ae..0000000000 --- a/plugins/probe/3rd/poisson4/ppolynomial.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef P_POLYNOMIAL_INCLUDED -#define P_POLYNOMIAL_INCLUDED - -#if defined __GNUC__ -# pragma GCC system_header -#endif - -#include -#include "polynomial.h" - -namespace pcl -{ - namespace poisson - { - template - class StartingPolynomial{ - public: - Polynomial p; - double start; - - template - StartingPolynomial operator * (const StartingPolynomial& p) const; - StartingPolynomial scale(double s) const; - StartingPolynomial shift(double t) const; - int operator < (const StartingPolynomial& sp) const; - static int Compare(const void* v1,const void* v2); - }; - - template - class PPolynomial - { - public: - size_t polyCount; - StartingPolynomial* polys; - - PPolynomial(void); - PPolynomial(const PPolynomial& p); - ~PPolynomial(void); - - PPolynomial& operator = (const PPolynomial& p); - - int size(void) const; - - void set( size_t size ); - // Note: this method will sort the elements in sps - void set( StartingPolynomial* sps , int count ); - void reset( size_t newSize ); - - - double operator()( double t ) const; - double integral( double tMin , double tMax ) const; - double Integral( void ) const; - - template - PPolynomial& operator = (const PPolynomial& p); - - PPolynomial operator + (const PPolynomial& p) const; - PPolynomial operator - (const PPolynomial& p) const; - - template - PPolynomial operator * (const Polynomial& p) const; - - template - PPolynomial operator * (const PPolynomial& p) const; - - - PPolynomial& operator += ( double s ); - PPolynomial& operator -= ( double s ); - PPolynomial& operator *= ( double s ); - PPolynomial& operator /= ( double s ); - PPolynomial operator + ( double s ) const; - PPolynomial operator - ( double s ) const; - PPolynomial operator * ( double s ) const; - PPolynomial operator / ( double s ) const; - - PPolynomial& addScaled(const PPolynomial& poly,double scale); - - PPolynomial scale( double s ) const; - PPolynomial shift( double t ) const; - - PPolynomial< Degree-1 > derivative(void) const; - PPolynomial< Degree+1 > integral(void) const; - - void getSolutions(double c,std::vector& roots,double EPS,double min=-DBL_MAX,double max=DBL_MAX) const; - - void printnl( void ) const; - - PPolynomial< Degree+1 > MovingAverage( double radius ); - static PPolynomial BSpline( double radius=0.5 ); - - void write( FILE* fp , int samples , double min , double max ) const; - }; - - - } -} - - -#include "ppolynomial.hpp" -#endif // P_POLYNOMIAL_INCLUDED diff --git a/plugins/probe/3rd/poisson4/ppolynomial.hpp b/plugins/probe/3rd/poisson4/ppolynomial.hpp deleted file mode 100644 index 3923ce53bf..0000000000 --- a/plugins/probe/3rd/poisson4/ppolynomial.hpp +++ /dev/null @@ -1,440 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include "factor.h" - -//////////////////////// -// StartingPolynomial // -//////////////////////// - -namespace pcl -{ - namespace poisson - { - - - template - template - StartingPolynomial StartingPolynomial::operator * (const StartingPolynomial& p) const{ - StartingPolynomial sp; - if(start>p.start){sp.start=start;} - else{sp.start=p.start;} - sp.p=this->p*p.p; - return sp; - } - template - StartingPolynomial StartingPolynomial::scale(double s) const{ - StartingPolynomial q; - q.start=start*s; - q.p=p.scale(s); - return q; - } - template - StartingPolynomial StartingPolynomial::shift(double s) const{ - StartingPolynomial q; - q.start=start+s; - q.p=p.shift(s); - return q; - } - - - template - int StartingPolynomial::operator < (const StartingPolynomial& sp) const{ - if(start - int StartingPolynomial::Compare(const void* v1,const void* v2){ - double d=((StartingPolynomial*)(v1))->start-((StartingPolynomial*)(v2))->start; - if (d<0) {return -1;} - else if (d>0) {return 1;} - else {return 0;} - } - - ///////////////// - // PPolynomial // - ///////////////// - template - PPolynomial::PPolynomial(void){ - polyCount=0; - polys=NULL; - } - template - PPolynomial::PPolynomial(const PPolynomial& p){ - polyCount=0; - polys=NULL; - set(p.polyCount); - memcpy(polys,p.polys,sizeof(StartingPolynomial)*p.polyCount); - } - - template - PPolynomial::~PPolynomial(void){ - if(polyCount){free(polys);} - polyCount=0; - polys=NULL; - } - template - void PPolynomial::set(StartingPolynomial* sps,int count){ - int i,c=0; - set(count); - qsort(sps,count,sizeof(StartingPolynomial),StartingPolynomial::Compare); - for( i=0 ; i - int PPolynomial::size(void) const{return int(sizeof(StartingPolynomial)*polyCount);} - - template - void PPolynomial::set( size_t size ) - { - if(polyCount){free(polys);} - polyCount=0; - polys=NULL; - polyCount=size; - if(size){ - polys=(StartingPolynomial*)malloc(sizeof(StartingPolynomial)*size); - memset(polys,0,sizeof(StartingPolynomial)*size); - } - } - template - void PPolynomial::reset( size_t newSize ) - { - polyCount=newSize; - polys=(StartingPolynomial*)realloc(polys,sizeof(StartingPolynomial)*newSize); - } - - template - PPolynomial& PPolynomial::operator = (const PPolynomial& p){ - set(p.polyCount); - memcpy(polys,p.polys,sizeof(StartingPolynomial)*p.polyCount); - return *this; - } - - template - template - PPolynomial& PPolynomial::operator = (const PPolynomial& p){ - set(p.polyCount); - for(int i=0;i - double PPolynomial::operator ()( double t ) const - { - double v=0; - for( int i=0 ; ipolys[i].start ; i++ ) v+=polys[i].p(t); - return v; - } - - template - double PPolynomial::integral( double tMin , double tMax ) const - { - int m=1; - double start,end,s,v=0; - start=tMin; - end=tMax; - if(tMin>tMax){ - m=-1; - start=tMax; - end=tMin; - } - for(int i=0;i - double PPolynomial::Integral(void) const{return integral(polys[0].start,polys[polyCount-1].start);} - template - PPolynomial PPolynomial::operator + (const PPolynomial& p) const{ - PPolynomial q; - int i,j; - size_t idx=0; - q.set(polyCount+p.polyCount); - i=j=-1; - - while(idx=int(p.polyCount)-1) {q.polys[idx]= polys[++i];} - else if (i>=int( polyCount)-1) {q.polys[idx]=p.polys[++j];} - else if(polys[i+1].start - PPolynomial PPolynomial::operator - (const PPolynomial& p) const{ - PPolynomial q; - int i,j; - size_t idx=0; - q.set(polyCount+p.polyCount); - i=j=-1; - - while(idx=int(p.polyCount)-1) {q.polys[idx]= polys[++i];} - else if (i>=int( polyCount)-1) {q.polys[idx].start=p.polys[++j].start;q.polys[idx].p=p.polys[j].p*(-1.0);} - else if(polys[i+1].start - PPolynomial& PPolynomial::addScaled(const PPolynomial& p,double scale){ - int i,j; - StartingPolynomial* oldPolys=polys; - size_t idx=0,cnt=0,oldPolyCount=polyCount; - polyCount=0; - polys=NULL; - set(oldPolyCount+p.polyCount); - i=j=-1; - while(cnt=int( p.polyCount)-1) {polys[idx]=oldPolys[++i];} - else if (i>=int(oldPolyCount)-1) {polys[idx].start= p.polys[++j].start;polys[idx].p=p.polys[j].p*scale;} - else if (oldPolys[i+1].start - template - PPolynomial PPolynomial::operator * (const PPolynomial& p) const{ - PPolynomial q; - StartingPolynomial *sp; - int i,j,spCount=int(polyCount*p.polyCount); - - sp=(StartingPolynomial*)malloc(sizeof(StartingPolynomial)*spCount); - for(i=0;i - template - PPolynomial PPolynomial::operator * (const Polynomial& p) const{ - PPolynomial q; - q.set(polyCount); - for(int i=0;i - PPolynomial PPolynomial::scale( double s ) const - { - PPolynomial q; - q.set(polyCount); - for(size_t i=0;i - PPolynomial PPolynomial::shift( double s ) const - { - PPolynomial q; - q.set(polyCount); - for(size_t i=0;i - PPolynomial PPolynomial::derivative(void) const{ - PPolynomial q; - q.set(polyCount); - for(size_t i=0;i - PPolynomial PPolynomial::integral(void) const{ - int i; - PPolynomial q; - q.set(polyCount); - for(i=0;i - PPolynomial& PPolynomial::operator += ( double s ) {polys[0].p+=s;} - template - PPolynomial& PPolynomial::operator -= ( double s ) {polys[0].p-=s;} - template - PPolynomial& PPolynomial::operator *= ( double s ) - { - for(int i=0;i - PPolynomial& PPolynomial::operator /= ( double s ) - { - for(size_t i=0;i - PPolynomial PPolynomial::operator + ( double s ) const - { - PPolynomial q=*this; - q+=s; - return q; - } - template - PPolynomial PPolynomial::operator - ( double s ) const - { - PPolynomial q=*this; - q-=s; - return q; - } - template - PPolynomial PPolynomial::operator * ( double s ) const - { - PPolynomial q=*this; - q*=s; - return q; - } - template - PPolynomial PPolynomial::operator / ( double s ) const - { - PPolynomial q=*this; - q/=s; - return q; - } - - template - void PPolynomial::printnl(void) const{ - Polynomial p; - - if(!polyCount){ - Polynomial p; - printf("[-Infinity,Infinity]\n"); - } - else{ - for(size_t i=0;i inline PPolynomial< 0 > PPolynomial< 0 >::BSpline( double radius ) - { - PPolynomial q; - q.set(2); - - q.polys[0].start=-radius; - q.polys[1].start= radius; - - q.polys[0].p.coefficients[0]= 1.0; - q.polys[1].p.coefficients[0]=-1.0; - return q; - } - template< int Degree > - PPolynomial< Degree > PPolynomial::BSpline( double radius ) - { - return PPolynomial< Degree-1 >::BSpline().MovingAverage( radius ); - } - template - PPolynomial PPolynomial::MovingAverage( double radius ) - { - PPolynomial A; - Polynomial p; - StartingPolynomial* sps; - - sps=(StartingPolynomial*)malloc(sizeof(StartingPolynomial)*polyCount*2); - - for(int i=0;i - void PPolynomial::getSolutions(double c,std::vector& roots,double EPS,double min,double max) const{ - Polynomial p; - std::vector tempRoots; - - p.setZero(); - for(size_t i=0;imax){break;} - if(ipolys[i].start && (i+1==polyCount || tempRoots[j]<=polys[i+1].start)){ - if(tempRoots[j]>min && tempRoots[j] - void PPolynomial::write(FILE* fp,int samples,double min,double max) const{ - fwrite(&samples,sizeof(int),1,fp); - for(int i=0;i - struct MatrixEntry - { - MatrixEntry( void ) { N =-1; Value = 0; } - MatrixEntry( int i ) { N = i; Value = 0; } - int N; - T Value; - }; - - template class SparseMatrix - { - private: - bool _contiguous; - int _maxEntriesPerRow; - static int UseAlloc; - public: - static Allocator > internalAllocator; - static int UseAllocator(void); - static void SetAllocator( int blockSize ); - - int rows; - int* rowSizes; - MatrixEntry** m_ppElements; - MatrixEntry< T >* operator[] ( int idx ) { return m_ppElements[idx]; } - const MatrixEntry< T >* operator[] ( int idx ) const { return m_ppElements[idx]; } - - SparseMatrix( void ); - SparseMatrix( int rows ); - SparseMatrix( int rows , int maxEntriesPerRow ); - void Resize( int rows ); - void Resize( int rows , int maxEntriesPerRow ); - void SetRowSize( int row , int count ); - int Entries( void ) const; - - SparseMatrix( const SparseMatrix& M ); - ~SparseMatrix(); - - void SetZero(); - void SetIdentity(); - - SparseMatrix& operator = (const SparseMatrix& M); - - SparseMatrix operator * (const T& V) const; - SparseMatrix& operator *= (const T& V); - - - SparseMatrix operator * (const SparseMatrix& M) const; - SparseMatrix Multiply( const SparseMatrix& M ) const; - SparseMatrix MultiplyTranspose( const SparseMatrix& Mt ) const; - - template - Vector operator * (const Vector& V) const; - template - Vector Multiply( const Vector& V ) const; - template - void Multiply( const Vector& In , Vector& Out , int threads=1 ) const; - - - SparseMatrix Transpose() const; - - static int Solve (const SparseMatrix& M,const Vector& b, int iters,Vector& solution,const T eps=1e-8); - - template - static int SolveSymmetric( const SparseMatrix& M , const Vector& b , int iters , Vector& solution , const T2 eps=1e-8 , int reset=1 , int threads=1 ); - - bool write( FILE* fp ) const; - bool write( const char* fileName ) const; - bool read( FILE* fp ); - bool read( const char* fileName ); - }; - - template< class T2 > - struct MapReduceVector - { - private: - int _dim; - public: - std::vector< T2* > out; - MapReduceVector( void ) { _dim = 0; } - ~MapReduceVector( void ) - { - if( _dim ) for( int t=0 ; t - class SparseSymmetricMatrix : public SparseMatrix< T > - { - public: - - template< class T2 > - Vector< T2 > operator * ( const Vector& V ) const; - - template< class T2 > - Vector< T2 > Multiply( const Vector& V ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , bool addDCTerm=false ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , MapReduceVector< T2 >& OutScratch , bool addDCTerm=false ) const; - - template< class T2 > - void Multiply( const Vector& In, Vector& Out , std::vector< T2* >& OutScratch , const std::vector< int >& bounds ) const; - - template< class T2 > - static int Solve( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& solution , T2 eps=1e-8 , int reset=1 , int threads=0 , bool addDCTerm=false , bool solveNormal=false ); - - template< class T2 > - static int Solve( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& solution , MapReduceVector& scratch , T2 eps=1e-8 , int reset=1 , bool addDCTerm=false , bool solveNormal=false ); -#if defined _WIN32 && !defined __MINGW32__ - template< class T2 > - static int SolveAtomic( const SparseSymmetricMatrix& M , const Vector& b , int iters , Vector& solution , T2 eps=1e-8 , int reset=1 , int threads=0 , bool solveNormal=false ); -#endif // _WIN32 || __MINGW32__ - template - static int Solve( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , int iters , Vector& solution , int reset=1 ); - - template< class T2 > - void getDiagonal( Vector< T2 >& diagonal ) const; - }; - - - } -} - - -#include "sparse_matrix.hpp" - -#endif - diff --git a/plugins/probe/3rd/poisson4/sparse_matrix.hpp b/plugins/probe/3rd/poisson4/sparse_matrix.hpp deleted file mode 100644 index 29fdc77939..0000000000 --- a/plugins/probe/3rd/poisson4/sparse_matrix.hpp +++ /dev/null @@ -1,973 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#include -#ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif // WIN32_LEAN_AND_MEAN -# ifndef NOMINMAX -# define NOMINMAX -# endif // NOMINMAX -# include -#endif //_WIN32 - -/////////////////// -// SparseMatrix // -/////////////////// -/////////////////////////////////////////// -// Static Allocator Methods and Memebers // -/////////////////////////////////////////// - -namespace pcl -{ - namespace poisson - { - - - template int SparseMatrix::UseAlloc=0; - template Allocator > SparseMatrix::internalAllocator; - template int SparseMatrix::UseAllocator(void){return UseAlloc;} - template - void SparseMatrix::SetAllocator( int blockSize ) - { - if(blockSize>0){ - UseAlloc=1; - internalAllocator.set(blockSize); - } - else{UseAlloc=0;} - } - /////////////////////////////////////// - // SparseMatrix Methods and Memebers // - /////////////////////////////////////// - - template< class T > - SparseMatrix< T >::SparseMatrix( void ) - { - _contiguous = false; - _maxEntriesPerRow = 0; - rows = 0; - rowSizes = NULL; - m_ppElements = NULL; - } - - template< class T > SparseMatrix< T >::SparseMatrix( int rows ) : SparseMatrix< T >() { Resize( rows ); } - template< class T > SparseMatrix< T >::SparseMatrix( int rows , int maxEntriesPerRow ) : SparseMatrix< T >() { Resize( rows , maxEntriesPerRow ); } - - template< class T > - SparseMatrix< T >::SparseMatrix( const SparseMatrix& M ) : SparseMatrix< T >() - { - if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); - else Resize( M.rows ); - for( int i=0 ; i ) * rowSizes[i] ); - } - } - template - int SparseMatrix::Entries( void ) const - { - int e = 0; - for( int i=0 ; i - SparseMatrix& SparseMatrix::operator = (const SparseMatrix& M) - { - if( M._contiguous ) Resize( M.rows , M._maxEntriesPerRow ); - else Resize( M.rows ); - for( int i=0 ; i ) * rowSizes[i] ); - } - return *this; - } - - template - SparseMatrix::~SparseMatrix( void ){ Resize( 0 ); } - - template< class T > - bool SparseMatrix< T >::write( const char* fileName ) const - { - FILE* fp = fopen( fileName , "wb" ); - if( !fp ) return false; - bool ret = write( fp ); - fclose( fp ); - return ret; - } - template< class T > - bool SparseMatrix< T >::read( const char* fileName ) - { - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) return false; - bool ret = read( fp ); - fclose( fp ); - return ret; - } - template< class T > - bool SparseMatrix< T >::write( FILE* fp ) const - { - if( fwrite( &rows , sizeof( int ) , 1 , fp )!=1 ) return false; - if( fwrite( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; - for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; - return true; - } - template< class T > - bool SparseMatrix< T >::read( FILE* fp ) - { - int r; - if( fread( &r , sizeof( int ) , 1 , fp )!=1 ) return false; - Resize( r ); - if( fread( rowSizes , sizeof( int ) , rows , fp )!=rows ) return false; - for( int i=0 ; i ) , rowSizes[i] , fp )!=rowSizes[i] ) return false; - } - return true; - } - - - template< class T > - void SparseMatrix< T >::Resize( int r ) - { - if( rows>0 ) - { - - if( !UseAlloc ) - if( _contiguous ){ if( _maxEntriesPerRow ) free( m_ppElements[0] ); } - else for( int i=0 ; i** )malloc( sizeof( MatrixEntry< T >* ) * r ); - } - _contiguous = false; - _maxEntriesPerRow = 0; - } - template< class T > - void SparseMatrix< T >::Resize( int r , int e ) - { - if( rows>0 ) - { - if( !UseAlloc ) - if( _contiguous ){ if( _maxEntriesPerRow ) free( m_ppElements[0] ); } - else for( int i=0 ; i** )malloc( sizeof( MatrixEntry< T >* ) * r ); - m_ppElements[0] = ( MatrixEntry< T >* )malloc( sizeof( MatrixEntry< T > ) * r * e ); - for( int i=1 ; i - void SparseMatrix< T >::SetRowSize( int row , int count ) - { - if( _contiguous ) - { - if (count > _maxEntriesPerRow) - { - POISSON_THROW_EXCEPTION (pcl::poisson::PoissonBadArgumentException, "Attempted to set row size on contiguous matrix larger than max row size: (requested)"<< count << " > (maximum)" << _maxEntriesPerRow ); - } - rowSizes[row] = count; - } - else if( row>=0 && row0 ) m_ppElements[row] = ( MatrixEntry< T >* )malloc( sizeof( MatrixEntry< T > ) * count ); - } - } - } - - - template - void SparseMatrix::SetZero() - { - Resize(this->m_N, this->m_M); - } - - template - void SparseMatrix::SetIdentity() - { - SetZero(); - for(int ij=0; ij < Min( this->Rows(), this->Columns() ); ij++) - (*this)(ij,ij) = T(1); - } - - template - SparseMatrix SparseMatrix::operator * (const T& V) const - { - SparseMatrix M(*this); - M *= V; - return M; - } - - template - SparseMatrix& SparseMatrix::operator *= (const T& V) - { - for (int i=0; iRows(); i++) - { - for(int ii=0;ii - SparseMatrix SparseMatrix::Multiply( const SparseMatrix& M ) const - { - SparseMatrix R( this->Rows(), M.Columns() ); - for(int i=0; i - template - Vector SparseMatrix::Multiply( const Vector& V ) const - { - Vector R( rows ); - - for (int i=0; i - template - void SparseMatrix::Multiply( const Vector& In , Vector& Out , int threads ) const - { -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i - SparseMatrix SparseMatrix::operator * (const SparseMatrix& M) const - { - return Multiply(M); - } - template - template - Vector SparseMatrix::operator * (const Vector& V) const - { - return Multiply(V); - } - - template - SparseMatrix SparseMatrix::Transpose() const - { - SparseMatrix M( this->Columns(), this->Rows() ); - - for (int i=0; iRows(); i++) - { - for(int ii=0;ii - template - int SparseMatrix::SolveSymmetric( const SparseMatrix& M , const Vector& b , int iters , Vector& solution , const T2 eps , int reset , int threads ) - { - if( reset ) - { - solution.Resize( b.Dimensions() ); - solution.SetZero(); - } - Vector< T2 > r; - r.Resize( solution.Dimensions() ); - M.Multiply( solution , r ); - r = b - r; - Vector< T2 > d = r; - double delta_new , delta_0; - for( int i=0 ; i q; - q.Resize( d.Dimensions() ); - for( ii=0; iieps*delta_0 ; ii++ ) - { - M.Multiply( d , q , threads ); - double dDotQ = 0 , alpha = 0; - for( int i=0 ; i - int SparseMatrix::Solve(const SparseMatrix& M,const Vector& b,int iters,Vector& solution,const T eps){ - SparseMatrix mTranspose=M.Transpose(); - Vector bb=mTranspose*b; - Vector d,r,Md; - T alpha,beta,rDotR; - int i; - - solution.Resize(M.Columns()); - solution.SetZero(); - - d=r=bb; - rDotR=r.Dot(r); - for(i=0;ieps;i++){ - T temp; - Md=mTranspose*(M*d); - alpha=rDotR/d.Dot(Md); - solution+=d*alpha; - r-=Md*alpha; - temp=r.Dot(r); - beta=temp/rDotR; - rDotR=temp; - d=r+d*beta; - } - return i; - } - - - - - /////////////////////////// - // SparseSymmetricMatrix // - /////////////////////////// - template - template - Vector SparseSymmetricMatrix::operator * (const Vector& V) const {return Multiply(V);} - template - template - Vector SparseSymmetricMatrix::Multiply( const Vector& V ) const - { - Vector R( SparseMatrix::rows ); - - for(int i=0; i::rows; i++){ - for(int ii=0;ii::rowSizes[i];ii++){ - int j=SparseMatrix::m_ppElements[i][ii].N; - R(i)+=SparseMatrix::m_ppElements[i][ii].Value * V.m_pV[j]; - R(j)+=SparseMatrix::m_ppElements[i][ii].Value * V.m_pV[i]; - } - } - return R; - } - - template - template - void SparseSymmetricMatrix::Multiply( const Vector& In , Vector& Out , bool addDCTerm ) const - { - Out.SetZero(); - const T2* in = &In[0]; - T2* out = &Out[0]; - T2 dcTerm = T2( 0 ); - if( addDCTerm ) - { - for( int i=0 ; i::rows ; i++ ) dcTerm += in[i]; - dcTerm /= SparseMatrix::rows; - } - for( int i=0 ; iSparseMatrix::rows ; i++ ) - { - const MatrixEntry* temp = SparseMatrix::m_ppElements[i]; - const MatrixEntry* end = temp + SparseMatrix::rowSizes[i]; - const T2& in_i_ = in[i]; - T2 out_i = T2(0); - for( ; temp!=end ; temp++ ) - { - int j=temp->N; - T2 v=temp->Value; - out_i += v * in[j]; - out[j] += v * in_i_; - } - out[i] += out_i; - } - if( addDCTerm ) for( int i=0 ; i::rows ; i++ ) out[i] += dcTerm; - } - template - template - void SparseSymmetricMatrix::Multiply( const Vector& In , Vector& Out , MapReduceVector< T2 >& OutScratch , bool addDCTerm ) const - { - int dim = int( In.Dimensions() ); - const T2* in = &In[0]; - int threads = OutScratch.threads(); - if( addDCTerm ) - { - T2 dcTerm = 0; -#pragma omp parallel for num_threads( threads ) reduction ( + : dcTerm ) - for( int t=0 ; t::rows*t)/threads ; i<(SparseMatrix::rows*(t+1))/threads ; i++ ) - { - const T2& in_i_ = in[i]; - T2& out_i_ = out[i]; - for( const MatrixEntry< T > *temp = SparseMatrix::m_ppElements[i] , *end = temp+SparseMatrix::rowSizes[i] ; temp!=end ; temp++ ) - { - int j = temp->N; - T2 v = temp->Value; - out_i_ += v * in[j]; - out[j] += v * in_i_; - } - dcTerm += in_i_; - } - } - dcTerm /= dim; - dim = int( Out.Dimensions() ); - T2* out = &Out[0]; -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i::rows*t)/threads ; i<(SparseMatrix::rows*(t+1))/threads ; i++ ) - { - const T2& in_i_ = in[i]; - T2& out_i_ = out[i]; - for( const MatrixEntry< T > *temp = SparseMatrix::m_ppElements[i] , *end = temp+SparseMatrix::rowSizes[i] ; temp!=end ; temp++ ) - { - int j = temp->N; - T2 v = temp->Value; - out_i_ += v * in[j]; - out[j] += v * in_i_; - } - } - } - dim = int( Out.Dimensions() ); - T2* out = &Out[0]; -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i - template - void SparseSymmetricMatrix::Multiply( const Vector& In , Vector& Out , std::vector< T2* >& OutScratch , const std::vector< int >& bounds ) const - { - int dim = In.Dimensions(); - const T2* in = &In[0]; - int threads = OutScratch.size(); -#pragma omp parallel for num_threads( threads ) - for( int t=0 ; t* temp = SparseMatrix::m_ppElements[i]; - const MatrixEntry* end = temp + SparseMatrix::rowSizes[i]; - const T2& in_i_ = in[i]; - T2& out_i_ = out[i]; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - T2 v = temp->Value; - out_i_ += v * in[j]; - out[j] += v * in_i_; - } - } - } - T2* out = &Out[0]; -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; i - void MultiplyAtomic( const SparseSymmetricMatrix< T >& A , const Vector< float >& In , Vector< float >& Out , int threads , const int* partition=NULL ) - { - Out.SetZero(); - const float* in = &In[0]; - float* out = &Out[0]; - if( partition ) -#pragma omp parallel for num_threads( threads ) - for( int t=0 ; t* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const float& in_i = in[i]; - float out_i = 0.; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - float v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } - else -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const float& in_i = in[i]; - float out_i = 0.f; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - float v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } - } - template< class T > - void MultiplyAtomic( const SparseSymmetricMatrix< T >& A , const Vector< double >& In , Vector< double >& Out , int threads , const int* partition=NULL ) - { - Out.SetZero(); - const double* in = &In[0]; - double* out = &Out[0]; - - if( partition ) -#pragma omp parallel for num_threads( threads ) - for( int t=0 ; t* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const double& in_i = in[i]; - double out_i = 0.; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - T v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } - else -#pragma omp parallel for num_threads( threads ) - for( int i=0 ; i* temp = A[i]; - const MatrixEntry< T >* end = temp + A.rowSizes[i]; - const double& in_i = in[i]; - double out_i = 0.; - for( ; temp!=end ; temp++ ) - { - int j = temp->N; - T v = temp->Value; - out_i += v * in[j]; - AtomicIncrement( out+j , v * in_i ); - } - AtomicIncrement( out+i , out_i ); - } - } - - template< class T > - template< class T2 > - int SparseSymmetricMatrix< T >::SolveAtomic( const SparseSymmetricMatrix< T >& A , const Vector< T2 >& b , int iters , Vector< T2 >& x , T2 eps , int reset , int threads , bool solveNormal ) - { - eps *= eps; - int dim = b.Dimensions(); - if( reset ) - { - x.Resize( dim ); - x.SetZero(); - } - Vector< T2 > r( dim ) , d( dim ) , q( dim ); - Vector< T2 > temp; - if( solveNormal ) temp.Resize( dim ); - T2 *_x = &x[0] , *_r = &r[0] , *_d = &d[0] , *_q = &q[0]; - const T2* _b = &b[0]; - - std::vector< int > partition( threads+1 ); - { - int eCount = 0; - for( int i=0 ; i=eCount*(t+1) ) - { - partition[t+1] = i; - break; - } - } - } - partition[threads] = A.rows; - } - if( solveNormal ) - { - MultiplyAtomic( A , x , temp , threads , &partition[0] ); - MultiplyAtomic( A , temp , r , threads , &partition[0] ); - MultiplyAtomic( A , b , temp , threads , &partition[0] ); -#pragma omp parallel for num_threads( threads ) schedule( static ) - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - if( solveNormal ) MultiplyAtomic( A , d , temp , threads , &partition[0] ) , MultiplyAtomic( A , temp , q , threads , &partition[0] ); - else MultiplyAtomic( A , d , q , threads , &partition[0] ); - double dDotQ = 0; - for( int i=0 ; i - template< class T2 > - int SparseSymmetricMatrix< T >::Solve( const SparseSymmetricMatrix& A , const Vector& b , int iters , Vector& x , MapReduceVector< T2 >& scratch , T2 eps , int reset , bool addDCTerm , bool solveNormal ) - { - int threads = scratch.threads(); - eps *= eps; - int dim = int( b.Dimensions() ); - Vector< T2 > r( dim ) , d( dim ) , q( dim ) , temp; - if( reset ) x.Resize( dim ); - if( solveNormal ) temp.Resize( dim ); - T2 *_x = &x[0] , *_r = &r[0] , *_d = &d[0] , *_q = &q[0]; - const T2* _b = &b[0]; - - double delta_new = 0 , delta_0; - if( solveNormal ) - { - A.Multiply( x , temp , scratch , addDCTerm ) , A.Multiply( temp , r , scratch , addDCTerm ) , A.Multiply( b , temp , scratch , addDCTerm ); -#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - if( solveNormal ) A.Multiply( d , temp , scratch , addDCTerm ) , A.Multiply( temp , q , scratch , addDCTerm ); - else A.Multiply( d , q , scratch , addDCTerm ); - double dDotQ = 0; -#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) - for( int i=0 ; i - template< class T2 > - int SparseSymmetricMatrix::Solve( const SparseSymmetricMatrix& A , const Vector& b , int iters , Vector& x , T2 eps , int reset , int threads , bool addDCTerm , bool solveNormal ) - { - eps *= eps; - int dim = int( b.Dimensions() ); - MapReduceVector< T2 > outScratch; - if( threads<1 ) threads = 1; - if( threads>1 ) outScratch.resize( threads , dim ); - if( reset ) x.Resize( dim ); - Vector< T2 > r( dim ) , d( dim ) , q( dim ); - Vector< T2 > temp; - if( solveNormal ) temp.Resize( dim ); - T2 *_x = &x[0] , *_r = &r[0] , *_d = &d[0] , *_q = &q[0]; - const T2* _b = &b[0]; - - double delta_new = 0 , delta_0; - - if( solveNormal ) - { - if( threads>1 ) A.Multiply( x , temp , outScratch , addDCTerm ) , A.Multiply( temp , r , outScratch , addDCTerm ) , A.Multiply( b , temp , outScratch , addDCTerm ); - else A.Multiply( x , temp , addDCTerm ) , A.Multiply( temp , r , addDCTerm ) , A.Multiply( b , temp , addDCTerm ); -#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) - for( int i=0 ; i1 ) A.Multiply( x , r , outScratch , addDCTerm ); - else A.Multiply( x , r , addDCTerm ); -#pragma omp parallel for num_threads( threads ) reduction( + : delta_new ) - for( int i=0 ; ieps*delta_0 ; ii++ ) - { - if( solveNormal ) - { - if( threads>1 ) A.Multiply( d , temp , outScratch , addDCTerm ) , A.Multiply( temp , q , outScratch , addDCTerm ); - else A.Multiply( d , temp , addDCTerm ) , A.Multiply( temp , q , addDCTerm ); - } - else - { - if( threads>1 ) A.Multiply( d , q , outScratch , addDCTerm ); - else A.Multiply( d , q , addDCTerm ); - } - double dDotQ = 0; -#pragma omp parallel for num_threads( threads ) reduction( + : dDotQ ) - for( int i=0 ; i1 ) A.Multiply( x , temp , outScratch , addDCTerm ) , A.Multiply( temp , r , outScratch , addDCTerm ); - else A.Multiply( x , temp , addDCTerm ) , A.Multiply( temp , r , addDCTerm ); - } - else - { - if( threads>1 ) A.Multiply( x , r , outScratch , addDCTerm ); - else A.Multiply( x , r , addDCTerm ); - } -#pragma omp parallel for num_threads( threads ) reduction ( + : delta_new ) - for( int i=0 ; i - template - int SparseSymmetricMatrix::Solve( const SparseSymmetricMatrix& M , const Vector& diagonal , const Vector& b , int iters , Vector& solution , int reset ) - { - Vector d,r,Md; - - if(reset) - { - solution.Resize(b.Dimensions()); - solution.SetZero(); - } - Md.Resize(M.rows); - for( int i=0 ; i - template< class T2 > - void SparseSymmetricMatrix< T >::getDiagonal( Vector< T2 >& diagonal ) const - { - diagonal.Resize( SparseMatrix::rows ); - for( int i=0 ; i::rows ; i++ ) - { - diagonal[i] = 0.; - for( int j=0 ; j::rowSizes[i] ; j++ ) if( SparseMatrix::m_ppElements[i][j].N==i ) diagonal[i] += SparseMatrix::m_ppElements[i][j].Value * 2; - } - } - - } -} diff --git a/plugins/probe/3rd/poisson4/vector.h b/plugins/probe/3rd/poisson4/vector.h deleted file mode 100644 index bbf6b40fe7..0000000000 --- a/plugins/probe/3rd/poisson4/vector.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef __VECTOR_HPP -#define __VECTOR_HPP - -#define Assert assert -#include - - -namespace pcl -{ - namespace poisson - { - template - class Vector - { - public: - Vector(); - Vector( const Vector& V ); - Vector( size_t N ); - Vector( size_t N, T* pV ); - ~Vector(); - - const T& operator () (size_t i) const; - T& operator () (size_t i); - const T& operator [] (size_t i) const; - T& operator [] (size_t i); - - void SetZero(); - - size_t Dimensions() const; - void Resize( size_t N ); - - Vector operator * (const T& A) const; - Vector operator / (const T& A) const; - Vector operator - (const Vector& V) const; - Vector operator + (const Vector& V) const; - - Vector& operator *= (const T& A); - Vector& operator /= (const T& A); - Vector& operator += (const Vector& V); - Vector& operator -= (const Vector& V); - - Vector& AddScaled(const Vector& V,const T& scale); - Vector& SubtractScaled(const Vector& V,const T& scale); - static void Add(const Vector& V1,const T& scale1,const Vector& V2,const T& scale2,Vector& Out); - static void Add(const Vector& V1,const T& scale1,const Vector& V2,Vector& Out); - - Vector operator - () const; - - Vector& operator = (const Vector& V); - - T Dot( const Vector& V ) const; - - T Length() const; - - T Norm( size_t Ln ) const; - void Normalize(); - - bool write( FILE* fp ) const; - bool write( const char* fileName ) const; - bool read( FILE* fp ); - bool read( const char* fileName ); - - T* m_pV; - protected: - size_t m_N; - - }; - - template - class NVector - { - public: - NVector(); - NVector( const NVector& V ); - NVector( size_t N ); - NVector( size_t N, T* pV ); - ~NVector(); - - const T* operator () (size_t i) const; - T* operator () (size_t i); - const T* operator [] (size_t i) const; - T* operator [] (size_t i); - - void SetZero(); - - size_t Dimensions() const; - void Resize( size_t N ); - - NVector operator * (const T& A) const; - NVector operator / (const T& A) const; - NVector operator - (const NVector& V) const; - NVector operator + (const NVector& V) const; - - NVector& operator *= (const T& A); - NVector& operator /= (const T& A); - NVector& operator += (const NVector& V); - NVector& operator -= (const NVector& V); - - NVector& AddScaled(const NVector& V,const T& scale); - NVector& SubtractScaled(const NVector& V,const T& scale); - static void Add(const NVector& V1,const T& scale1,const NVector& V2,const T& scale2,NVector& Out); - static void Add(const NVector& V1,const T& scale1,const NVector& V2, NVector& Out); - - NVector operator - () const; - - NVector& operator = (const NVector& V); - - T Dot( const NVector& V ) const; - - T Length() const; - - T Norm( size_t Ln ) const; - void Normalize(); - - T* m_pV; - protected: - size_t m_N; - - }; - - } -} - - -#include "vector.hpp" - -#endif diff --git a/plugins/probe/3rd/poisson4/vector.hpp b/plugins/probe/3rd/poisson4/vector.hpp deleted file mode 100644 index f8a5bd8e6d..0000000000 --- a/plugins/probe/3rd/poisson4/vector.hpp +++ /dev/null @@ -1,492 +0,0 @@ -/* -Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. Redistributions in binary form must reproduce -the above copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the distribution. - -Neither the name of the Johns Hopkins University nor the names of its contributors -may be used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. -*/ - -#ifndef __VECTORIMPL_HPP -#define __VECTORIMPL_HPP - -//////////// -// Vector // -//////////// -namespace pcl -{ - namespace poisson - { - - - template - Vector::Vector() - { - m_N = 0; - m_pV = 0; - } - template - Vector::Vector( const Vector& V ) - { - m_N = 0; - m_pV = 0; - Resize(V.m_N); - memcpy( m_pV, V.m_pV, m_N*sizeof(T) ); - } - template - Vector::Vector( size_t N ) - { - m_N=0; - m_pV=0; - Resize(N); - } - template - void Vector::Resize( size_t N ) - { - if(m_N!=N){ - if(m_N){delete[] m_pV;} - m_pV=NULL; - m_N = N; - if(N){m_pV = new T[N];} - } - memset( m_pV, 0, N*sizeof(T) ); - } - template - Vector::Vector( size_t N, T* pV ) - { - Resize(N); - memcpy( m_pV, pV, N*sizeof(T) ); - } - template - Vector::~Vector(){Resize(0);} - template - Vector& Vector::operator = (const Vector& V) - { - Resize(V.m_N); - memcpy( m_pV, V.m_pV, m_N*sizeof(T) ); - return *this; - } - template - size_t Vector::Dimensions() const{return m_N;} - template - void Vector::SetZero(void){for (size_t i=0; i - const T& Vector::operator () (size_t i) const - { - Assert( i < m_N ); - return m_pV[i]; - } - template - T& Vector::operator () (size_t i) - { - return m_pV[i]; - } - template - const T& Vector::operator [] (size_t i) const - { - return m_pV[i]; - } - template - T& Vector::operator [] (size_t i) - { - return m_pV[i]; - } - template - Vector Vector::operator * (const T& A) const - { - Vector V(*this); - for (size_t i=0; i - Vector& Vector::operator *= (const T& A) - { - for (size_t i=0; i - Vector Vector::operator / (const T& A) const - { - Vector V(*this); - for (size_t i=0; i - Vector& Vector::operator /= (const T& A) - { - for (size_t i=0; i - Vector Vector::operator + (const Vector& V0) const - { - Vector V(m_N); - for (size_t i=0; i - Vector& Vector::AddScaled(const Vector& V,const T& scale) - { - for (size_t i=0; i - Vector& Vector::SubtractScaled(const Vector& V,const T& scale) - { - for (size_t i=0; i - void Vector::Add(const Vector& V1,const T& scale1,const Vector& V2,const T& scale2,Vector& Out){ - for (size_t i=0; i - void Vector::Add(const Vector& V1,const T& scale1,const Vector& V2,Vector& Out){ - for (size_t i=0; i - Vector& Vector::operator += (const Vector& V) - { - for (size_t i=0; i - Vector Vector::operator - (const Vector& V0) const - { - Vector V(m_N); - for (size_t i=0; i - Vector Vector::operator - (void) const - { - Vector V(m_N); - - for (size_t i=0; i - Vector& Vector::operator -= (const Vector& V) - { - for (size_t i=0; i - T Vector::Norm( size_t Ln ) const - { - T N = T(); - for (size_t i = 0; i - void Vector::Normalize() - { - T N = 1.0f/Norm(2); - for (size_t i = 0; i - T Vector::Length() const - { - T N = T(); - for (size_t i = 0; i - T Vector::Dot( const Vector& V ) const - { - T V0 = T(); - for (size_t i=0; i - bool Vector< T >::read( const char* fileName ) - { - FILE* fp = fopen( fileName , "rb" ); - if( !fp ) return false; - bool ret = read( fp ); - fclose( fp ); - return ret; - } - template< class T > - bool Vector< T >::write( const char* fileName ) const - { - FILE* fp = fopen( fileName , "wb" ); - if( !fp ) return false; - bool ret = write( fp ); - fclose( fp ); - return ret; - } - template< class T > - bool Vector< T >::read( FILE* fp ) - { - int d; - if( fread( &d , sizeof(int) , 1 , fp )!=1 ) return false; - Resize( d ); - if( fread( &(*this)[0] , sizeof( T ) , d , fp )!=d ) return false; - return true; - } - template< class T > - bool Vector< T >::write( FILE* fp ) const - { - if( fwrite( &m_N , sizeof( int ) , 1 , fp )!=1 ) return false; - if( fwrite( &(*this)[0] , sizeof( T ) , m_N , fp )!=m_N ) return false; - return true; - } - - - ///////////// - // NVector // - ///////////// - template - NVector::NVector() - { - m_N = 0; - m_pV = 0; - } - template - NVector::NVector( const NVector& V ) - { - m_N = 0; - m_pV = 0; - Resize(V.m_N); - memcpy( m_pV, V.m_pV, m_N*sizeof(T)*Dim ); - } - template - NVector::NVector( size_t N ) - { - m_N=0; - m_pV=0; - Resize(N); - } - template - void NVector::Resize( size_t N ) - { - if(m_N!=N){ - if(m_N){delete[] m_pV;} - m_pV=NULL; - m_N = N; - if(N){m_pV = new T[Dim*N];} - } - memset( m_pV, 0, N*sizeof(T)*Dim ); - } - template - NVector::NVector( size_t N, T* pV ) - { - Resize(N); - memcpy( m_pV, pV, N*sizeof(T)*Dim ); - } - template - NVector::~NVector(){Resize(0);} - template - NVector& NVector::operator = (const NVector& V) - { - Resize(V.m_N); - memcpy( m_pV, V.m_pV, m_N*sizeof(T)*Dim ); - return *this; - } - template - size_t NVector::Dimensions() const{return m_N;} - template - void NVector::SetZero(void){for (size_t i=0; i - const T* NVector::operator () (size_t i) const - { - Assert( i < m_N ); - return &m_pV[i*Dim]; - } - template - T* NVector::operator () (size_t i) - { - return &m_pV[i*Dim]; - } - template - const T* NVector::operator [] (size_t i) const - { - return &m_pV[i*Dim]; - } - template - T* NVector::operator [] (size_t i) - { - return &m_pV[i*Dim]; - } - template - NVector NVector::operator * (const T& A) const - { - NVector V(*this); - for (size_t i=0; i - NVector& NVector::operator *= (const T& A) - { - for (size_t i=0; i - NVector NVector::operator / (const T& A) const - { - NVector V(*this); - for (size_t i=0; i - NVector& NVector::operator /= (const T& A) - { - for (size_t i=0; i - NVector NVector::operator + (const NVector& V0) const - { - NVector V(m_N); - for (size_t i=0; i - NVector& NVector::AddScaled(const NVector& V,const T& scale) - { - for (size_t i=0; i - NVector& NVector::SubtractScaled(const NVector& V,const T& scale) - { - for (size_t i=0; i - void NVector::Add(const NVector& V1,const T& scale1,const NVector& V2,const T& scale2,NVector& Out){ - for (size_t i=0; i - void NVector::Add(const NVector& V1,const T& scale1,const NVector& V2,NVector& Out){ - for (size_t i=0; i - NVector& NVector::operator += (const NVector& V) - { - for (size_t i=0; i - NVector NVector::operator - (const NVector& V0) const - { - NVector V(m_N); - for (size_t i=0; i - NVector NVector::operator - (void) const - { - NVector V(m_N); - - for (size_t i=0; i - NVector& NVector::operator -= (const NVector& V) - { - for (size_t i=0; i - T NVector::Norm( size_t Ln ) const - { - T N = T(); - for (size_t i = 0; i - void NVector::Normalize() - { - T N = 1.0f/Norm(2); - for (size_t i = 0; i - T NVector::Length() const - { - T N = T(); - for (size_t i = 0; i - T NVector::Dot( const NVector& V ) const - { - T V0 = T(); - for (size_t i=0; i class PCLSurfaceBase : public PCLBase { -public: - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - - typedef KdTreeFLANN KdTree; - typedef typename KdTree::Ptr KdTreePtr; - - /** \brief Empty constructor. */ - PCLSurfaceBase() : tree_() {} - - /** \brief Empty destructor */ - virtual ~PCLSurfaceBase() {} - - /** \brief Provide an optional pointer to a search object. - * \param[in] tree a pointer to the spatial search object. - */ - inline void setSearchMethod(const KdTreePtr& tree) { tree_ = tree; } - - /** \brief Get a pointer to the search method used. */ - inline KdTreePtr getSearchMethod() { return (tree_); } - -protected: - /** \brief A pointer to the spatial search object. */ - KdTreePtr tree_; - - /** \brief Abstract class get name method. */ - virtual std::string getClassName() const { return (""); } -}; - -/** \brief SurfaceReconstruction represents a base surface reconstruction - * class. All \b surface reconstruction methods take in a point cloud and - * generate a new surface from it, by either re-sampling the data or - * generating new data altogether. These methods are thus \b not preserving - * the topology of the original data. - * - * \note Reconstruction methods that always preserve the original input - * point cloud data as the surface vertices and simply construct the mesh on - * top should inherit from \ref MeshConstruction. - * - * \author Radu B. Rusu, Michael Dixon, Alexandru E. Ichim - * \ingroup surface - */ -template class SurfaceReconstruction : public PCLSurfaceBase { -public: - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - - using PCLSurfaceBase::input_; - using PCLSurfaceBase::indices_; - using PCLSurfaceBase::initCompute; - using PCLSurfaceBase::deinitCompute; - using PCLSurfaceBase::tree_; - using PCLSurfaceBase::getClassName; - - /** \brief Constructor. */ - SurfaceReconstruction() : check_tree_(true) {} - - /** \brief Destructor. */ - ~SurfaceReconstruction() {} - - /** \brief Base method for surface reconstruction for all points given in - * - * \param[out] points the resultant points lying on the new surface - * \param[out] polygons the resultant polygons, as a set of - * vertices. The Vertices structure contains an array of point indices. - */ - virtual void reconstruct(pcl::PointCloud& points, std::vector& polygons); - -protected: - /** \brief A flag specifying whether or not the derived reconstruction - * algorithm needs the search object \a tree.*/ - bool check_tree_; - - /** \brief Abstract surface reconstruction method. - * \param[out] points the resultant points lying on the surface - * \param[out] polygons the resultant polygons, as a set of vertices. The Vertices structure contains an array of - * point indices. - */ - virtual void performReconstruction(pcl::PointCloud& points, std::vector& polygons) = 0; -}; - -/** \brief MeshConstruction represents a base surface reconstruction - * class. All \b mesh constructing methods that take in a point cloud and - * generate a surface that uses the original data as vertices should inherit - * from this class. - * - * \note Reconstruction methods that generate a new surface or create new - * vertices in locations different than the input data should inherit from - * \ref SurfaceReconstruction. - * - * \author Radu B. Rusu, Michael Dixon, Alexandru E. Ichim - * \ingroup surface - */ -template class MeshConstruction : public PCLSurfaceBase { -public: - using Ptr = std::shared_ptr>; - using ConstPtr = std::shared_ptr>; - - using PCLSurfaceBase::input_; - using PCLSurfaceBase::indices_; - using PCLSurfaceBase::initCompute; - using PCLSurfaceBase::deinitCompute; - using PCLSurfaceBase::tree_; - using PCLSurfaceBase::getClassName; - - /** \brief Constructor. */ - MeshConstruction() : check_tree_(true) {} - - /** \brief Destructor. */ - ~MeshConstruction() {} - - /** \brief Base method for mesh construction for all points given in - * - * \param[out] polygons the resultant polygons, as a set of - * vertices. The Vertices structure contains an array of point indices. - */ - virtual void reconstruct(std::vector& polygons); - -protected: - /** \brief A flag specifying whether or not the derived reconstruction - * algorithm needs the search object \a tree.*/ - bool check_tree_; - - /** \brief Abstract surface reconstruction method. - * \param[out] polygons the resultant polygons, as a set of vertices. The Vertices structure contains an array of - * point indices. - */ - virtual void performReconstruction(std::vector& polygons) = 0; -}; - - -////////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::SurfaceReconstruction::reconstruct( - pcl::PointCloud& points, std::vector& polygons) { - // Copy the header - points.header = input_->header; - - if (!initCompute()) { - points.width = points.height = 0; - points.points.clear(); - polygons.clear(); - return; - } - - // Check if a space search locator was given - if (check_tree_) { - if (!tree_) { - //if (input_->isOrganized()) - //vislib::sys::Log::DefaultLog.WriteError("[Reconstruction] Organized pattern noct supported"); - //tree_.reset(new pcl::search::OrganizedNeighbor()); - //else - tree_.reset(new KdTreeFLANN(false)); - } - - // Send the surface dataset to the spatial locator - tree_->setInputCloud(input_, indices_); - } - - // Set up the output dataset - polygons.clear(); - polygons.reserve( - 2 * indices_->size()); /// NOTE: usually the number of triangles is around twice the number of vertices - // Perform the actual surface reconstruction - performReconstruction(points, polygons); - - deinitCompute(); -} - -template void pcl::MeshConstruction::reconstruct(std::vector& polygons) { - if (!initCompute()) { - polygons.clear(); - return; - } - - // Check if a space search locator was given - if (check_tree_) { - if (!tree_) { - if (input_->isOrganized()) - vislib::sys::Log::DefaultLog.WriteError("[Reconstruction] Organized pattern noct supported"); - //tree_.reset(new pcl::search::OrganizedNeighbor()); - else - tree_.reset(new KdTree(false)); - } - - // Send the surface dataset to the spatial locator - tree_->setInputCloud(input_, indices_); - } - - // Set up the output dataset - // polygons.clear (); - // polygons.reserve (2 * indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of - // vertices - // Perform the actual surface reconstruction - performReconstruction(polygons); - - deinitCompute(); -} -} // namespace pcl diff --git a/plugins/probe/3rd/transforms.h b/plugins/probe/3rd/transforms.h deleted file mode 100644 index 0a29de21f3..0000000000 --- a/plugins/probe/3rd/transforms.h +++ /dev/null @@ -1,815 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2010, Willow Garage, Inc. - * Copyright (c) 2012-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * - */ - -#pragma once - -#include "common.h"" - -namespace pcl -{ - /** \brief Apply an affine transform defined by an Eigen Transform - * \param[in] cloud_in the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z) should be copied into the new transformed cloud - * \note Can be used with cloud_in equal to cloud_out - * \ingroup common - */ - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Transform &transform, - bool copy_all_fields = true); - - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Affine3f &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, cloud_out, transform, copy_all_fields)); - } - - /** \brief Apply an affine transform defined by an Eigen Transform - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z) should be copied into the new transformed cloud - * \ingroup common - */ - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Transform &transform, - bool copy_all_fields = true); - - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Affine3f &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Apply an affine transform defined by an Eigen Transform - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z) should be copied into the new transformed cloud - * \ingroup common - */ - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Transform &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, indices.indices, cloud_out, transform, copy_all_fields)); - } - - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Affine3f &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Transform a point cloud and rotate its normals using an Eigen transform. - * \param[in] cloud_in the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z, normal_x, normal_y, normal_z) should be copied into the new - * transformed cloud - * \note Can be used with cloud_in equal to cloud_out - */ - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Transform &transform, - bool copy_all_fields = true); - - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Affine3f &transform, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, cloud_out, transform, copy_all_fields)); - } - - /** \brief Transform a point cloud and rotate its normals using an Eigen transform. - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z, normal_x, normal_y, normal_z) should be copied into the new - * transformed cloud - */ - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Transform &transform, - bool copy_all_fields = true); - - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Affine3f &transform, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Transform a point cloud and rotate its normals using an Eigen transform. - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z, normal_x, normal_y, normal_z) should be copied into the new - * transformed cloud - */ - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Transform &transform, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, indices.indices, cloud_out, transform, copy_all_fields)); - } - - - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Affine3f &transform, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Apply a rigid transform defined by a 4x4 matrix - * \param[in] cloud_in the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform a rigid transformation - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z) should be copied into the new transformed cloud - * \note Can be used with cloud_in equal to cloud_out - * \ingroup common - */ - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &transform, - bool copy_all_fields = true) - { - Eigen::Transform t (transform); - return (transformPointCloud (cloud_in, cloud_out, t, copy_all_fields)); - } - - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Matrix4f &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, cloud_out, transform, copy_all_fields)); - } - - /** \brief Apply a rigid transform defined by a 4x4 matrix - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform a rigid transformation - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z) should be copied into the new transformed cloud - * \ingroup common - */ - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &transform, - bool copy_all_fields = true) - { - Eigen::Transform t (transform); - return (transformPointCloud (cloud_in, indices, cloud_out, t, copy_all_fields)); - } - - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix4f &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Apply a rigid transform defined by a 4x4 matrix - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform a rigid transformation - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z) should be copied into the new transformed cloud - * \ingroup common - */ - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, indices.indices, cloud_out, transform, copy_all_fields)); - } - - template void - transformPointCloud (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix4f &transform, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Transform a point cloud and rotate its normals using an Eigen transform. - * \param[in] cloud_in the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z, normal_x, normal_y, normal_z) should be copied into the new - * transformed cloud - * \note Can be used with cloud_in equal to cloud_out - * \ingroup common - */ - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &transform, - bool copy_all_fields = true) - { - Eigen::Transform t (transform); - return (transformPointCloudWithNormals (cloud_in, cloud_out, t, copy_all_fields)); - } - - - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Matrix4f &transform, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, cloud_out, transform, copy_all_fields)); - } - - /** \brief Transform a point cloud and rotate its normals using an Eigen transform. - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z, normal_x, normal_y, normal_z) should be copied into the new - * transformed cloud - * \note Can be used with cloud_in equal to cloud_out - * \ingroup common - */ - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &transform, - bool copy_all_fields = true) - { - Eigen::Transform t (transform); - return (transformPointCloudWithNormals (cloud_in, indices, cloud_out, t, copy_all_fields)); - } - - - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const std::vector &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix4f &transform, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Transform a point cloud and rotate its normals using an Eigen transform. - * \param[in] cloud_in the input point cloud - * \param[in] indices the set of point indices to use from the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] transform an affine transformation (typically a rigid transformation) - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z, normal_x, normal_y, normal_z) should be copied into the new - * transformed cloud - * \note Can be used with cloud_in equal to cloud_out - * \ingroup common - */ - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &transform, - bool copy_all_fields = true) - { - Eigen::Transform t (transform); - return (transformPointCloudWithNormals (cloud_in, indices, cloud_out, t, copy_all_fields)); - } - - - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - const pcl::PointIndices &indices, - pcl::PointCloud &cloud_out, - const Eigen::Matrix4f &transform, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, indices, cloud_out, transform, copy_all_fields)); - } - - /** \brief Apply a rigid transform defined by a 3D offset and a quaternion - * \param[in] cloud_in the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] offset the translation component of the rigid transformation - * \param[in] rotation the rotation component of the rigid transformation - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z) should be copied into the new transformed cloud - * \ingroup common - */ - template inline void - transformPointCloud (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &offset, - const Eigen::Quaternion &rotation, - bool copy_all_fields = true); - - template inline void - transformPointCloud (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Vector3f &offset, - const Eigen::Quaternionf &rotation, - bool copy_all_fields = true) - { - return (transformPointCloud (cloud_in, cloud_out, offset, rotation, copy_all_fields)); - } - - /** \brief Transform a point cloud and rotate its normals using an Eigen transform. - * \param[in] cloud_in the input point cloud - * \param[out] cloud_out the resultant output point cloud - * \param[in] offset the translation component of the rigid transformation - * \param[in] rotation the rotation component of the rigid transformation - * \param[in] copy_all_fields flag that controls whether the contents of the fields - * (other than x, y, z, normal_x, normal_y, normal_z) should be copied into the new - * transformed cloud - * \ingroup common - */ - template inline void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Matrix &offset, - const Eigen::Quaternion &rotation, - bool copy_all_fields = true); - - template void - transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, - pcl::PointCloud &cloud_out, - const Eigen::Vector3f &offset, - const Eigen::Quaternionf &rotation, - bool copy_all_fields = true) - { - return (transformPointCloudWithNormals (cloud_in, cloud_out, offset, rotation, copy_all_fields)); - } - - /** \brief Transform a point with members x,y,z - * \param[in] point the point to transform - * \param[out] transform the transformation to apply - * \return the transformed point - * \ingroup common - */ - template inline PointT - transformPoint (const PointT &point, - const Eigen::Transform &transform); - - template inline PointT - transformPoint (const PointT &point, - const Eigen::Affine3f &transform) - { - return (transformPoint (point, transform)); - } - - /** \brief Transform a point with members x,y,z,normal_x,normal_y,normal_z - * \param[in] point the point to transform - * \param[out] transform the transformation to apply - * \return the transformed point - * \ingroup common - */ - template inline PointT - transformPointWithNormal (const PointT &point, - const Eigen::Transform &transform); - - template inline PointT - transformPointWithNormal (const PointT &point, - const Eigen::Affine3f &transform) - { - return (transformPointWithNormal (point, transform)); - } -} - -//#include - - -#if defined(__SSE2__) -# include -#endif - -#if defined(__AVX__) -# include -#endif - -namespace pcl { - -namespace detail { - -/** A helper struct to apply an SO3 or SE3 transform to a 3D point. - * Supports single and double precision transform matrices. */ -template struct Transformer { - const Eigen::Matrix& tf; - - /** Construct a transformer object. - * The transform matrix is captured by const reference. Make sure that it does not go out of scope before this - * object does. */ - Transformer(const Eigen::Matrix& transform) : tf(transform){}; - - /** Apply SO3 transform (top-left corner of the transform matrix). - * \param[in] src input 3D point (pointer to 3 floats) - * \param[out] tgt output 3D point (pointer to 4 floats), can be the same as input. The fourth element is set to 0. - */ - void so3(const float* src, float* tgt) const { - const Scalar p[3] = {src[0], src[1], src[2]}; // need this when src == tgt - tgt[0] = static_cast(tf(0, 0) * p[0] + tf(0, 1) * p[1] + tf(0, 2) * p[2]); - tgt[1] = static_cast(tf(1, 0) * p[0] + tf(1, 1) * p[1] + tf(1, 2) * p[2]); - tgt[2] = static_cast(tf(2, 0) * p[0] + tf(2, 1) * p[1] + tf(2, 2) * p[2]); - tgt[3] = 0; - } - - /** Apply SE3 transform. - * \param[in] src input 3D point (pointer to 3 floats) - * \param[out] tgt output 3D point (pointer to 4 floats), can be the same as input. The fourth element is set to 1. - */ - void se3(const float* src, float* tgt) const { - const Scalar p[3] = {src[0], src[1], src[2]}; // need this when src == tgt - tgt[0] = static_cast(tf(0, 0) * p[0] + tf(0, 1) * p[1] + tf(0, 2) * p[2] + tf(0, 3)); - tgt[1] = static_cast(tf(1, 0) * p[0] + tf(1, 1) * p[1] + tf(1, 2) * p[2] + tf(1, 3)); - tgt[2] = static_cast(tf(2, 0) * p[0] + tf(2, 1) * p[1] + tf(2, 2) * p[2] + tf(2, 3)); - tgt[3] = 1; - } -}; - -#if defined(__SSE2__) - -/** Optimized version for single-precision transforms using SSE2 intrinsics. */ -template <> struct Transformer { - /// Columns of the transform matrix stored in XMM registers. - __m128 c[4]; - - Transformer(const Eigen::Matrix4f& tf) { - for (size_t i = 0; i < 4; ++i) c[i] = _mm_load_ps(tf.col(i).data()); - } - - void so3(const float* src, float* tgt) const { - __m128 p0 = _mm_mul_ps(_mm_load_ps1(&src[0]), c[0]); - __m128 p1 = _mm_mul_ps(_mm_load_ps1(&src[1]), c[1]); - __m128 p2 = _mm_mul_ps(_mm_load_ps1(&src[2]), c[2]); - _mm_store_ps(tgt, _mm_add_ps(p0, _mm_add_ps(p1, p2))); - } - - void se3(const float* src, float* tgt) const { - __m128 p0 = _mm_mul_ps(_mm_load_ps1(&src[0]), c[0]); - __m128 p1 = _mm_mul_ps(_mm_load_ps1(&src[1]), c[1]); - __m128 p2 = _mm_mul_ps(_mm_load_ps1(&src[2]), c[2]); - _mm_store_ps(tgt, _mm_add_ps(p0, _mm_add_ps(p1, _mm_add_ps(p2, c[3])))); - } -}; - -# if !defined(__AVX__) - -/** Optimized version for double-precision transform using SSE2 intrinsics. */ -template <> struct Transformer { - /// Columns of the transform matrix stored in XMM registers. - __m128d c[4][2]; - - Transformer(const Eigen::Matrix4d& tf) { - for (size_t i = 0; i < 4; ++i) { - c[i][0] = _mm_load_pd(tf.col(i).data() + 0); - c[i][1] = _mm_load_pd(tf.col(i).data() + 2); - } - } - - void so3(const float* src, float* tgt) const { - __m128d xx = _mm_cvtps_pd(_mm_load_ps1(&src[0])); - __m128d p0 = _mm_mul_pd(xx, c[0][0]); - __m128d p1 = _mm_mul_pd(xx, c[0][1]); - - for (size_t i = 1; i < 3; ++i) { - __m128d vv = _mm_cvtps_pd(_mm_load_ps1(&src[i])); - p0 = _mm_add_pd(_mm_mul_pd(vv, c[i][0]), p0); - p1 = _mm_add_pd(_mm_mul_pd(vv, c[i][1]), p1); - } - - _mm_store_ps(tgt, _mm_movelh_ps(_mm_cvtpd_ps(p0), _mm_cvtpd_ps(p1))); - } - - void se3(const float* src, float* tgt) const { - __m128d p0 = c[3][0]; - __m128d p1 = c[3][1]; - - for (size_t i = 0; i < 3; ++i) { - __m128d vv = _mm_cvtps_pd(_mm_load_ps1(&src[i])); - p0 = _mm_add_pd(_mm_mul_pd(vv, c[i][0]), p0); - p1 = _mm_add_pd(_mm_mul_pd(vv, c[i][1]), p1); - } - - _mm_store_ps(tgt, _mm_movelh_ps(_mm_cvtpd_ps(p0), _mm_cvtpd_ps(p1))); - } -}; - -# else - -/** Optimized version for double-precision transform using AVX intrinsics. */ -template <> struct Transformer { - __m256d c[4]; - - Transformer(const Eigen::Matrix4d& tf) { - for (size_t i = 0; i < 4; ++i) c[i] = _mm256_load_pd(tf.col(i).data()); - } - - void so3(const float* src, float* tgt) const { - __m256d p0 = _mm256_mul_pd(_mm256_cvtps_pd(_mm_load_ps1(&src[0])), c[0]); - __m256d p1 = _mm256_mul_pd(_mm256_cvtps_pd(_mm_load_ps1(&src[1])), c[1]); - __m256d p2 = _mm256_mul_pd(_mm256_cvtps_pd(_mm_load_ps1(&src[2])), c[2]); - _mm_store_ps(tgt, _mm256_cvtpd_ps(_mm256_add_pd(p0, _mm256_add_pd(p1, p2)))); - } - - void se3(const float* src, float* tgt) const { - __m256d p0 = _mm256_mul_pd(_mm256_cvtps_pd(_mm_load_ps1(&src[0])), c[0]); - __m256d p1 = _mm256_mul_pd(_mm256_cvtps_pd(_mm_load_ps1(&src[1])), c[1]); - __m256d p2 = _mm256_mul_pd(_mm256_cvtps_pd(_mm_load_ps1(&src[2])), c[2]); - _mm_store_ps(tgt, _mm256_cvtpd_ps(_mm256_add_pd(p0, _mm256_add_pd(p1, _mm256_add_pd(p2, c[3]))))); - } -}; - -# endif -#endif - -} // namespace detail -} // namespace pcl - -/////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::transformPointCloud(const pcl::PointCloud& cloud_in, pcl::PointCloud& cloud_out, - const Eigen::Transform& transform, bool copy_all_fields) { - if (&cloud_in != &cloud_out) { - cloud_out.header = cloud_in.header; - cloud_out.is_dense = cloud_in.is_dense; - cloud_out.width = cloud_in.width; - cloud_out.height = cloud_in.height; - cloud_out.points.reserve(cloud_in.points.size()); - if (copy_all_fields) - cloud_out.points.assign(cloud_in.points.begin(), cloud_in.points.end()); - else - cloud_out.points.resize(cloud_in.points.size()); - //cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_; - //cloud_out.sensor_origin_ = cloud_in.sensor_origin_; - } - - pcl::detail::Transformer tf(transform.matrix()); - if (cloud_in.is_dense) { - // If the dataset is dense, simply transform it! - for (size_t i = 0; i < cloud_out.points.size(); ++i) - tf.se3(cloud_in.points[i].data, cloud_out.points[i].data); - } else { - // Dataset might contain NaNs and Infs, so check for them first, - // otherwise we get errors during the multiplication (?) - for (size_t i = 0; i < cloud_out.points.size(); ++i) { - if (!std::isfinite(cloud_in.points[i].x) || !std::isfinite(cloud_in.points[i].y) || - !std::isfinite(cloud_in.points[i].z)) - continue; - tf.se3(cloud_in.points[i].data, cloud_out.points[i].data); - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::transformPointCloud(const pcl::PointCloud& cloud_in, const std::vector& indices, - pcl::PointCloud& cloud_out, const Eigen::Transform& transform, - bool copy_all_fields) { - size_t npts = indices.size(); - // In order to transform the data, we need to remove NaNs - cloud_out.is_dense = cloud_in.is_dense; - cloud_out.header = cloud_in.header; - cloud_out.width = static_cast(npts); - cloud_out.height = 1; - cloud_out.points.resize(npts); - cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_; - cloud_out.sensor_origin_ = cloud_in.sensor_origin_; - - pcl::detail::Transformer tf(transform.matrix()); - if (cloud_in.is_dense) { - // If the dataset is dense, simply transform it! - for (size_t i = 0; i < npts; ++i) { - // Copy fields first, then transform xyz data - if (copy_all_fields) cloud_out.points[i] = cloud_in.points[indices[i]]; - tf.se3(cloud_in[indices[i]].data, cloud_out[i].data); - } - } else { - // Dataset might contain NaNs and Infs, so check for them first, - // otherwise we get errors during the multiplication (?) - for (size_t i = 0; i < npts; ++i) { - if (copy_all_fields) cloud_out.points[i] = cloud_in.points[indices[i]]; - if (!std::isfinite(cloud_in.points[indices[i]].x) || !std::isfinite(cloud_in.points[indices[i]].y) || - !std::isfinite(cloud_in.points[indices[i]].z)) - continue; - tf.se3(cloud_in[indices[i]].data, cloud_out[i].data); - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::transformPointCloudWithNormals(const pcl::PointCloud& cloud_in, pcl::PointCloud& cloud_out, - const Eigen::Transform& transform, bool copy_all_fields) { - if (&cloud_in != &cloud_out) { - // Note: could be replaced by cloud_out = cloud_in - cloud_out.header = cloud_in.header; - cloud_out.width = cloud_in.width; - cloud_out.height = cloud_in.height; - cloud_out.is_dense = cloud_in.is_dense; - cloud_out.points.reserve(cloud_out.points.size()); - if (copy_all_fields) - cloud_out.points.assign(cloud_in.points.begin(), cloud_in.points.end()); - else - cloud_out.points.resize(cloud_in.points.size()); - cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_; - cloud_out.sensor_origin_ = cloud_in.sensor_origin_; - } - - pcl::detail::Transformer tf(transform.matrix()); - // If the data is dense, we don't need to check for NaN - if (cloud_in.is_dense) { - for (size_t i = 0; i < cloud_out.points.size(); ++i) { - tf.se3(cloud_in[i].data, cloud_out[i].data); - tf.so3(cloud_in[i].data_n, cloud_out[i].data_n); - } - } - // Dataset might contain NaNs and Infs, so check for them first. - else { - for (size_t i = 0; i < cloud_out.points.size(); ++i) { - if (!std::isfinite(cloud_in.points[i].x) || !std::isfinite(cloud_in.points[i].y) || - !std::isfinite(cloud_in.points[i].z)) - continue; - tf.se3(cloud_in[i].data, cloud_out[i].data); - tf.so3(cloud_in[i].data_n, cloud_out[i].data_n); - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -void pcl::transformPointCloudWithNormals(const pcl::PointCloud& cloud_in, const std::vector& indices, - pcl::PointCloud& cloud_out, const Eigen::Transform& transform, - bool copy_all_fields) { - size_t npts = indices.size(); - // In order to transform the data, we need to remove NaNs - cloud_out.is_dense = cloud_in.is_dense; - cloud_out.header = cloud_in.header; - cloud_out.width = static_cast(npts); - cloud_out.height = 1; - cloud_out.points.resize(npts); - cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_; - cloud_out.sensor_origin_ = cloud_in.sensor_origin_; - - pcl::detail::Transformer tf(transform.matrix()); - // If the data is dense, we don't need to check for NaN - if (cloud_in.is_dense) { - for (size_t i = 0; i < cloud_out.points.size(); ++i) { - // Copy fields first, then transform - if (copy_all_fields) cloud_out.points[i] = cloud_in.points[indices[i]]; - tf.se3(cloud_in[indices[i]].data, cloud_out[i].data); - tf.so3(cloud_in[indices[i]].data_n, cloud_out[i].data_n); - } - } - // Dataset might contain NaNs and Infs, so check for them first. - else { - for (size_t i = 0; i < cloud_out.points.size(); ++i) { - // Copy fields first, then transform - if (copy_all_fields) cloud_out.points[i] = cloud_in.points[indices[i]]; - - if (!std::isfinite(cloud_in.points[indices[i]].x) || !std::isfinite(cloud_in.points[indices[i]].y) || - !std::isfinite(cloud_in.points[indices[i]].z)) - continue; - - tf.se3(cloud_in[indices[i]].data, cloud_out[i].data); - tf.so3(cloud_in[indices[i]].data_n, cloud_out[i].data_n); - } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::transformPointCloud(const pcl::PointCloud& cloud_in, pcl::PointCloud& cloud_out, - const Eigen::Matrix& offset, const Eigen::Quaternion& rotation, bool copy_all_fields) { - Eigen::Translation translation(offset); - // Assemble an Eigen Transform - Eigen::Transform t(translation * rotation); - transformPointCloud(cloud_in, cloud_out, t, copy_all_fields); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -inline void pcl::transformPointCloudWithNormals(const pcl::PointCloud& cloud_in, - pcl::PointCloud& cloud_out, const Eigen::Matrix& offset, - const Eigen::Quaternion& rotation, bool copy_all_fields) { - Eigen::Translation translation(offset); - // Assemble an Eigen Transform - Eigen::Transform t(translation * rotation); - transformPointCloudWithNormals(cloud_in, cloud_out, t, copy_all_fields); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -inline PointT pcl::transformPoint(const PointT& point, const Eigen::Transform& transform) { - PointT ret = point; - pcl::detail::Transformer tf(transform.matrix()); - tf.se3(point.data, ret.data); - return (ret); -} - -/////////////////////////////////////////////////////////////////////////////////////////// -template -inline PointT pcl::transformPointWithNormal( - const PointT& point, const Eigen::Transform& transform) { - PointT ret = point; - pcl::detail::Transformer tf(transform.matrix()); - tf.se3(point.data, ret.data); - tf.so3(point.data_n, ret.data_n); - return (ret); -} diff --git a/plugins/probe/CMakeLists.txt b/plugins/probe/CMakeLists.txt index 977511e6af..f448ac21b9 100644 --- a/plugins/probe/CMakeLists.txt +++ b/plugins/probe/CMakeLists.txt @@ -14,18 +14,15 @@ megamol_plugin(probe libigl asmjit blend2d - qhull PUBLIC Eigen nanoflann) if (probe_PLUGIN_ENABLED) - file(GLOB_RECURSE third RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "3rd/*") file(GLOB_RECURSE ospray_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "probe_ospray/src/*.cpp") file(GLOB_RECURSE ospray_headers RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "probe_ospray/src/*.h") file(GLOB_RECURSE ospray_public_headers RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "probe_ospray/include/*.h") target_sources(probe PRIVATE ${third}) - target_include_directories(probe PUBLIC "3rd") find_package(CGAL 5.3 CONFIG REQUIRED) target_link_libraries(probe PUBLIC CGAL::CGAL) diff --git a/plugins/probe/include/probe/CallKDTree.h b/plugins/probe/include/probe/CallKDTree.h index 508a5b83a9..42f8428d83 100644 --- a/plugins/probe/include/probe/CallKDTree.h +++ b/plugins/probe/include/probe/CallKDTree.h @@ -5,16 +5,62 @@ */ #pragma once -#include "kdtree.h" #include "mmcore/CallGeneric.h" +#include namespace megamol { namespace probe { + +template +struct kd_adaptor { + typedef typename Derived::value_type::value_type coord_t; + + const Derived& obj; //!< A const ref to the data set origin + + /// The constructor that sets the data set source + kd_adaptor(const Derived& obj_) : obj(obj_) {} + + /// CRTP helper method + inline const Derived& derived() const { + return obj; + } + + // Must return the number of data points + inline size_t kdtree_get_point_count() const { + return derived().size(); + } + + // Returns the dim'th component of the idx'th point in the class: + // Since this is inlined and the "dim" argument is typically an immediate value, the + // "if/else's" are actually solved at compile time. + inline coord_t kdtree_get_pt(const size_t idx, const size_t dim) const { + if (dim == 0) + return derived()[idx][0]; + else if (dim == 1) + return derived()[idx][1]; + else + return derived()[idx][2]; + } + + // Optional bounding-box computation: return false to default to a standard bbox computation loop. + // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo + // it again. Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) + template + bool kdtree_get_bbox(BBOX& /*bb*/) const { + return false; + } + +}; // end of PointCloudAdaptor + +typedef kd_adaptor>> data2KD; +typedef nanoflann::KDTreeSingleIndexAdaptor, data2KD, 3 /* dim */> +my_kd_tree_t; + class CallKDTree - : public core::GenericVersionedCall>, core::Spatial3DMetaData> { -public: + : public core::GenericVersionedCall, core::Spatial3DMetaData> { + public: CallKDTree() - : core::GenericVersionedCall>, core::Spatial3DMetaData>() {} + : core::GenericVersionedCall, core::Spatial3DMetaData>() {} ~CallKDTree(){}; static const char* ClassName(void) { diff --git a/plugins/probe/src/ConstructHull.h b/plugins/probe/src/ConstructHull.h index 7d5a0dcc00..a48fddc335 100644 --- a/plugins/probe/src/ConstructHull.h +++ b/plugins/probe/src/ConstructHull.h @@ -12,6 +12,7 @@ #include "mmcore/Module.h" #include "mmcore/param/ParamSlot.h" #include "nanoflann.hpp" +#include "probe/CallKDTree.h" #include #include #include @@ -25,47 +26,6 @@ typedef Tr::Geom_traits GT; typedef GT::Point_3 Point; typedef CGAL::Surface_mesh Surface_mesh; -template -struct kd_adaptor { - typedef typename Derived::value_type::value_type coord_t; - - const Derived& obj; //!< A const ref to the data set origin - - /// The constructor that sets the data set source - kd_adaptor(const Derived& obj_) : obj(obj_) {} - - /// CRTP helper method - inline const Derived& derived() const { - return obj; - } - - // Must return the number of data points - inline size_t kdtree_get_point_count() const { - return derived().size(); - } - - // Returns the dim'th component of the idx'th point in the class: - // Since this is inlined and the "dim" argument is typically an immediate value, the - // "if/else's" are actually solved at compile time. - inline coord_t kdtree_get_pt(const size_t idx, const size_t dim) const { - if (dim == 0) - return derived()[idx][0]; - else if (dim == 1) - return derived()[idx][1]; - else - return derived()[idx][2]; - } - - // Optional bounding-box computation: return false to default to a standard bbox computation loop. - // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo - // it again. Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) - template - bool kdtree_get_bbox(BBOX& /*bb*/) const { - return false; - } - -}; // end of PointCloudAdaptor - class ConstructHull : public core::Module { public: @@ -193,10 +153,6 @@ class ConstructHull : public core::Module { // store bounding box megamol::core::BoundingBoxes_2 _bbox; - typedef kd_adaptor>> data2KD; - typedef nanoflann::KDTreeSingleIndexAdaptor, data2KD, 3 /* dim */ - > - my_kd_tree_t; std::vector> _kd_indices; std::vector> _data2kd; diff --git a/plugins/probe/src/ConstructKDTree.cpp b/plugins/probe/src/ConstructKDTree.cpp index d41be72455..fdb11e088f 100644 --- a/plugins/probe/src/ConstructKDTree.cpp +++ b/plugins/probe/src/ConstructKDTree.cpp @@ -10,7 +10,6 @@ #include "mmcore/param/EnumParam.h" #include "mmcore/param/FlexEnumParam.h" #include "mmcore/param/FloatParam.h" -#include "normal_3d_omp.h" #include "probe/CallKDTree.h" #include #include @@ -87,7 +86,7 @@ bool ConstructKDTree::createPointCloud(std::vector& vars) { const auto count = cd->getData(vars[0])->size(); - _cloud.points.resize(count); + _cloud.resize(count); for (auto var : vars) { if (this->_formatSlot.Param()->Value() == 0) { @@ -105,9 +104,9 @@ bool ConstructKDTree::createPointCloud(std::vector& vars) { *xminmax.first, *yminmax.first, *zminmax.second, *xminmax.second, *yminmax.second, *zminmax.first); for (unsigned long long i = 0; i < count; i++) { - _cloud.points[i].x = x[i]; - _cloud.points[i].y = y[i]; - _cloud.points[i].z = z[i]; + _cloud[i][0] = x[i]; + _cloud[i][1] = y[i]; + _cloud[i][2] = z[i]; } } else { @@ -123,18 +122,18 @@ bool ConstructKDTree::createPointCloud(std::vector& vars) { float zmin = std::numeric_limits::max(); float zmax = std::numeric_limits::min(); - _cloud.points.resize(count / coarse_factor); + _cloud.resize(count / coarse_factor); for (unsigned long long i = 0; i < count / (3 * coarse_factor); i++) { - _cloud.points[i].x = xyz[3 * (i * coarse_factor) + 0]; - _cloud.points[i].y = xyz[3 * (i * coarse_factor) + 1]; - _cloud.points[i].z = xyz[3 * (i * coarse_factor) + 2]; - - xmin = std::min(xmin, _cloud.points[i].x); - xmax = std::max(xmax, _cloud.points[i].x); - ymin = std::min(ymin, _cloud.points[i].y); - ymax = std::max(ymax, _cloud.points[i].y); - zmin = std::min(zmin, _cloud.points[i].z); - zmax = std::max(zmax, _cloud.points[i].z); + _cloud[i][0] = xyz[3 * (i * coarse_factor) + 0]; + _cloud[i][1] = xyz[3 * (i * coarse_factor) + 1]; + _cloud[i][2] = xyz[3 * (i * coarse_factor) + 2]; + + xmin = std::min(xmin, _cloud[i][0]); + xmax = std::max(xmax, _cloud[i][0]); + ymin = std::min(ymin, _cloud[i][1]); + ymax = std::max(ymax, _cloud[i][1]); + zmin = std::min(zmin, _cloud[i][2]); + zmax = std::max(zmax, _cloud[i][2]); } _bbox.SetBoundingBox(xmin, ymin, zmax, xmax, ymax, zmin); } @@ -217,9 +216,10 @@ bool ConstructKDTree::getData(core::Call& call) { ct->setMetaData(meta_data); // Extract the kd tree for easy sampling of the data - _inputCloud = std::make_shared>(_cloud); - this->_full_data_tree = std::make_shared>(); - this->_full_data_tree->setInputCloud(_inputCloud, nullptr); + + this->_full_data_tree = std::make_shared( + 3 /*dim*/, _cloud, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + this->_full_data_tree->buildIndex(); this->_version++; _old_datahash = cd->getDataHash(); } diff --git a/plugins/probe/src/ConstructKDTree.h b/plugins/probe/src/ConstructKDTree.h index 810d937a9d..df7b032c81 100644 --- a/plugins/probe/src/ConstructKDTree.h +++ b/plugins/probe/src/ConstructKDTree.h @@ -5,13 +5,13 @@ */ #pragma once -#include "concave_hull.h" #include "mesh/MeshCalls.h" #include "mmcore/CalleeSlot.h" #include "mmcore/CallerSlot.h" #include "mmcore/Module.h" #include "mmcore/param/ParamSlot.h" -#include "poisson.h" +#include "ConstructHull.h" +#include namespace megamol { namespace probe { @@ -72,10 +72,8 @@ class ConstructKDTree : public core::Module { bool toggleFormat(core::param::ParamSlot& p); // PCL stuff - pcl::PointCloud::ConstPtr _inputCloud; - pcl::PointCloud _cloud; - std::shared_ptr> _resultNormalCloud; - std::shared_ptr> _full_data_tree; + std::vector> _cloud; + std::shared_ptr _full_data_tree; size_t _old_datahash = 0; uint32_t _version = 0; diff --git a/plugins/probe/src/ElementColoring.cpp b/plugins/probe/src/ElementColoring.cpp index 4efbc1014f..86739e6a8a 100644 --- a/plugins/probe/src/ElementColoring.cpp +++ b/plugins/probe/src/ElementColoring.cpp @@ -11,6 +11,7 @@ #include "mmcore/param/EnumParam.h" #include "probe/CallKDTree.h" #include "probe/ProbeCalls.h" +#include namespace megamol { diff --git a/plugins/probe/src/ExtractCenterline.cpp b/plugins/probe/src/ExtractCenterline.cpp index f1014a7779..ffc8eb37a4 100644 --- a/plugins/probe/src/ExtractCenterline.cpp +++ b/plugins/probe/src/ExtractCenterline.cpp @@ -11,7 +11,6 @@ #include "mmcore/param/FlexEnumParam.h" #include "mmcore/param/FloatParam.h" #include "mmcore/utility/log/Log.h" -#include "normal_3d_omp.h" #include "probe/CallKDTree.h" #include #include diff --git a/plugins/probe/src/ExtractCenterline.h b/plugins/probe/src/ExtractCenterline.h index 7f3e219d5e..f54b2b9c8a 100644 --- a/plugins/probe/src/ExtractCenterline.h +++ b/plugins/probe/src/ExtractCenterline.h @@ -5,13 +5,11 @@ */ #pragma once -#include "concave_hull.h" #include "mesh/MeshCalls.h" #include "mmcore/CalleeSlot.h" #include "mmcore/CallerSlot.h" #include "mmcore/Module.h" #include "mmcore/param/ParamSlot.h" -#include "poisson.h" #include namespace megamol { diff --git a/plugins/probe/src/ExtractMesh.cpp b/plugins/probe/src/ExtractMesh.cpp deleted file mode 100644 index c29b069b1a..0000000000 --- a/plugins/probe/src/ExtractMesh.cpp +++ /dev/null @@ -1,925 +0,0 @@ -/* - * ExtractMesh.cpp - * Copyright (C) 2019 by MegaMol Team - * Alle Rechte vorbehalten. - */ - -#include "ExtractMesh.h" -#include "geometry_calls/MultiParticleDataCall.h" -#include "mmadios/CallADIOSData.h" -#include "mmcore/param/EnumParam.h" -#include "mmcore/param/FlexEnumParam.h" -#include "mmcore/param/FloatParam.h" -#include "normal_3d_omp.h" -#include "probe/CallKDTree.h" -#include - - -namespace megamol { -namespace probe { - - -ExtractMesh::ExtractMesh() - : Module() - , m_version(0) - , _getDataCall("getData", "") - , _deployMeshCall("deployMesh", "") - , _deployLineCall("deployCenterline", "") - , _deploySpheresCall("deploySpheres", "") - , _deployFullDataTree("deployFullDataTree", "") - , _algorithmSlot("algorithm", "") - , _xSlot("x", "") - , _ySlot("y", "") - , _zSlot("z", "") - , _xyzSlot("xyz", "") - , _formatSlot("format", "") - , _alphaSlot("alpha", "") { - - this->_alphaSlot << new core::param::FloatParam(1.0f); - this->_alphaSlot.SetUpdateCallback(&ExtractMesh::alphaChanged); - this->MakeSlotAvailable(&this->_alphaSlot); - - core::param::EnumParam* ep = new core::param::EnumParam(0); - ep->SetTypePair(0, "alpha_shape"); - this->_algorithmSlot << ep; - this->MakeSlotAvailable(&this->_algorithmSlot); - - core::param::EnumParam* fp = new core::param::EnumParam(0); - fp->SetTypePair(0, "separated"); - fp->SetTypePair(1, "interleaved"); - this->_formatSlot << fp; - this->_formatSlot.SetUpdateCallback(&ExtractMesh::toggleFormat); - this->MakeSlotAvailable(&this->_formatSlot); - - core::param::FlexEnumParam* xEp = new core::param::FlexEnumParam("undef"); - this->_xSlot << xEp; - this->MakeSlotAvailable(&this->_xSlot); - - core::param::FlexEnumParam* yEp = new core::param::FlexEnumParam("undef"); - this->_ySlot << yEp; - this->MakeSlotAvailable(&this->_ySlot); - - core::param::FlexEnumParam* zEp = new core::param::FlexEnumParam("undef"); - this->_zSlot << zEp; - this->MakeSlotAvailable(&this->_zSlot); - - core::param::FlexEnumParam* xyzEp = new core::param::FlexEnumParam("undef"); - this->_xyzSlot << xyzEp; - xyzEp->SetGUIVisible(false); - this->MakeSlotAvailable(&this->_xyzSlot); - - this->_deployMeshCall.SetCallback( - mesh::CallMesh::ClassName(), mesh::CallMesh::FunctionName(0), &ExtractMesh::getData); - this->_deployMeshCall.SetCallback( - mesh::CallMesh::ClassName(), mesh::CallMesh::FunctionName(1), &ExtractMesh::getMetaData); - this->MakeSlotAvailable(&this->_deployMeshCall); - - this->_deployLineCall.SetCallback( - mesh::CallMesh::ClassName(), mesh::CallMesh::FunctionName(0), &ExtractMesh::getCenterlineData); - this->_deployLineCall.SetCallback( - mesh::CallMesh::ClassName(), mesh::CallMesh::FunctionName(1), &ExtractMesh::getMetaData); - this->MakeSlotAvailable(&this->_deployLineCall); - - this->_deployFullDataTree.SetCallback( - CallKDTree::ClassName(), CallKDTree::FunctionName(0), &ExtractMesh::getKDData); - this->_deployFullDataTree.SetCallback( - CallKDTree::ClassName(), CallKDTree::FunctionName(1), &ExtractMesh::getKDMetaData); - this->MakeSlotAvailable(&this->_deployFullDataTree); - - this->_getDataCall.SetCompatibleCall(); - this->MakeSlotAvailable(&this->_getDataCall); - - this->_deploySpheresCall.SetCallback(geocalls::MultiParticleDataCall::ClassName(), - geocalls::MultiParticleDataCall::FunctionName(0), &ExtractMesh::getParticleData); - this->_deploySpheresCall.SetCallback(geocalls::MultiParticleDataCall::ClassName(), - geocalls::MultiParticleDataCall::FunctionName(1), &ExtractMesh::getParticleMetaData); - this->MakeSlotAvailable(&this->_deploySpheresCall); -} - -ExtractMesh::~ExtractMesh() { - this->Release(); -} - -bool ExtractMesh::create() { - return true; -} - -void ExtractMesh::release() {} - -bool ExtractMesh::InterfaceIsDirty() { - return (this->_alphaSlot.IsDirty() || this->_formatSlot.IsDirty()); -} - -bool ExtractMesh::flipNormalsWithCenterLine(pcl::PointCloud& point_cloud) { - - for (uint32_t i = 0; i < _cl_indices_per_slice.size(); i++) { - for (auto& center_idx : _cl_indices_per_slice[i]) { - - auto cl_x = _centerline[i][0]; - auto cl_y = _centerline[i][1]; - auto cl_z = _centerline[i][2]; - - cl_x -= point_cloud.points[center_idx].x; - cl_y -= point_cloud.points[center_idx].y; - cl_z -= point_cloud.points[center_idx].z; - - // Projection of the normal on the center line point - const float cos_theta = - (cl_x * point_cloud.points[center_idx].normal_x + cl_y * point_cloud.points[center_idx].normal_y + - cl_z * point_cloud.points[center_idx].normal_z); - - // Flip the plane normal away from center line point - if (cos_theta > 0) { - point_cloud.points[center_idx].normal_x *= -1; - point_cloud.points[center_idx].normal_y *= -1; - point_cloud.points[center_idx].normal_z *= -1; - } - } - } - - return true; -} - -bool ExtractMesh::flipNormalsWithCenterLine_distanceBased(pcl::PointCloud& point_cloud) { - - for (uint32_t i = 0; i < point_cloud.points.size(); i++) { - - std::vector distances(_centerline.size()); - for (uint32_t j = 0; j < _centerline.size(); j++) { - // std::array diffvec = { - // vertex_accessor[vertex_step * i + 0] - centerline_accessor[centerline_step * j + 0], - // vertex_accessor[vertex_step * i + 1] - centerline_accessor[centerline_step * j + 1], - // vertex_accessor[vertex_step * i + 2] - centerline_accessor[centerline_step * j + 2]}; - // distances[j] = std::sqrt(diffvec[0] * diffvec[0] + diffvec[1] * diffvec[1] + diffvec[2] * - // diffvec[2]); - std::array diff; - diff[0] = point_cloud.points[i].x - _centerline[j][0]; - diff[1] = point_cloud.points[i].y - _centerline[j][1]; - diff[2] = point_cloud.points[i].z - _centerline[j][2]; - distances[j] = std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]); - } - - auto min_iter = std::min_element(distances.begin(), distances.end()); - auto min_index = std::distance(distances.begin(), min_iter); - - auto cl_x = _centerline[min_index][0]; - auto cl_y = _centerline[min_index][1]; - auto cl_z = _centerline[min_index][2]; - - cl_x -= point_cloud.points[i].x; - cl_y -= point_cloud.points[i].y; - cl_z -= point_cloud.points[i].z; - - // Projection of the normal on the center line point - const float cos_theta = (cl_x * point_cloud.points[i].normal_x + cl_y * point_cloud.points[i].normal_y + - cl_z * point_cloud.points[i].normal_z); - - // Flip the plane normal away from center line point - if (cos_theta > 0) { - point_cloud.points[i].normal_x *= -1; - point_cloud.points[i].normal_y *= -1; - point_cloud.points[i].normal_z *= -1; - } - } - - return true; -} - -bool ExtractMesh::extractCenterLine(pcl::PointCloud& point_cloud) { - - std::array whd = {this->_bbox.ObjectSpaceBBox().Width(), this->_bbox.ObjectSpaceBBox().Height(), - this->_bbox.ObjectSpaceBBox().Depth()}; - const auto longest_edge_index = std::distance(whd.begin(), std::max_element(whd.begin(), whd.end())); - - const uint32_t num_steps = 20; - const auto step_size = whd[longest_edge_index] / (num_steps + 2); // without begin and end - const auto step_epsilon = step_size / 2; - float offset = 0.0f; - if (longest_edge_index == 0) { - offset = std::min(this->_bbox.ObjectSpaceBBox().GetLeft(), this->_bbox.ObjectSpaceBBox().GetRight()); - } else if (longest_edge_index == 1) { - offset = std::min(this->_bbox.ObjectSpaceBBox().GetBottom(), this->_bbox.ObjectSpaceBBox().GetTop()); - } else if (longest_edge_index == 2) { - offset = std::min(this->_bbox.ObjectSpaceBBox().GetFront(), this->_bbox.ObjectSpaceBBox().GetBack()); - } - _cl_indices_per_slice.clear(); - _centerline.clear(); - _centerline.resize(num_steps); - _cl_indices_per_slice.resize(num_steps); - - - for (uint32_t i = 0; i < _centerline.size(); i++) { - const auto slice = offset + (i + 1) * step_size; - const auto slice_min = slice - step_epsilon; - const auto slice_max = slice + step_epsilon; - float slice_dim1_mean = 0.0f; - float slice_dim2_mean = 0.0f; - for (uint32_t n = 0; n < point_cloud.points.size(); n++) { - if (longest_edge_index == 0) { - if (point_cloud.points[n].x >= slice_min && point_cloud.points[n].x < slice_max) { - _cl_indices_per_slice[i].emplace_back(n); - slice_dim1_mean += point_cloud.points[n].y; - slice_dim2_mean += point_cloud.points[n].z; - // std::array tmp_slice_point = {point_cloud.points[n].y, point_cloud.points[n].z}; - // slice_vertices.emplace_back(tmp_slice_point); - } - } else if (longest_edge_index == 1) { - if (point_cloud.points[n].y >= slice_min && point_cloud.points[n].y < slice_max) { - _cl_indices_per_slice[i].emplace_back(n); - slice_dim1_mean += point_cloud.points[n].x; - slice_dim2_mean += point_cloud.points[n].z; - } - } else if (longest_edge_index == 2) { - if (point_cloud.points[n].z >= slice_min && point_cloud.points[n].z < slice_max) { - _cl_indices_per_slice[i].emplace_back(n); - slice_dim1_mean += point_cloud.points[n].x; - slice_dim2_mean += point_cloud.points[n].y; - } - } - } - slice_dim1_mean /= _cl_indices_per_slice[i].size(); - slice_dim2_mean /= _cl_indices_per_slice[i].size(); - if (longest_edge_index == 0) { - _centerline[i] = {slice, slice_dim1_mean, slice_dim2_mean, 1.0f}; - } else if (longest_edge_index == 1) { - _centerline[i] = {slice_dim1_mean, slice, slice_dim2_mean, 1.0f}; - } else if (longest_edge_index == 2) { - _centerline[i] = {slice_dim1_mean, slice_dim2_mean, slice, 1.0f}; - } - } - - return true; -} - -void ExtractMesh::applyMeshCorrections() { - - for (auto& point : _poissonCloud.points) { - - std::vector k_indices; - std::vector k_distances; - - pcl::PointXYZ p; - p.x = point.x; - p.y = point.y; - p.z = point.z; - - auto neighbors = this->_alpha_hull_tree->nearestKSearch(p, 1, k_indices, k_distances); - - std::array diffvec; - float distance = 0.0f; - if (neighbors > 0) { - diffvec[0] = _alphaHullCloud->points[k_indices[0]].x - point.x; - diffvec[1] = _alphaHullCloud->points[k_indices[0]].y - point.y; - diffvec[2] = _alphaHullCloud->points[k_indices[0]].z - point.z; - // distance = std::sqrt(diffvec[0] * diffvec[0] + diffvec[1] * diffvec[1] + diffvec[2] * diffvec[2]); - - // point.x -= _resultNormalCloud->points[k_indices[0]].normal_x * distance; - // point.y -= _resultNormalCloud->points[k_indices[0]].normal_y * distance; - // point.z -= _resultNormalCloud->points[k_indices[0]].normal_z * distance; - - // point.x += diffvec[0]; - // point.y += diffvec[1]; - // point.z += diffvec[2]; - - // move along normal - float d = std::sqrt(diffvec[0] * _resultNormalCloud->points[k_indices[0]].normal_x + - diffvec[1] * _resultNormalCloud->points[k_indices[0]].normal_y + - diffvec[2] * _resultNormalCloud->points[k_indices[0]].normal_z); - - point.x -= d * _resultNormalCloud->points[k_indices[0]].normal_x; - point.y -= d * _resultNormalCloud->points[k_indices[0]].normal_y; - point.z -= d * _resultNormalCloud->points[k_indices[0]].normal_z; - } - } -} - - -void ExtractMesh::calculateAlphaShape() { - - // Calculate the alpha hull of the initial point cloud - pcl::ConcaveHull hull; - hull.setAlpha(this->_alphaSlot.Param()->Value()); - hull.setDimension(3); - _inputCloud = std::make_shared>(_cloud); - hull.setInputCloud(_inputCloud); - // hull.setDoFiltering(true); - pcl::PointCloud resultCloud; - hull.reconstruct(resultCloud, _polygons); - _alphaHullCloud = std::make_shared>(resultCloud); - - // Extract the kd tree for easy sampling of the data - this->_full_data_tree = std::make_shared>(); - this->_full_data_tree->setInputCloud(_inputCloud, nullptr); - - this->_alpha_hull_tree = std::make_shared>(); - this->_alpha_hull_tree->setInputCloud(_alphaHullCloud, nullptr); - - - // Estimate normals of the alpha shape vertices. - // Correct normals are needed for the Poisson surface reconstruction - pcl::NormalEstimationOMP normal_est; - normal_est.setInputCloud(_alphaHullCloud); - pcl::PointCloud normal_cloud; - normal_est.setRadiusSearch(_bbox.ObjectSpaceBBox().LongestEdge() * 1e-2); - // normal_est.setKSearch(40); - normal_est.compute(normal_cloud); - - // The estimated normals are not oriented correctly - // Calculate center line and use it to flip normals - this->extractCenterLine(normal_cloud); - // this->flipNormalsWithCenterLine(normal_cloud); - this->flipNormalsWithCenterLine_distanceBased(normal_cloud); - - _resultNormalCloud = std::make_shared>(normal_cloud); - - if (usePoisson) { - - pcl::Poisson surface; - - // Perform a Poisson surface reconstruction - _polygons.clear(); - surface.setInputCloud(_resultNormalCloud); - surface.setDepth(9); - surface.setSamplesPerNode(2.0f); - // surface.setConfidence(true); - - surface.reconstruct(_poissonCloud, _polygons); - - // Estimate normals of the reconstructed surface - pcl::NormalEstimationOMP new_normal_est; - new_normal_est.setKSearch(40); - std::shared_ptr> surface_shared = - std::make_shared>(_poissonCloud); - new_normal_est.setInputCloud(surface_shared); - new_normal_est.compute(_poissonCloud); - - this->flipNormalsWithCenterLine_distanceBased(_poissonCloud); - } - - // this->applyMeshCorrections(); -} - -bool ExtractMesh::createPointCloud(std::vector& vars) { - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - if (vars.empty()) - return false; - - const auto count = cd->getData(vars[0])->size(); - - _cloud.points.resize(count); - - for (auto var : vars) { - if (this->_formatSlot.Param()->Value() == 0) { - auto x = - cd->getData(std::string(this->_xSlot.Param()->ValueString()))->GetAsFloat(); - auto y = - cd->getData(std::string(this->_ySlot.Param()->ValueString()))->GetAsFloat(); - auto z = - cd->getData(std::string(this->_zSlot.Param()->ValueString()))->GetAsFloat(); - - auto xminmax = std::minmax_element(x.begin(), x.end()); - auto yminmax = std::minmax_element(y.begin(), y.end()); - auto zminmax = std::minmax_element(z.begin(), z.end()); - _bbox.SetObjectSpaceBBox( - *xminmax.first, *yminmax.first, *zminmax.second, *xminmax.second, *yminmax.second, *zminmax.first); - - for (unsigned long long i = 0; i < count; i++) { - _cloud.points[i].x = x[i]; - _cloud.points[i].y = y[i]; - _cloud.points[i].z = z[i]; - } - - } else { - // auto xyz = - // cd->getData(std::string(this->_xyzSlot.Param()->ValueString())) - // ->GetAsFloat(); - int coarse_factor = 30; - auto xyz = cd->getData(std::string(this->_xyzSlot.Param()->ValueString())) - ->GetAsDouble(); - float xmin = std::numeric_limits::max(); - float xmax = std::numeric_limits::min(); - float ymin = std::numeric_limits::max(); - float ymax = std::numeric_limits::min(); - float zmin = std::numeric_limits::max(); - float zmax = std::numeric_limits::min(); - - _cloud.points.resize(count / coarse_factor); - for (unsigned long long i = 0; i < count / (3 * coarse_factor); i++) { - _cloud.points[i].x = xyz[3 * (i * coarse_factor) + 0]; - _cloud.points[i].y = xyz[3 * (i * coarse_factor) + 1]; - _cloud.points[i].z = xyz[3 * (i * coarse_factor) + 2]; - - xmin = std::min(xmin, _cloud.points[i].x); - xmax = std::max(xmax, _cloud.points[i].x); - ymin = std::min(ymin, _cloud.points[i].y); - ymax = std::max(ymax, _cloud.points[i].y); - zmin = std::min(zmin, _cloud.points[i].z); - zmax = std::max(zmax, _cloud.points[i].z); - } - _bbox.SetObjectSpaceBBox(xmin, ymin, zmax, xmax, ymax, zmin); - } - } - return true; -} - -void ExtractMesh::convertToMesh() { - - if (!usePoisson) { - _mesh_attribs.resize(1); - _mesh_attribs[0].component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; - _mesh_attribs[0].byte_size = _alphaHullCloud->points.size() * sizeof(pcl::PointXYZ); - _mesh_attribs[0].component_cnt = 3; - _mesh_attribs[0].stride = sizeof(pcl::PointXYZ); - _mesh_attribs[0].data = reinterpret_cast(const_cast(_alphaHullCloud->points.data())); - } else { - _mesh_attribs.resize(2); - _vertex_data.resize(3 * _poissonCloud.points.size()); - _normal_data.resize(3 * _poissonCloud.points.size()); -#pragma omp parallel for - for (auto i = 0; i < _poissonCloud.points.size(); i++) { - // - _vertex_data[3 * i + 0] = _poissonCloud.points[i].x; - _vertex_data[3 * i + 1] = _poissonCloud.points[i].y; - _vertex_data[3 * i + 2] = _poissonCloud.points[i].z; - // - _normal_data[3 * i + 0] = _poissonCloud.points[i].normal_x; - _normal_data[3 * i + 1] = _poissonCloud.points[i].normal_y; - _normal_data[3 * i + 2] = _poissonCloud.points[i].normal_z; - } - - // - _mesh_attribs[0].semantic = mesh::MeshDataAccessCollection::AttributeSemanticType::POSITION; - _mesh_attribs[0].component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; - _mesh_attribs[0].byte_size = sizeof(float) * _vertex_data.size(); - _mesh_attribs[0].component_cnt = 3; - _mesh_attribs[0].stride = 3 * sizeof(float); - _mesh_attribs[0].data = reinterpret_cast(_vertex_data.data()); - - // - _mesh_attribs[1].semantic = mesh::MeshDataAccessCollection::AttributeSemanticType::NORMAL; - _mesh_attribs[1].component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; - _mesh_attribs[1].byte_size = sizeof(float) * _normal_data.size(); - _mesh_attribs[1].component_cnt = 3; - _mesh_attribs[1].stride = 3 * sizeof(float); - _mesh_attribs[1].data = reinterpret_cast(_normal_data.data()); - } - - _mesh_indices.type = mesh::MeshDataAccessCollection::ValueType::UNSIGNED_INT; - _mesh_indices.byte_size = 3 * _polygons.size() * sizeof(uint32_t); - _mesh_indices.data = reinterpret_cast(_polygons.data()); -} - -bool ExtractMesh::getData(core::Call& call) { - - bool something_changed = _recalc; - - auto cm = dynamic_cast(&call); - if (cm == nullptr) - return false; - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - std::vector toInq; - toInq.clear(); - if (this->_formatSlot.Param()->Value() == 0) { - toInq.emplace_back(std::string(this->_xSlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_ySlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_zSlot.Param()->ValueString())); - } else { - toInq.emplace_back(std::string(this->_xyzSlot.Param()->ValueString())); - } - - // get data from adios - for (auto var : toInq) { - if (!cd->inquireVar(var)) - return false; - } - - if (cd->getDataHash() != _old_datahash) { - if (!(*cd)(0)) - return false; - something_changed = true; - } - - if (something_changed) { - - if (!this->createPointCloud(toInq)) - return false; - - this->calculateAlphaShape(); - - // this->filterResult(); - // this->filterByIndex(); - } - - if (_mesh_attribs.empty() || something_changed) { - this->convertToMesh(); - - ++m_version; - } - - if (cm->version() < m_version) { - auto meta_data = cm->getMetaData(); - meta_data.m_bboxs = _bbox; - cm->setMetaData(meta_data); - - // put data in mesh - mesh::MeshDataAccessCollection mesh; - - std::string identifier = std::string(FullName()) + "_mesh"; - mesh.addMesh(identifier, _mesh_attribs, _mesh_indices); - cm->setData(std::make_shared(std::move(mesh)), m_version); - } - - _old_datahash = cd->getDataHash(); - _recalc = false; - - return true; -} - -bool ExtractMesh::getMetaData(core::Call& call) { - - auto cm = dynamic_cast(&call); - if (cm == nullptr) - return false; - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - auto meta_data = cm->getMetaData(); - - // get metadata from adios - cd->setFrameIDtoLoad(meta_data.m_frame_ID); - if (!(*cd)(1)) - return false; - auto vars = cd->getAvailableVars(); - for (auto var : vars) { - this->_xSlot.Param()->AddValue(var); - this->_ySlot.Param()->AddValue(var); - this->_zSlot.Param()->AddValue(var); - this->_xyzSlot.Param()->AddValue(var); - } - - if (cd->getDataHash() == _old_datahash && !_recalc) - return true; - - // put metadata in mesh call - meta_data.m_frame_cnt = cd->getFrameCount(); - cm->setMetaData(meta_data); - - return true; -} - -bool ExtractMesh::getParticleData(core::Call& call) { - auto cm = dynamic_cast(&call); - if (cm == nullptr) - return false; - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - // if (cd->getDataHash() == _old_datahash && cm->FrameID() == cd->getFrameIDtoLoad() && cm->DataHash() == - // _recalc_hash) - // return true; - - std::vector toInq; - toInq.clear(); - if (this->_formatSlot.Param()->Value() == 0) { - toInq.emplace_back(std::string(this->_xSlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_ySlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_zSlot.Param()->ValueString())); - } else { - toInq.emplace_back(std::string(this->_xyzSlot.Param()->ValueString())); - } - - // get data from adios - for (auto var : toInq) { - if (!cd->inquireVar(var)) - return false; - } - if (cd->getDataHash() != _old_datahash) - if (!(*cd)(0)) - return false; - - - if (!this->createPointCloud(toInq)) - return false; - - - cm->AccessBoundingBoxes().SetObjectSpaceBBox(_bbox.ObjectSpaceBBox()); - - if (cd->getDataHash() != _old_datahash || _recalc) - this->calculateAlphaShape(); - - // this->filterResult(); - // this->filterByIndex(); - - cm->SetParticleListCount(1); - // cm->AccessParticles(0).SetGlobalRadius(0.02f); - cm->AccessParticles(0).SetGlobalRadius(_bbox.ObjectSpaceBBox().LongestEdge() * 1e-3); - cm->AccessParticles(0).SetCount(_alphaHullCloud->points.size()); - cm->AccessParticles(0).SetVertexData(geocalls::MultiParticleDataCall::Particles::VERTDATA_FLOAT_XYZ, - reinterpret_cast(&_resultNormalCloud->points[0].x), sizeof(pcl::PointNormal)); - cm->AccessParticles(0).SetDirData(geocalls::MultiParticleDataCall::Particles::DIRDATA_FLOAT_XYZ, - &_resultNormalCloud->points[0].normal_x, sizeof(pcl::PointNormal)); - - _old_datahash = cd->getDataHash(); - _recalc = false; - - return true; -} - -bool ExtractMesh::getParticleMetaData(core::Call& call) { - auto cm = dynamic_cast(&call); - if (cm == nullptr) - return false; - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - if (cd->getDataHash() == _old_datahash && cm->FrameID() == cd->getFrameIDtoLoad()) - return true; - - // get metadata from adios - if (!(*cd)(1)) - return false; - auto vars = cd->getAvailableVars(); - for (auto var : vars) { - this->_xSlot.Param()->AddValue(var); - this->_ySlot.Param()->AddValue(var); - this->_zSlot.Param()->AddValue(var); - this->_xyzSlot.Param()->AddValue(var); - } - - - cm->SetFrameCount(cd->getFrameCount()); - cd->setFrameIDtoLoad(cm->FrameID()); - cm->SetDataHash(_old_datahash); - - return true; -} - -bool ExtractMesh::getCenterlineData(core::Call& call) { - auto cm = dynamic_cast(&call); - if (cm == nullptr) - return false; - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - // if (cd->getDataHash() == _old_datahash && meta_data.m_frame_ID == cd->getFrameIDtoLoad() && - // meta_data.m_data_hash == _recalc_hash) - // return true; - - std::vector toInq; - toInq.clear(); - if (this->_formatSlot.Param()->Value() == 0) { - toInq.emplace_back(std::string(this->_xSlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_ySlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_zSlot.Param()->ValueString())); - } else { - toInq.emplace_back(std::string(this->_xyzSlot.Param()->ValueString())); - } - - // get data from adios - for (auto var : toInq) { - if (!cd->inquireVar(var)) - return false; - } - - if (cd->getDataHash() != _old_datahash) - if (!(*cd)(0)) - return false; - - bool something_has_changed = (cd->getDataHash() != _old_datahash); - - if (something_has_changed) { - ++m_version; - - if (!this->createPointCloud(toInq)) - return false; - - this->calculateAlphaShape(); - } - - if (cm->version() < m_version) { - - _line_attribs.resize(1); - _line_attribs[0].component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; - _line_attribs[0].byte_size = _centerline.size() * sizeof(std::array); - _line_attribs[0].component_cnt = 3; - _line_attribs[0].stride = sizeof(std::array); - _line_attribs[0].data = reinterpret_cast(_centerline.data()); - - _cl_indices.resize(_centerline.size() - 1); - std::generate(_cl_indices.begin(), _cl_indices.end(), [n = 0]() mutable { return n++; }); - - _line_indices.type = mesh::MeshDataAccessCollection::ValueType::UNSIGNED_INT; - _line_indices.byte_size = _cl_indices.size() * sizeof(uint32_t); - _line_indices.data = reinterpret_cast(_cl_indices.data()); - - // put data in line - mesh::MeshDataAccessCollection line; - std::string identifier = std::string(FullName()) + "_line"; - line.addMesh(identifier, _line_attribs, _line_indices); - cm->setData(std::make_shared(std::move(line)), m_version); - - auto meta_data = cm->getMetaData(); - meta_data.m_bboxs = _bbox; - cm->setMetaData(meta_data); - } - - _old_datahash = cd->getDataHash(); - _recalc = false; - - return true; -} - -bool ExtractMesh::getKDMetaData(core::Call& call) { - - auto cm = dynamic_cast(&call); - if (cm == nullptr) - return false; - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - auto meta_data = cm->getMetaData(); - if (cd->getDataHash() == _old_datahash && meta_data.m_frame_ID == cd->getFrameIDtoLoad() && !_recalc) - return true; - - // get metadata from adios - - cd->setFrameIDtoLoad(meta_data.m_frame_ID); - if (!(*cd)(1)) - return false; - auto vars = cd->getAvailableVars(); - for (auto var : vars) { - this->_xSlot.Param()->AddValue(var); - this->_ySlot.Param()->AddValue(var); - this->_zSlot.Param()->AddValue(var); - this->_xyzSlot.Param()->AddValue(var); - } - - // put metadata in mesh call - meta_data.m_frame_cnt = cd->getFrameCount(); - cm->setMetaData(meta_data); - - return true; -} - -bool ExtractMesh::getKDData(core::Call& call) { - - auto cm = dynamic_cast(&call); - if (cm == nullptr) - return false; - - auto cd = this->_getDataCall.CallAs(); - if (cd == nullptr) - return false; - - - // if (cd->getDataHash() == _old_datahash && meta_data.m_frame_ID == cd->getFrameIDtoLoad() && - // meta_data.m_data_hash == _recalc_hash) - // return true; - - std::vector toInq; - toInq.clear(); - if (this->_formatSlot.Param()->Value() == 0) { - toInq.emplace_back(std::string(this->_xSlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_ySlot.Param()->ValueString())); - toInq.emplace_back(std::string(this->_zSlot.Param()->ValueString())); - } else { - toInq.emplace_back(std::string(this->_xyzSlot.Param()->ValueString())); - } - - // get data from adios - for (auto var : toInq) { - if (!cd->inquireVar(var)) - return false; - } - - if (cd->getDataHash() != _old_datahash) - if (!(*cd)(0)) - return false; - - if (cd->getDataHash() != _old_datahash || _recalc) { - ++m_version; - - if (!this->createPointCloud(toInq)) - return false; - - this->calculateAlphaShape(); - } - - if (cm->version() < m_version) { - cm->setData(this->_full_data_tree, m_version); - - auto meta_data = cm->getMetaData(); - meta_data.m_bboxs = _bbox; - cm->setMetaData(meta_data); - } - - _old_datahash = cd->getDataHash(); - _recalc = false; - - return true; -} - -bool ExtractMesh::toggleFormat(core::param::ParamSlot& p) { - - if (this->_formatSlot.Param()->Value() == 0) { - this->_xSlot.Param()->SetGUIVisible(true); - this->_ySlot.Param()->SetGUIVisible(true); - this->_zSlot.Param()->SetGUIVisible(true); - this->_xyzSlot.Param()->SetGUIVisible(false); - } else { - this->_xSlot.Param()->SetGUIVisible(false); - this->_ySlot.Param()->SetGUIVisible(false); - this->_zSlot.Param()->SetGUIVisible(false); - this->_xyzSlot.Param()->SetGUIVisible(true); - } - - return true; -} - -bool ExtractMesh::alphaChanged(core::param::ParamSlot& p) { - - _recalc = true; - - return true; -} - -bool ExtractMesh::filterResult() { - - const int factor = 3; - - std::vector new_polygon; - new_polygon.reserve(_polygons.size()); - - for (auto& polygon : _polygons) { - auto v1 = _alphaHullCloud->points[polygon.vertices[0]]; - auto v2 = _alphaHullCloud->points[polygon.vertices[1]]; - auto v3 = _alphaHullCloud->points[polygon.vertices[2]]; - - auto a = v1 - v2; - auto length_a = std::sqrt(a.x * a.x + a.y * a.y + a.z * a.z); - - auto b = v1 - v3; - auto length_b = std::sqrt(b.x * b.x + b.y * b.y + b.z * b.z); - - auto c = v2 - v3; - auto length_c = std::sqrt(c.x * c.x + c.y * c.y + c.z * c.z); - - auto l1 = length_b > length_a ? length_b / length_a : length_a / length_b; - auto l2 = length_c > length_a ? length_c / length_a : length_a / length_c; - auto l3 = length_b > length_c ? length_b / length_c : length_c / length_b; - - if (l1 >= factor || l2 >= factor || l3 >= factor) { - megamol::core::utility::log::Log::DefaultLog.WriteInfo("[ExtractMesh] Found bad polygon."); - } else { - new_polygon.emplace_back(polygon); - } - } - new_polygon.shrink_to_fit(); - - _polygons = std::move(new_polygon); - - return true; -} - -bool ExtractMesh::filterByIndex() { - - size_t max_distance = 10; - - std::vector new_polygon; - new_polygon.reserve(_polygons.size()); - - for (auto polygon : _polygons) { - auto dist_a = std::abs(static_cast(polygon.vertices[0]) - static_cast(polygon.vertices[1])); - auto dist_b = std::abs(static_cast(polygon.vertices[2]) - static_cast(polygon.vertices[1])); - auto dist_c = std::abs(static_cast(polygon.vertices[0]) - static_cast(polygon.vertices[2])); - - if (!(dist_a >= max_distance || dist_b >= max_distance || dist_c >= max_distance)) { - new_polygon.emplace_back(polygon); - } - } - new_polygon.shrink_to_fit(); - _polygons = std::move(new_polygon); - - return true; -} - -} // namespace probe -} // namespace megamol diff --git a/plugins/probe/src/ExtractMesh.h b/plugins/probe/src/ExtractMesh.h deleted file mode 100644 index 303c57a54e..0000000000 --- a/plugins/probe/src/ExtractMesh.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ExtractMesh.h - * Copyright (C) 2019 by MegaMol Team - * Alle Rechte vorbehalten. - */ -#pragma once - -#include "concave_hull.h" -#include "mesh/MeshCalls.h" -#include "mmcore/CalleeSlot.h" -#include "mmcore/CallerSlot.h" -#include "mmcore/Module.h" -#include "mmcore/param/ParamSlot.h" -#include "poisson.h" -#include - -namespace megamol { -namespace probe { - -class ExtractMesh : public core::Module { -public: - /** - * Answer the name of this module. - * - * @return The name of this module. - */ - static const char* ClassName(void) { - return "ExtractMesh"; - } - - /** - * Answer a human readable description of this module. - * - * @return A human readable description of this module. - */ - static const char* Description(void) { - return "Extracts a mesh from point data."; - } - - /** - * Answers whether this module is available on the current system. - * - * @return 'true' if the module is available, 'false' otherwise. - */ - static bool IsAvailable(void) { - return true; - } - - /** Ctor. */ - ExtractMesh(void); - - /** Dtor. */ - virtual ~ExtractMesh(void); - -protected: - virtual bool create(); - virtual void release(); - - - core::CallerSlot _getDataCall; - core::CalleeSlot _deployMeshCall; - core::CalleeSlot _deploySpheresCall; - core::CalleeSlot _deployLineCall; - core::CalleeSlot _deployFullDataTree; - core::param::ParamSlot _algorithmSlot; - core::param::ParamSlot _xSlot; - core::param::ParamSlot _ySlot; - core::param::ParamSlot _zSlot; - core::param::ParamSlot _xyzSlot; - core::param::ParamSlot _formatSlot; - core::param::ParamSlot _alphaSlot; - - -private: - bool InterfaceIsDirty(); - bool flipNormalsWithCenterLine(pcl::PointCloud& point_cloud); - bool flipNormalsWithCenterLine_distanceBased(pcl::PointCloud& point_cloud); - bool extractCenterLine(pcl::PointCloud& point_cloud); - void applyMeshCorrections(); - // virtual void readParams(); - void calculateAlphaShape(); - - bool createPointCloud(std::vector& vars); - void convertToMesh(); - - bool getMetaData(core::Call& call); - bool getData(core::Call& call); - - bool getParticleData(core::Call& call); - bool getParticleMetaData(core::Call& call); - - bool getCenterlineData(core::Call& call); - - bool getKDMetaData(core::Call& call); - bool getKDData(core::Call& call); - - - bool toggleFormat(core::param::ParamSlot& p); - - bool alphaChanged(core::param::ParamSlot& p); - - bool filterResult(); - bool filterByIndex(); - - bool usePoisson = true; - std::vector _vertex_data; - std::vector _normal_data; - - // PCL stuff - pcl::PointCloud::ConstPtr _inputCloud; - pcl::PointCloud _cloud; - std::vector _polygons; - std::vector _indices; - pcl::PointCloud::ConstPtr _alphaHullCloud; - pcl::PointCloud _poissonCloud; - std::shared_ptr> _resultNormalCloud; - std::shared_ptr> _full_data_tree; - std::shared_ptr> _alpha_hull_tree; - - // CallMesh stuff - std::vector _mesh_attribs; - mesh::MeshDataAccessCollection::IndexData _mesh_indices; - core::BoundingBoxes _bbox; - - // CallCenterline stuff - std::vector _line_attribs; - mesh::MeshDataAccessCollection::IndexData _line_indices; - std::vector> _centerline; - std::vector> _cl_indices_per_slice; - std::vector _cl_indices; - - size_t _old_datahash = 0; - bool _recalc = true; - - uint32_t m_version; -}; - -} // namespace probe -} // namespace megamol diff --git a/plugins/probe/src/ExtractSkeleton.h b/plugins/probe/src/ExtractSkeleton.h index 70a2dbbab0..39131290ec 100644 --- a/plugins/probe/src/ExtractSkeleton.h +++ b/plugins/probe/src/ExtractSkeleton.h @@ -5,13 +5,11 @@ */ #pragma once -#include "concave_hull.h" #include "mesh/MeshCalls.h" #include "mmcore/CalleeSlot.h" #include "mmcore/CallerSlot.h" #include "mmcore/Module.h" #include "mmcore/param/ParamSlot.h" -#include "poisson.h" #include namespace megamol { diff --git a/plugins/probe/src/SampleAlongProbes.h b/plugins/probe/src/SampleAlongProbes.h index e80baba90d..a44f182a5e 100644 --- a/plugins/probe/src/SampleAlongProbes.h +++ b/plugins/probe/src/SampleAlongProbes.h @@ -12,13 +12,13 @@ #include "mmcore/Module.h" #include "geometry_calls/VolumetricDataCall.h" -#include "kdtree.h" #include "mmadios/CallADIOSData.h" #include "mmcore/param/EnumParam.h" #include "mmcore/param/FloatParam.h" #include "mmcore/param/IntParam.h" #include "mmcore/param/ParamSlot.h" #include "probe/ProbeCollection.h" +#include "probe/CallKDTree.h" #include "CGAL/Delaunay_triangulation_3.h" #include "CGAL/Delaunay_triangulation_cell_base_3.h" @@ -96,11 +96,11 @@ class SampleAlongPobes : public core::Module { private: template - void doScalarSampling(const std::shared_ptr>& tree, std::vector& data); + void doScalarSampling(const std::shared_ptr& tree, std::vector& data); template void doScalarDistributionSampling( - const std::shared_ptr>& tree, std::vector& data); + const std::shared_ptr& tree, std::vector& data); template void doVolumeRadiusSampling(T* data); @@ -109,19 +109,19 @@ class SampleAlongPobes : public core::Module { void doVolumeTrilinSampling(T* data); template - void doVectorSamling(const std::shared_ptr>& tree, const std::vector& data_x, + void doVectorSamling(const std::shared_ptr& tree, const std::vector& data_x, const std::vector& data_y, const std::vector& data_z, const std::vector& data_w); template - void doTetrahedralSampling(const std::shared_ptr>& tree, std::vector& data); + void doTetrahedralSampling(const std::shared_ptr& tree, std::vector& data); template - void doTetrahedralVectorSamling(const std::shared_ptr>& tree, + void doTetrahedralVectorSamling(const std::shared_ptr& tree, const std::vector& data_x, const std::vector& data_y, const std::vector& data_z, const std::vector& data_w); template - void doNearestNeighborSampling(const std::shared_ptr>& tree, std::vector& data); + void doNearestNeighborSampling(const std::shared_ptr& tree, std::vector& data); bool getData(core::Call& call); @@ -139,8 +139,7 @@ class SampleAlongPobes : public core::Module { template -void SampleAlongPobes::doScalarSampling( - const std::shared_ptr>& tree, std::vector& data) { +void SampleAlongPobes::doScalarSampling(const std::shared_ptr& tree, std::vector& data) { const int samples_per_probe = this->_num_samples_per_probe_slot.Param()->Value(); const float sample_radius_factor = this->_sample_radius_factor_slot.Param()->Value(); @@ -196,26 +195,34 @@ void SampleAlongPobes::doScalarSampling( for (int j = 0; j < samples_per_probe; j++) { - pcl::PointXYZ sample_point; - sample_point.x = probe.m_position[0] + j * sample_step * probe.m_direction[0]; - sample_point.y = probe.m_position[1] + j * sample_step * probe.m_direction[1]; - sample_point.z = probe.m_position[2] + j * sample_step * probe.m_direction[2]; + std::array sample_point; + sample_point[0] = probe.m_position[0] + j * sample_step * probe.m_direction[0]; + sample_point[1] = probe.m_position[1] + j * sample_step * probe.m_direction[1]; + sample_point[2] = probe.m_position[2] + j * sample_step * probe.m_direction[2]; - std::vector k_indices; - std::vector k_distances; + std::vector> res; - auto num_neighbors = tree->radiusSearch(sample_point, radius, k_indices, k_distances); + auto num_neighbors = + tree->radiusSearch(&sample_point[0], radius, res, nanoflann::SearchParams(10, 0.01f, true)); if (num_neighbors == 0) { - num_neighbors = tree->nearestKSearch(sample_point, 1, k_indices, k_distances); + std::vector ret_index(1); + std::vector out_dist_sqr(1); + nanoflann::KNNResultSet resultSet(1); + resultSet.init(ret_index.data(), out_dist_sqr.data()); + num_neighbors = tree->findNeighbors(resultSet ,&sample_point[0], nanoflann::SearchParams(10)); + + res.resize(1); + res[0].first = ret_index[0]; + res[0].second = out_dist_sqr[0]; } // accumulate values float value = 0; for (int n = 0; n < num_neighbors; n++) { - auto distance_weight = k_distances[n] / radius; - value += data[k_indices[n]] * distance_weight; - min_data = std::min(min_data, static_cast(data[k_indices[n]])); - max_data = std::max(max_data, static_cast(data[k_indices[n]])); + auto distance_weight = res[n].second / radius; + value += data[res[n].first] * distance_weight; + min_data = std::min(min_data, static_cast(data[res[n].first])); + max_data = std::max(max_data, static_cast(data[res[n].first])); } // end num_neighbors value /= num_neighbors; if (this->_weighting.Param()->Value() == 0) { @@ -245,7 +252,7 @@ void SampleAlongPobes::doScalarSampling( template inline void SampleAlongPobes::doScalarDistributionSampling( - const std::shared_ptr>& tree, std::vector& data) { + const std::shared_ptr& tree, std::vector& data) { const int samples_per_probe = this->_num_samples_per_probe_slot.Param()->Value(); const float sample_radius_factor = this->_sample_radius_factor_slot.Param()->Value(); @@ -299,17 +306,25 @@ inline void SampleAlongPobes::doScalarDistributionSampling( for (int j = 0; j < samples_per_probe; j++) { - pcl::PointXYZ sample_point; - sample_point.x = probe.m_position[0] + j * sample_step * probe.m_direction[0]; - sample_point.y = probe.m_position[1] + j * sample_step * probe.m_direction[1]; - sample_point.z = probe.m_position[2] + j * sample_step * probe.m_direction[2]; + std::array sample_point; + sample_point[0] = probe.m_position[0] + j * sample_step * probe.m_direction[0]; + sample_point[1] = probe.m_position[1] + j * sample_step * probe.m_direction[1]; + sample_point[2] = probe.m_position[2] + j * sample_step * probe.m_direction[2]; - std::vector k_indices; - std::vector k_distances; + std::vector> res; - auto num_neighbors = tree->radiusSearch(sample_point, radius, k_indices, k_distances); + auto num_neighbors = + tree->radiusSearch(&sample_point[0], radius, res, nanoflann::SearchParams(10, 0.01f, true)); if (num_neighbors == 0) { - num_neighbors = tree->nearestKSearch(sample_point, 1, k_indices, k_distances); + std::vector ret_index(1); + std::vector out_dist_sqr(1); + nanoflann::KNNResultSet resultSet(1); + resultSet.init(ret_index.data(), out_dist_sqr.data()); + num_neighbors = tree->findNeighbors(resultSet, &sample_point[0], nanoflann::SearchParams(10)); + + res.resize(1); + res[0].first = ret_index[0]; + res[0].second = out_dist_sqr[0]; } // accumulate values @@ -317,9 +332,9 @@ inline void SampleAlongPobes::doScalarDistributionSampling( float min_data = std::numeric_limits::max(); float max_data = std::numeric_limits::min(); for (int n = 0; n < num_neighbors; n++) { - value += data[k_indices[n]]; - min_data = std::min(min_data, static_cast(data[k_indices[n]])); - max_data = std::max(max_data, static_cast(data[k_indices[n]])); + value += data[res[n].first]; + min_data = std::min(min_data, static_cast(data[res[n].first])); + max_data = std::max(max_data, static_cast(data[res[n].first])); } // end num_neighbors value /= num_neighbors; @@ -339,7 +354,7 @@ inline void SampleAlongPobes::doScalarDistributionSampling( } template -inline void SampleAlongPobes::doVectorSamling(const std::shared_ptr>& tree, +inline void SampleAlongPobes::doVectorSamling(const std::shared_ptr& tree, const std::vector& data_x, const std::vector& data_y, const std::vector& data_z, const std::vector& data_w) { @@ -399,27 +414,35 @@ inline void SampleAlongPobes::doVectorSamling(const std::shared_ptr sample_point; + sample_point[0] = probe.m_position[0] + j * sample_step * probe.m_direction[0]; + sample_point[1] = probe.m_position[1] + j * sample_step * probe.m_direction[1]; + sample_point[2] = probe.m_position[2] + j * sample_step * probe.m_direction[2]; - std::vector k_indices; - std::vector k_distances; + std::vector> res; - auto num_neighbors = tree->radiusSearch(sample_point, radius, k_indices, k_distances); + auto num_neighbors = + tree->radiusSearch(&sample_point[0], radius, res, nanoflann::SearchParams(10, 0.01f, true)); if (num_neighbors == 0) { - num_neighbors = tree->nearestKSearch(sample_point, 1, k_indices, k_distances); + std::vector ret_index(1); + std::vector out_dist_sqr(1); + nanoflann::KNNResultSet resultSet(1); + resultSet.init(ret_index.data(), out_dist_sqr.data()); + num_neighbors = tree->findNeighbors(resultSet, &sample_point[0], nanoflann::SearchParams(10)); + + res.resize(1); + res[0].first = ret_index[0]; + res[0].second = out_dist_sqr[0]; } // accumulate values float value_x = 0, value_y = 0, value_z = 0, value_w = 0; for (int n = 0; n < num_neighbors; n++) { - value_x += data_x[k_indices[n]]; - value_y += data_y[k_indices[n]]; - value_z += data_z[k_indices[n]]; - value_w += data_w[k_indices[n]]; + value_x += data_x[res[n].first]; + value_y += data_y[res[n].first]; + value_z += data_z[res[n].first]; + value_w += data_w[res[n].first]; } // end num_neighbors samples->samples[j][0] = value_x / num_neighbors; ; @@ -443,7 +466,7 @@ inline void SampleAlongPobes::doVectorSamling(const std::shared_ptr void SampleAlongPobes::doTetrahedralSampling( - const std::shared_ptr>& tree, std::vector& data) { + const std::shared_ptr& tree, std::vector& data) { using K = CGAL::Exact_predicates_inexact_constructions_kernel; using Vb = CGAL::Triangulation_vertex_base_with_info_3; @@ -457,11 +480,12 @@ void SampleAlongPobes::doTetrahedralSampling( Triangulation tri; { - auto const num_points = tree->getInputCloud()->points.size(); - auto const& cloud = tree->getInputCloud()->points; + + auto const num_points = tree->dataset.derived().size(); + auto const& cloud = tree->dataset.derived(); std::vector> points(num_points); std::transform(cloud.cbegin(), cloud.cend(), data.cbegin(), points.begin(), - [](pcl::PointXYZ const& p, T const& val) { return std::make_pair(Point(p.x, p.y, p.z), val); }); + [](std::array const& p, T const& val) { return std::make_pair(Point(p[0], p[1], p[2]), val); }); tri = Triangulation(points.cbegin(), points.cend()); } @@ -576,7 +600,7 @@ void SampleAlongPobes::doTetrahedralSampling( } template -inline void SampleAlongPobes::doTetrahedralVectorSamling(const std::shared_ptr>& tree, +inline void SampleAlongPobes::doTetrahedralVectorSamling(const std::shared_ptr& tree, const std::vector& data_x, const std::vector& data_y, const std::vector& data_z, const std::vector& data_w) { @@ -594,18 +618,18 @@ inline void SampleAlongPobes::doTetrahedralVectorSamling(const std::shared_ptr

getInputCloud()->points.size(); - auto const& cloud = tree->getInputCloud()->points; + auto const num_points = tree->dataset.derived().size(); + auto const& cloud = tree->dataset.derived(); std::vector> points(num_points); for (int i = 0; i < num_points; ++i) { - pcl::PointXYZ const& p = cloud[i]; + auto const& p = cloud[i]; T const& val_x = data_x[i]; T const& val_y = data_y[i]; T const& val_z = data_z[i]; T const& val_w = data_w[i]; - points[i] = std::make_pair(Point(p.x, p.y, p.z), std::array({val_x, val_y, val_z, val_w})); + points[i] = std::make_pair(Point(p[0], p[1], p[2]), std::array({val_x, val_y, val_z, val_w})); } tri = Triangulation(points.cbegin(), points.cend()); } @@ -739,7 +763,7 @@ inline void SampleAlongPobes::doTetrahedralVectorSamling(const std::shared_ptr

void SampleAlongPobes::doNearestNeighborSampling( - const std::shared_ptr>& tree, std::vector& data) { + const std::shared_ptr& tree, std::vector& data) { using K = CGAL::Exact_predicates_inexact_constructions_kernel; using Vb = CGAL::Triangulation_vertex_base_with_info_3; @@ -753,11 +777,11 @@ void SampleAlongPobes::doNearestNeighborSampling( Triangulation tri; { - auto const num_points = tree->getInputCloud()->points.size(); - auto const& cloud = tree->getInputCloud()->points; + auto const num_points = tree->dataset.derived().size(); + auto const& cloud = tree->dataset.derived(); std::vector> points(num_points); std::transform(cloud.cbegin(), cloud.cend(), data.cbegin(), points.begin(), - [](pcl::PointXYZ const& p, T const& val) { return std::make_pair(Point(p.x, p.y, p.z), val); }); + [](std::array const& p, T const& val) { return std::make_pair(Point(p[0], p[1], p[2]), val); }); tri = Triangulation(points.begin(), points.end()); } diff --git a/plugins/probe/src/SumGlyphs.cpp b/plugins/probe/src/SumGlyphs.cpp index e872282c6b..05214a04f6 100644 --- a/plugins/probe/src/SumGlyphs.cpp +++ b/plugins/probe/src/SumGlyphs.cpp @@ -101,8 +101,7 @@ bool SumGlyphs::getData(core::Call& call) { probe_positions[i] = pos; probes_with_this_clusterid[cluster_id].emplace_back(i); } - //using current_probe_type = std::decay_tgetGenericProbe(0))>; - + using current_probe_type = std::decay_tgetGenericProbe(0))>; // calculate middle probe distance diff --git a/plugins/probe/src/SumGlyphs.h b/plugins/probe/src/SumGlyphs.h index dbef783fb4..ed9115c7b3 100644 --- a/plugins/probe/src/SumGlyphs.h +++ b/plugins/probe/src/SumGlyphs.h @@ -16,7 +16,7 @@ #include "mesh/MeshCalls.h" #include "mmcore/param/ParamSlot.h" #include "probe/ProbeCollection.h" -#include "ConstructHull.h" +#include "probe/CallKDTree.h" namespace megamol { diff --git a/plugins/probe/src/SurfaceNets.h b/plugins/probe/src/SurfaceNets.h index 74b3204f15..bbf86b36d6 100644 --- a/plugins/probe/src/SurfaceNets.h +++ b/plugins/probe/src/SurfaceNets.h @@ -5,14 +5,12 @@ */ #pragma once -#include "concave_hull.h" #include "geometry_calls/VolumetricDataCall.h" #include "mesh/MeshCalls.h" #include "mmcore/CalleeSlot.h" #include "mmcore/CallerSlot.h" #include "mmcore/Module.h" #include "mmcore/param/ParamSlot.h" -#include "poisson.h" #include namespace megamol { diff --git a/plugins/probe/src/probe.cpp b/plugins/probe/src/probe.cpp index 8971e9fcb4..bad86478b6 100644 --- a/plugins/probe/src/probe.cpp +++ b/plugins/probe/src/probe.cpp @@ -9,7 +9,6 @@ #include "ConstructKDTree.h" #include "ExtractCenterline.h" -#include "ExtractMesh.h" #include "ExtractProbeGeometry.h" #include "GenerateGlyphs.h" #include "ManipulateMesh.h" @@ -49,7 +48,6 @@ class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPlug void registerClasses() override { // register modules - this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); diff --git a/plugins/probe_gl/src/FilterByProbe.cpp b/plugins/probe_gl/src/FilterByProbe.cpp index 167728e0a8..5c1635c089 100644 --- a/plugins/probe_gl/src/FilterByProbe.cpp +++ b/plugins/probe_gl/src/FilterByProbe.cpp @@ -248,21 +248,30 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { for (int j = 0; j < samples_per_probe; j++) { - pcl::PointXYZ sample_point; - sample_point.x = position[0] + j * sample_step * direction[0]; - sample_point.y = position[1] + j * sample_step * direction[1]; - sample_point.z = position[2] + j * sample_step * direction[2]; + std::array sample_point; + sample_point[0] = position[0] + j * sample_step * direction[0]; + sample_point[1] = position[1] + j * sample_step * direction[1]; + sample_point[2] = position[2] + j * sample_step * direction[2]; - std::vector k_distances; - std::vector k_indices; + std::vector> res; - auto num_neighbors = - tree->radiusSearch(sample_point, arg.m_sample_radius, k_indices, k_distances); + auto num_neighbors = tree->radiusSearch( + &sample_point[0], radius, res, nanoflann::SearchParams(10, 0.01f, true)); if (num_neighbors == 0) { - num_neighbors = tree->nearestKSearch(sample_point, 1, k_indices, k_distances); + std::vector ret_index(1); + std::vector out_dist_sqr(1); + nanoflann::KNNResultSet resultSet(1); + resultSet.init(ret_index.data(), out_dist_sqr.data()); + num_neighbors = tree->findNeighbors( + resultSet, &sample_point[0], nanoflann::SearchParams(10)); + + res.resize(1); + res[0].first = ret_index[0]; + res[0].second = out_dist_sqr[0]; + } + for (auto r : res) { + indices.emplace_back(r.first); } - - indices.insert(indices.end(), k_indices.begin(), k_indices.end()); } // end num samples per probe } }; @@ -353,21 +362,30 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { float depth = std::min(end, pending_filter_event.back().depth); //float depth = pending_filter_event.back().depth; - pcl::PointXYZ sample_point; - sample_point.x = position[0] + depth * direction[0]; - sample_point.y = position[1] + depth * direction[1]; - sample_point.z = position[2] + depth * direction[2]; + std::array sample_point; + sample_point[0] = position[0] + depth * direction[0]; + sample_point[1] = position[1] + depth * direction[1]; + sample_point[2] = position[2] + depth * direction[2]; - std::vector k_distances; - std::vector k_indices; + std::vector> res; - auto num_neighbors = - tree->radiusSearch(sample_point, arg.m_sample_radius, k_indices, k_distances); + auto num_neighbors = tree->radiusSearch( + &sample_point[0], radius, res, nanoflann::SearchParams(10, 0.01f, true)); if (num_neighbors == 0) { - num_neighbors = tree->nearestKSearch(sample_point, 1, k_indices, k_distances); + std::vector ret_index(1); + std::vector out_dist_sqr(1); + nanoflann::KNNResultSet resultSet(1); + resultSet.init(ret_index.data(), out_dist_sqr.data()); + num_neighbors = + tree->findNeighbors(resultSet, &sample_point[0], nanoflann::SearchParams(10)); + + res.resize(1); + res[0].first = ret_index[0]; + res[0].second = out_dist_sqr[0]; + } + for (auto r : res) { + indices.emplace_back(r.first); } - - indices.insert(indices.end(), k_indices.begin(), k_indices.end()); } }; From e377a7da65e1f124dcf45e2e22fa5c794cfc0e4d Mon Sep 17 00:00:00 2001 From: rauts Date: Tue, 7 Jun 2022 18:21:49 +0200 Subject: [PATCH 06/47] more 3rd party removal fixes --- plugins/probe/src/ConstructKDTree.cpp | 10 +++++----- plugins/probe/src/ConstructKDTree.h | 1 + plugins/probe_gl/src/ComputeDistance.cpp | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/probe/src/ConstructKDTree.cpp b/plugins/probe/src/ConstructKDTree.cpp index fdb11e088f..d833fbf352 100644 --- a/plugins/probe/src/ConstructKDTree.cpp +++ b/plugins/probe/src/ConstructKDTree.cpp @@ -216,11 +216,11 @@ bool ConstructKDTree::getData(core::Call& call) { ct->setMetaData(meta_data); // Extract the kd tree for easy sampling of the data - - this->_full_data_tree = std::make_shared( - 3 /*dim*/, _cloud, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); - this->_full_data_tree->buildIndex(); - this->_version++; + _data2kd = std::make_shared(_cloud); + _full_data_tree = std::make_shared( + 3 /*dim*/, *_data2kd, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + _full_data_tree->buildIndex(); + _version++; _old_datahash = cd->getDataHash(); } diff --git a/plugins/probe/src/ConstructKDTree.h b/plugins/probe/src/ConstructKDTree.h index df7b032c81..8dc38aefd5 100644 --- a/plugins/probe/src/ConstructKDTree.h +++ b/plugins/probe/src/ConstructKDTree.h @@ -72,6 +72,7 @@ class ConstructKDTree : public core::Module { bool toggleFormat(core::param::ParamSlot& p); // PCL stuff + std::shared_ptr _data2kd; std::vector> _cloud; std::shared_ptr _full_data_tree; diff --git a/plugins/probe_gl/src/ComputeDistance.cpp b/plugins/probe_gl/src/ComputeDistance.cpp index eb15c4fd06..c97bbf25a5 100644 --- a/plugins/probe_gl/src/ComputeDistance.cpp +++ b/plugins/probe_gl/src/ComputeDistance.cpp @@ -8,7 +8,7 @@ #include "datatools/misc/FrechetDistance.h" -#include "eigen.h" +#include #define _USE_MATH_DEFINES #include From ffba311bf54c12b4729ba77c99f6cfd2d90d6113 Mon Sep 17 00:00:00 2001 From: becherml Date: Wed, 15 Jun 2022 16:03:36 +0200 Subject: [PATCH 07/47] fix imgui hack in probe interaction and dirtyness in glyph rendering --- .../probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp | 1 + plugins/probe_gl/src/ProbeInteraction.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp b/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp index 66a2073e7f..3e27abcdf8 100644 --- a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp +++ b/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp @@ -164,6 +164,7 @@ bool megamol::probe_gl::ProbeBillboardGlyphRenderTasks::getDataCallback(core::Ca if (something_has_changed) { ++m_version; + this->m_billboard_size_slot.ResetDirty(); this->m_rendering_mode_slot.ResetDirty(); auto gpu_mtl_storage = mtlc->getData(); auto probes = pc->getData(); diff --git a/plugins/probe_gl/src/ProbeInteraction.cpp b/plugins/probe_gl/src/ProbeInteraction.cpp index 503a560d88..d7a033857d 100644 --- a/plugins/probe_gl/src/ProbeInteraction.cpp +++ b/plugins/probe_gl/src/ProbeInteraction.cpp @@ -336,10 +336,12 @@ bool megamol::probe_gl::ProbeInteraction::Render(core_gl::view::CallRender3DGL& { bool my_tool_active = true; - auto ctx = reinterpret_cast(this->GetCoreInstance()->GetCurrentImGuiContext()); - if (ctx != nullptr) { - ImGui::SetCurrentContext(ctx); - + bool valid_imgui_scope = + ((ImGui::GetCurrentContext() != nullptr) ? (ImGui::GetCurrentContext()->WithinFrameScope) : (false)); + //auto ctx = reinterpret_cast(this->GetCoreInstance()->GetCurrentImGuiContext()); + //if (ctx != nullptr) { + //ImGui::SetCurrentContext(ctx); + if (valid_imgui_scope) { ImGuiIO& io = ImGui::GetIO(); ImVec2 viewport = ImVec2(io.DisplaySize.x, io.DisplaySize.y); From ba6aa157f0764efcca786cdf737c7be0984c4997 Mon Sep 17 00:00:00 2001 From: becherml Date: Mon, 20 Jun 2022 17:37:24 +0200 Subject: [PATCH 08/47] Fix flag storage buffer usage --- plugins/probe_gl/src/FilterByProbe.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/probe_gl/src/FilterByProbe.cpp b/plugins/probe_gl/src/FilterByProbe.cpp index 5c1635c089..396d32a0c3 100644 --- a/plugins/probe_gl/src/FilterByProbe.cpp +++ b/plugins/probe_gl/src/FilterByProbe.cpp @@ -203,7 +203,7 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { glUniform1ui(m_filterNone_prgm->ParameterLocation("flag_cnt"), flag_cnt); - flag_data->flags->bind(1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); m_filterNone_prgm->Dispatch(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); @@ -285,7 +285,7 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { auto writeFlags = m_writeFlagsSlot.CallAs(); if (readFlags != nullptr && writeFlags != nullptr) { - (*readFlags)(core_gl::FlagCallWrite_GL::CallGetData); + (*readFlags)(core_gl::FlagCallRead_GL::CallGetData); if (readFlags->hasUpdate()) { this->m_version = readFlags->version(); @@ -304,7 +304,7 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { glUniform1ui(m_filterAll_prgm->ParameterLocation("flag_cnt"), flag_cnt); - flag_data->flags->bind(1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); m_filterAll_prgm->Dispatch(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); @@ -317,7 +317,7 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { glUniform1ui(m_setFlags_prgm->ParameterLocation("id_cnt"), static_cast(indices.size())); kdtree_ids->bind(0); - flag_data->flags->bind(1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); m_setFlags_prgm->Dispatch(static_cast(std::ceil(indices.size() / 64.0f)), 1, 1); @@ -416,7 +416,7 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { glUniform1ui(m_filterAll_prgm->ParameterLocation("flag_cnt"), flag_cnt); - flag_data->flags->bind(1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); m_filterAll_prgm->Dispatch(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); @@ -429,7 +429,7 @@ bool FilterByProbe::Render(core_gl::view::CallRender3DGL& call) { glUniform1ui(m_setFlags_prgm->ParameterLocation("id_cnt"), static_cast(indices.size())); kdtree_ids->bind(0); - flag_data->flags->bind(1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); m_setFlags_prgm->Dispatch(static_cast(std::ceil(indices.size() / 64.0f)), 1, 1); From 8a5718b61646f10a96565c15a470127e4326fb24 Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 1 Jun 2022 15:11:06 +0200 Subject: [PATCH 09/47] fixed representations --- plugins/mmospray/src/OSPRaySphereGeometry.cpp | 174 ++++++-- plugins/mmospray/src/OSPRaySphereGeometry.h | 6 + plugins/probe/include/probe/ProbeCollection.h | 25 +- plugins/probe/src/FilterProbes.cpp | 380 ++++++++++++++++++ .../probe/src/{SumGlyphs.h => FilterProbes.h} | 19 +- plugins/probe/src/PlaceProbes.cpp | 14 + plugins/probe/src/PlaceProbes.h | 1 + plugins/probe/src/ProbeClustering.cpp | 55 ++- plugins/probe/src/SumGlyphs.cpp | 246 ------------ plugins/probe/src/probe.cpp | 4 +- 10 files changed, 604 insertions(+), 320 deletions(-) create mode 100644 plugins/probe/src/FilterProbes.cpp rename plugins/probe/src/{SumGlyphs.h => FilterProbes.h} (80%) delete mode 100644 plugins/probe/src/SumGlyphs.cpp diff --git a/plugins/mmospray/src/OSPRaySphereGeometry.cpp b/plugins/mmospray/src/OSPRaySphereGeometry.cpp index 4202222f73..985fecfa12 100644 --- a/plugins/mmospray/src/OSPRaySphereGeometry.cpp +++ b/plugins/mmospray/src/OSPRaySphereGeometry.cpp @@ -36,6 +36,19 @@ bool OSPRaySphereGeometry::readData(megamol::core::Call& call) { CallOSPRayStructure* os = dynamic_cast(&call); megamol::geocalls::MultiParticleDataCall* cd = this->getDataSlot.CallAs(); + // check flagstorage + auto fcw = writeFlagsSlot.CallAs(); + auto fcr = readFlagsSlot.CallAs(); + + bool flags_dirty = false; + size_t flags_size = 0; + if (fcw != nullptr && fcr != nullptr) { + if ((*fcr)(core::FlagCallWrite_CPU::CallGetData)) { + flags_dirty = fcr->hasUpdate(); + } + flags_size = fcr->getData()->flags->size(); + } + this->structureContainer.dataChanged = false; if (cd == NULL) return false; @@ -47,7 +60,7 @@ bool OSPRaySphereGeometry::readData(megamol::core::Call& call) { return false; auto interface_dirty = this->InterfaceIsDirty(); - if (this->datahash != cd->DataHash() || this->time != os->getTime() || interface_dirty) { + if (this->datahash != cd->DataHash() || this->time != os->getTime() || interface_dirty || flags_dirty) { this->datahash = cd->DataHash(); this->time = os->getTime(); this->structureContainer.dataChanged = true; @@ -62,6 +75,15 @@ bool OSPRaySphereGeometry::readData(megamol::core::Call& call) { ss.spheres = std::make_shared(); const auto plist_count = cd->GetParticleListCount(); + int tot_part_count = 0; + std::vector offset_list(plist_count); + for (int i = 0; i < plist_count; ++i) { + offset_list[i] = tot_part_count; + tot_part_count += cd->AccessParticles(i).GetCount(); + } + _enabled_vertices.resize(plist_count); + _enabled_colors.resize(plist_count); + _selected_vertices.resize(plist_count); for (int i = 0; i < plist_count; ++i) { geocalls::MultiParticleDataCall::Particles& parts = cd->AccessParticles(i); @@ -82,44 +104,112 @@ bool OSPRaySphereGeometry::readData(megamol::core::Call& call) { ? geocalls::MultiParticleDataCall::Particles::ColorDataSize[parts.GetColourDataType()] : color_byte_stride; - // Vertex data type check - if (parts.GetVertexDataType() == geocalls::MultiParticleDataCall::Particles::VERTDATA_FLOAT_XYZ) { - auto va = ParticleDataAccessCollection::VertexAttribute(); - va.data = static_cast(parts.GetVertexData()); - va.byte_size = vertex_byte_stride * partCount; - va.component_cnt = 3; - va.component_type = ParticleDataAccessCollection::FLOAT; - va.stride = vertex_byte_stride; - va.offset = 0; - va.semantic = ParticleDataAccessCollection::AttributeSemanticType::POSITION; - attrib.emplace_back(va); - } else if (parts.GetVertexDataType() == geocalls::MultiParticleDataCall::Particles::VERTDATA_FLOAT_XYZR) { - attrib.emplace_back( - ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetVertexData()), - vertex_byte_stride * partCount, 3, ParticleDataAccessCollection::FLOAT, vertex_byte_stride, 0, - ParticleDataAccessCollection::AttributeSemanticType::POSITION}); - - attrib.emplace_back( - ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetVertexData()), - vertex_byte_stride * partCount, 1, ParticleDataAccessCollection::FLOAT, vertex_byte_stride, - 3 * ParticleDataAccessCollection::getByteSize(ParticleDataAccessCollection::FLOAT), - ParticleDataAccessCollection::AttributeSemanticType::RADIUS}); - vertex_stride = 4; - } + // process flags + if (flags_dirty) { + fcr->getData()->validateFlagCount(tot_part_count); + _enabled_vertices[i].clear(); + _enabled_colors[i].clear(); + _selected_vertices[i].clear(); + _enabled_colors[i].reserve(partCount); + _enabled_vertices[i].reserve(partCount); + _selected_vertices[i].reserve(partCount); + vertex_byte_stride = 3 * sizeof(float); + color_byte_stride = 4 * sizeof(float); + + for (int j = 0; j < partCount; j++) { + if (fcr->getData()->flags->operator[](j + offset_list[i]) == + core::FlagStorageTypes::to_integral(core::FlagStorageTypes::flag_bits::ENABLED)) { + const std::array current_pos = {parts.GetParticleStore().GetXAcc()->Get_f(j), + parts.GetParticleStore().GetYAcc()->Get_f(j), + parts.GetParticleStore().GetZAcc()->Get_f(j)}; + _enabled_vertices[i].emplace_back(current_pos); + if (parts.GetColourDataType() == geocalls::MultiParticleDataCall::Particles::COLDATA_FLOAT_RGBA) { + const std::array current_col = {parts.GetParticleStore().GetCRAcc()->Get_f(j), + parts.GetParticleStore().GetCGAcc()->Get_f(j), + parts.GetParticleStore().GetCBAcc()->Get_f(j), + parts.GetParticleStore().GetCAAcc()->Get_f(j)}; + _enabled_colors[i].emplace_back(current_col); + } + } + if (fcr->getData()->flags->operator[](j + offset_list[i]) & + core::FlagStorageTypes::to_integral(core::FlagStorageTypes::flag_bits::SELECTED)) { + const std::array current_pos = {parts.GetParticleStore().GetXAcc()->Get_f(j), + parts.GetParticleStore().GetYAcc()->Get_f(j), parts.GetParticleStore().GetZAcc()->Get_f(j)}; + _selected_vertices[i].emplace_back(current_pos); + } + } + + // process selected + if (!_selected_vertices[i].empty()) { + std::vector sel_attrib; + sel_attrib.emplace_back(ParticleDataAccessCollection::VertexAttribute{ + reinterpret_cast(_selected_vertices[i][0].data()), + vertex_byte_stride * _selected_vertices[i].size(), 3, ParticleDataAccessCollection::FLOAT, + vertex_byte_stride, 0, ParticleDataAccessCollection::AttributeSemanticType::POSITION}); + + std::string sel_identifier = std::string(FullName()) + "_spheres_selected_" + std::to_string(i); + ss.spheres->addSphereCollection( + sel_identifier, sel_attrib, parts.GetGlobalRadius(), {0.8*255.0f, 0.0f, 0.0f, 255.0f}); + } - // Color data type check - if (parts.GetColourDataType() == geocalls::MultiParticleDataCall::Particles::COLDATA_FLOAT_RGBA) { - if (parts.GetColourData() == parts.GetVertexData()) { + // process enabled + if (!_enabled_vertices[i].empty()) { + attrib.emplace_back(ParticleDataAccessCollection::VertexAttribute{ + reinterpret_cast(_enabled_vertices[i][0].data()), + vertex_byte_stride * _enabled_vertices[i].size(), 3, ParticleDataAccessCollection::FLOAT, + vertex_byte_stride, 0, ParticleDataAccessCollection::AttributeSemanticType::POSITION}); + } + + if (!_enabled_colors[i].empty()) { + attrib.emplace_back(ParticleDataAccessCollection::VertexAttribute{ + reinterpret_cast(_enabled_colors[i][0].data()), + color_byte_stride * _enabled_colors[i].size(), 4, ParticleDataAccessCollection::FLOAT, + color_byte_stride, + vertex_stride * ParticleDataAccessCollection::getByteSize(ParticleDataAccessCollection::FLOAT), + ParticleDataAccessCollection::AttributeSemanticType::COLOR}); + } + + + } else { + // Vertex data type check + if (parts.GetVertexDataType() == geocalls::MultiParticleDataCall::Particles::VERTDATA_FLOAT_XYZ) { + auto va = ParticleDataAccessCollection::VertexAttribute(); + va.data = static_cast(parts.GetVertexData()); + va.byte_size = vertex_byte_stride * partCount; + va.component_cnt = 3; + va.component_type = ParticleDataAccessCollection::FLOAT; + va.stride = vertex_byte_stride; + va.offset = 0; + va.semantic = ParticleDataAccessCollection::AttributeSemanticType::POSITION; + attrib.emplace_back(va); + } else if (parts.GetVertexDataType() == geocalls::MultiParticleDataCall::Particles::VERTDATA_FLOAT_XYZR) { attrib.emplace_back( - ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetColourData()), - color_byte_stride * partCount, 4, ParticleDataAccessCollection::FLOAT, color_byte_stride, - vertex_stride * ParticleDataAccessCollection::getByteSize(ParticleDataAccessCollection::FLOAT), - ParticleDataAccessCollection::AttributeSemanticType::COLOR}); - } else { + ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetVertexData()), + vertex_byte_stride * partCount, 3, ParticleDataAccessCollection::FLOAT, vertex_byte_stride, 0, + ParticleDataAccessCollection::AttributeSemanticType::POSITION}); + attrib.emplace_back( - ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetColourData()), - color_byte_stride * partCount, 4, ParticleDataAccessCollection::FLOAT, color_byte_stride, 0, - ParticleDataAccessCollection::AttributeSemanticType::COLOR}); + ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetVertexData()), + vertex_byte_stride * partCount, 1, ParticleDataAccessCollection::FLOAT, vertex_byte_stride, + 3 * ParticleDataAccessCollection::getByteSize(ParticleDataAccessCollection::FLOAT), + ParticleDataAccessCollection::AttributeSemanticType::RADIUS}); + vertex_stride = 4; + } + + // Color data type check + if (parts.GetColourDataType() == geocalls::MultiParticleDataCall::Particles::COLDATA_FLOAT_RGBA) { + if (parts.GetColourData() == parts.GetVertexData()) { + attrib.emplace_back( + ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetColourData()), + color_byte_stride * partCount, 4, ParticleDataAccessCollection::FLOAT, color_byte_stride, + vertex_stride * ParticleDataAccessCollection::getByteSize(ParticleDataAccessCollection::FLOAT), + ParticleDataAccessCollection::AttributeSemanticType::COLOR}); + } else { + attrib.emplace_back( + ParticleDataAccessCollection::VertexAttribute{static_cast(parts.GetColourData()), + color_byte_stride * partCount, 4, ParticleDataAccessCollection::FLOAT, color_byte_stride, 0, + ParticleDataAccessCollection::AttributeSemanticType::COLOR}); + } } } @@ -143,16 +233,28 @@ OSPRaySphereGeometry::~OSPRaySphereGeometry() { this->Release(); } + bool OSPRaySphereGeometry::create() { return true; } + void OSPRaySphereGeometry::release() {} + /* ospray::OSPRaySphereGeometry::InterfaceIsDirty() */ bool OSPRaySphereGeometry::InterfaceIsDirty() { + CallOSPRayMaterial* cm = this->getMaterialSlot.CallAs(); + bool material_dirty = false; + if (cm != nullptr) { + cm->getMaterialParameter(); + material_dirty = cm->InterfaceIsDirty(); + } + if (material_dirty) { + return true; + } return false; } diff --git a/plugins/mmospray/src/OSPRaySphereGeometry.h b/plugins/mmospray/src/OSPRaySphereGeometry.h index 5480db74eb..3b291c6530 100644 --- a/plugins/mmospray/src/OSPRaySphereGeometry.h +++ b/plugins/mmospray/src/OSPRaySphereGeometry.h @@ -59,6 +59,12 @@ class OSPRaySphereGeometry : public AbstractOSPRayStructure { /** The call for data */ core::CallerSlot getDataSlot; + + // filtered data + std::vector>> _enabled_vertices; + std::vector>> _enabled_colors; + std::vector < std::vector>> _selected_vertices; + }; } // namespace ospray diff --git a/plugins/probe/include/probe/ProbeCollection.h b/plugins/probe/include/probe/ProbeCollection.h index bf89435fae..e7357aff15 100644 --- a/plugins/probe/include/probe/ProbeCollection.h +++ b/plugins/probe/include/probe/ProbeCollection.h @@ -36,7 +36,7 @@ struct BaseProbe { /** for clustered samples */ int m_cluster_id; /** true, if clustering considers this probe to be a representant */ - bool m_representant; + bool m_representant = false; /** string id of the meshes that the probe goes through */ std::vector m_geo_ids; /** string id of the meshes that the probe goes through */ @@ -149,26 +149,9 @@ class ProbeCollection { return m_probes[idx]; } - BaseProbe getBaseProbe(size_t idx) const { - using T = std::decay_t; - if constexpr (std::is_same_v) { - FloatProbe fp = std::get(m_probes[idx]); - FloatProbe* fpp = &fp; - BaseProbe* bpp = dynamic_cast(fpp); - return *bpp; - } else if constexpr (std::is_same_v) { - IntProbe ip = std::get(m_probes[idx]); - IntProbe* ipp = &ip; - BaseProbe* bpp = dynamic_cast(ipp); - return *bpp; - } else if constexpr (std::is_same_v) { - Vec4Probe vecp = std::get(m_probes[idx]); - Vec4Probe* vecpp = &vecp; - BaseProbe* bpp = dynamic_cast(vecpp); - return *bpp; - } else { - return std::get(m_probes[idx]); - } + const BaseProbe& getBaseProbe(size_t idx) const { + const BaseProbe& x = std::visit([](const auto& x) -> const BaseProbe& { return x; }, m_probes[idx]); + return x; } uint32_t getProbeCount() const { diff --git a/plugins/probe/src/FilterProbes.cpp b/plugins/probe/src/FilterProbes.cpp new file mode 100644 index 0000000000..cf6bfb0365 --- /dev/null +++ b/plugins/probe/src/FilterProbes.cpp @@ -0,0 +1,380 @@ +/* + * FilterProbes.cpp + * Copyright (C) 2022 by MegaMol Team + * Alle Rechte vorbehalten. + */ + +#include "FilterProbes.h" +#include "glm/glm.hpp" +#include "mmadios/CallADIOSData.h" +#include "mmcore/param/ColorParam.h" +#include "mmcore/param/BoolParam.h" +#include "probe/CallKDTree.h" +#include "probe/ProbeCalls.h" + + +namespace megamol { +namespace probe { + +FilterProbes::FilterProbes() + : Module() + , _version(0) + , _probe_rhs_slot("getProbes", "") + , _probe_lhs_slot("deployMesh", "") + , _center_param("centerProbes", "") { + + this->_probe_rhs_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->_probe_rhs_slot); + + + this->_probe_lhs_slot.SetCallback( + CallProbes::ClassName(), CallProbes::FunctionName(0), &FilterProbes::getData); + this->_probe_lhs_slot.SetCallback( + CallProbes::ClassName(), CallProbes::FunctionName(1), &FilterProbes::getMetaData); + this->MakeSlotAvailable(&this->_probe_lhs_slot); + this->_probe_lhs_slot.SetNecessity(core::AbstractCallSlotPresentation::SLOT_REQUIRED); + + this->_center_param << new core::param::BoolParam(true); + this->_center_param.SetUpdateCallback(&FilterProbes::parameterChanged); + this->MakeSlotAvailable(&this->_center_param); +} + +FilterProbes::~FilterProbes() { + this->Release(); +} + +bool FilterProbes::create() { + return true; +} + +void FilterProbes::release() {} + +bool FilterProbes::getData(core::Call& call) { + + CallProbes* lhsProbesCall = dynamic_cast(&call); + if (lhsProbesCall == nullptr) + return false; + + auto rhsProbesCall = this->_probe_rhs_slot.CallAs(); + if (rhsProbesCall != nullptr) { + auto meta_data = rhsProbesCall->getMetaData(); + if (!(*rhsProbesCall)(0)) + return false; + const bool rhs_dirty = rhsProbesCall->hasUpdate(); + if (rhs_dirty || _recalc) { + ++_version; + _recalc = false; + _filtered_probe_collection = std::make_shared(); + + auto const probe_count = rhsProbesCall->getData()->getProbeCount(); + auto const probes = rhsProbesCall->getData(); + + auto minmax = probes->getGlobalMinMax(); + _filtered_probe_collection->setGlobalMinMax(minmax[0], minmax[1]); + + std::map < int, std::vector> representant_of_cluster; + + for (auto i = 0; i < probe_count; i++) { + auto generic_probe = probes->getGenericProbe(i); + + int cluster_id; + bool representant = false; + + auto visitor = [&cluster_id, &representant](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + representant = arg.m_representant; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + representant = arg.m_representant; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + representant = arg.m_representant; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + representant = arg.m_representant; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + representant = arg.m_representant; + } else { + // unknown probe type, throw error? do nothing? + } + }; + + std::visit(visitor, generic_probe); + if (representant) { + representant_of_cluster[cluster_id].emplace_back(i); + _filtered_probe_collection->addProbe(generic_probe); + } + } + + auto center_probes = _center_param.Param()->Value(); + if (center_probes) { + + // custom algorithm to find regions and determine mean probe for region + std::vector> probe_positions(probe_count); + std::map, std::vector>>> cluster_positions; + std::map> probes_with_this_clusterid; + for (auto i = 0; i < probe_count; i++) { + auto generic_probe = rhsProbesCall->getData()->getGenericProbe(i); + + int cluster_id; + std::array pos; + + auto visitor = [&cluster_id, &pos](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else if constexpr (std::is_same_v) { + cluster_id = arg.m_cluster_id; + pos = arg.m_position; + } else { + // unknown probe type, throw error? do nothing? + } + }; + + std::visit(visitor, generic_probe); + + probe_positions[i] = pos; + cluster_positions[cluster_id].first.emplace_back(i); + cluster_positions[cluster_id].second.emplace_back(pos); + probes_with_this_clusterid[cluster_id].emplace_back(i); + } + + int i = 0; + for (auto& cluster : cluster_positions) { + + auto const num_probes_in_this_cluster = cluster.second.first.size(); + std::array center_of_mass = {0,0,0}; + + for (auto& pos : cluster.second.second) { + center_of_mass[0] += pos[0]; + center_of_mass[1] += pos[1]; + center_of_mass[2] += pos[2]; + } + center_of_mass[0] /= static_cast(num_probes_in_this_cluster); + center_of_mass[1] /= static_cast(num_probes_in_this_cluster); + center_of_mass[2] /= static_cast(num_probes_in_this_cluster); + + auto kd_tree = my_kd_tree_t( + 3 /*dim*/, cluster.second.second, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + kd_tree.buildIndex(); + + std::vector ret_index(1); + std::vector sqr_dist(1); + nanoflann::KNNResultSet resultSet(1); + resultSet.init(ret_index.data(), sqr_dist.data()); + + + kd_tree.findNeighbors(resultSet, ¢er_of_mass[0], nanoflann::SearchParams()); + + auto new_probe_id = cluster.second.first[ret_index[0]]; + + newPosDir(i, new_probe_id); + + ++i; + } + +#if 0 + + // calculate middle probe distance + auto avg_dist = calculateAverageDistance(probe_positions, 10); + + // check if cluster is connected region + // generate one summed glyph for each region + for (auto& cluster : probes_with_this_clusterid) { + if (cluster.second.size() > 1) { + std::vector> cluster_positions; + cluster_positions.reserve(cluster.second.size()); + std::vector id_translator; + id_translator.reserve(cluster.second.size()); + for (auto probe_id : cluster.second) { + cluster_positions.emplace_back(probe_positions[probe_id]); + id_translator.emplace_back(probe_id); + } + + std::mt19937 rnd; + rnd.seed(std::random_device()()); + std::uniform_int_distribution dist(0, cluster.second.size()); + auto start_index = dist(rnd); + + + std::map> to_check_map; + to_check_map[start_index] = cluster_positions[start_index]; + + // store region + std::vector>> region; + + // if there is more than one re + while (!cluster_positions.empty()) { + region.emplace_back(std::map>()); + //if (!cluster_positions.empty() && to_check_map.empty()) { + // start_index = dist(rnd); + // to_check_map[start_index] = cluster_positions[start_index]; + //} + + // check connection in region + while (!to_check_map.empty()) { + + auto old_to_check_map = to_check_map; + + auto kd_tree = my_kd_tree_t( + 3 /*dim*/, cluster_positions, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + kd_tree.buildIndex(); + + + for (auto sample_point : to_check_map) { + std::vector> res; + auto num_results = kd_tree.radiusSearch( + &sample_point.second[0], 2 * avg_dist, res, nanoflann::SearchParams(10, 0.01f, true)); + + for (auto entry: res) { + to_check_map[std::get<0>(entry)] = cluster_positions[std::get<0>(entry)]; + region.back()[std::get<0>(entry)] = cluster_positions[std::get<0>(entry)]; + } + } + + // erase already checked points + for (auto old_id : old_to_check_map) { + to_check_map.erase(old_id.first); + cluster_positions.erase(std::find(cluster_positions.begin(), cluster_positions.end(), old_id.second)); + } + } + } + + + //current_probe_type sum_probe; + + } + } +#endif + } + } + } + + lhsProbesCall->setData(_filtered_probe_collection, _version); + + return true; +} + +bool FilterProbes::getMetaData(core::Call& call) { + + CallProbes* lhsProbesCall = dynamic_cast(&call); + if (lhsProbesCall == nullptr) + return false; + + auto rhsProbesCall = this->_probe_rhs_slot.CallAs(); + if (rhsProbesCall != nullptr) + return false; + + + auto rhs_meta_data = rhsProbesCall->getMetaData(); + auto lhs_meta_data = lhsProbesCall->getMetaData(); + + rhs_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; + + rhsProbesCall->setMetaData(rhs_meta_data); + if (!(*rhsProbesCall)(1)) + return false; + rhs_meta_data = rhsProbesCall->getMetaData(); + + lhs_meta_data.m_frame_cnt = rhs_meta_data.m_frame_cnt; + lhs_meta_data.m_bboxs = rhs_meta_data.m_bboxs; + + // put metadata in mesh call + lhsProbesCall->setMetaData(lhs_meta_data); + + return true; +} + +bool FilterProbes::parameterChanged(core::param::ParamSlot& p) { + _recalc = true; + return true; +} + +float FilterProbes::calculateAverageDistance(std::vector> const& input_data, int const num_neighbors) { + auto kd_tree = my_kd_tree_t(3 /*dim*/, input_data, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + kd_tree.buildIndex(); + int const num_results = num_neighbors + 1; + float distance = 0.0f; + int normalizer = 0; + for (auto& pos : input_data) { + std::vector ret_index(num_results); + std::vector sqr_dist(num_results); + nanoflann::KNNResultSet resultSet(num_results); + resultSet.init(ret_index.data(), sqr_dist.data()); + + + kd_tree.findNeighbors(resultSet, &pos[0], nanoflann::SearchParams()); + for (int i = 1; i < num_results; ++i) { + if (sqr_dist[i] > 0.0f) { + distance += std::sqrtf(sqr_dist[i]); + ++normalizer; + break; + } + } + } + + return distance / normalizer; +} + +float FilterProbes::getDistance(std::arrayconst& point1, std::array const& point2) { + return std::sqrtf( + std::powf(point2[0] - point1[0], 2) + std::powf(point2[0] - point1[0], 2) + std::powf(point2[0] - point1[0], 2)); +} + +bool FilterProbes::newPosDir(int const id_filtered, int const id_all) { + + auto all_probes = _probe_rhs_slot.CallAs()->getData(); + auto const gen_probe = all_probes->getGenericProbe(id_all); + + if (std::holds_alternative(gen_probe)) { + auto probe = all_probes->getProbe(id_all); + auto probe_f = _filtered_probe_collection->getProbe(id_filtered); + probe_f.m_begin = probe.m_begin; + probe_f.m_direction = probe.m_direction; + probe_f.m_position = probe.m_position; + probe_f.m_end = probe.m_end; + _filtered_probe_collection->setProbe(id_filtered, probe_f); + } else if (std::holds_alternative(gen_probe)) { + auto probe = all_probes->getProbe(id_all); + auto probe_f = _filtered_probe_collection->getProbe(id_filtered); + probe_f.m_begin = probe.m_begin; + probe_f.m_direction = probe.m_direction; + probe_f.m_position = probe.m_position; + probe_f.m_end = probe.m_end; + _filtered_probe_collection->setProbe(id_filtered, probe_f); + } else if (std::holds_alternative(gen_probe)) { + auto probe = all_probes->getProbe(id_all); + auto probe_f = _filtered_probe_collection->getProbe(id_filtered); + probe_f.m_begin = probe.m_begin; + probe_f.m_direction = probe.m_direction; + probe_f.m_position = probe.m_position; + probe_f.m_end = probe.m_end; + _filtered_probe_collection->setProbe(id_filtered, probe_f); + } else { + auto probe = all_probes->getProbe(id_all); + auto probe_f = _filtered_probe_collection->getProbe(id_filtered); + probe_f.m_begin = probe.m_begin; + probe_f.m_direction = probe.m_direction; + probe_f.m_position = probe.m_position; + probe_f.m_end = probe.m_end; + _filtered_probe_collection->setProbe(id_filtered, probe_f); + } + + return true; +} + +} // namespace probe +} // namespace megamol diff --git a/plugins/probe/src/SumGlyphs.h b/plugins/probe/src/FilterProbes.h similarity index 80% rename from plugins/probe/src/SumGlyphs.h rename to plugins/probe/src/FilterProbes.h index ed9115c7b3..0d2fd2cf7a 100644 --- a/plugins/probe/src/SumGlyphs.h +++ b/plugins/probe/src/FilterProbes.h @@ -1,5 +1,5 @@ /* - * SumGlyphs.h + * FilterProbes.h * Copyright (C) 2021 by MegaMol Team * Alle Rechte vorbehalten. */ @@ -22,7 +22,12 @@ namespace megamol { namespace probe { -class SumGlyphs : public core::Module { +inline glm::vec3 to_vec3(std::array const& input) { + return glm::vec3(input[0], input[1], input[2]); +} + + +class FilterProbes : public core::Module { public: /** * Answer the name of this module. @@ -30,7 +35,7 @@ class SumGlyphs : public core::Module { * @return The name of this module. */ static const char* ClassName() { - return "SumGlyphs"; + return "FilterProbes"; } /** @@ -51,8 +56,8 @@ class SumGlyphs : public core::Module { return true; } - SumGlyphs(); - virtual ~SumGlyphs(); + FilterProbes(); + virtual ~FilterProbes(); protected: virtual bool create(); @@ -60,6 +65,7 @@ class SumGlyphs : public core::Module { uint32_t _version; + core::param::ParamSlot _center_param; core::CallerSlot _probe_rhs_slot; core::CalleeSlot _probe_lhs_slot; @@ -72,8 +78,9 @@ class SumGlyphs : public core::Module { bool parameterChanged(core::param::ParamSlot& p); float calculateAverageDistance(std::vector> const& input_data, int const num_neighbors); float getDistance(std::array const& point1, std::array const& point2); + bool newPosDir(int const id_filtered, int const id_all); - std::shared_ptr _sum_probe_collection; + std::shared_ptr _filtered_probe_collection; bool _recalc; }; diff --git a/plugins/probe/src/PlaceProbes.cpp b/plugins/probe/src/PlaceProbes.cpp index 6cd0ba8552..721544b605 100644 --- a/plugins/probe/src/PlaceProbes.cpp +++ b/plugins/probe/src/PlaceProbes.cpp @@ -26,6 +26,7 @@ megamol::probe::PlaceProbes::PlaceProbes() , _probe_positions_slot("deployProbePositions", "Safe probe positions to a file") , _load_probe_positions_slot("loadProbePositions", "Load saved probe positions") , _scale_probe_begin_slot("distanceFromSurfaceFactor", "") + , _override_probe_length_slot("overrideProbeLength", "") , _longest_edge_index(0) { this->_probe_slot.SetCallback(CallProbes::ClassName(), CallProbes::FunctionName(0), &PlaceProbes::getData); @@ -60,6 +61,12 @@ megamol::probe::PlaceProbes::PlaceProbes() this->_probes_per_unit_slot << new core::param::FloatParam(1, 0); + this->_probes_per_unit_slot.SetUpdateCallback(&PlaceProbes::parameterChanged); + this->MakeSlotAvailable(&this->_probes_per_unit_slot); + + this->_override_probe_length_slot << new core::param::FloatParam(0); + this->_override_probe_length_slot.SetUpdateCallback(&PlaceProbes::parameterChanged); + this->MakeSlotAvailable(&this->_override_probe_length_slot); this->_scale_probe_begin_slot << new core::param::FloatParam(1.0f); this->_scale_probe_begin_slot.SetUpdateCallback(&PlaceProbes::parameterChanged); @@ -890,6 +897,13 @@ bool megamol::probe::PlaceProbes::placeByCenterpoint() { normal[1] /= normal_length; normal[2] /= normal_length; + auto override_length = _override_probe_length_slot.Param() + ->Value(); + + if (override_length > 0.0f){ + normal_length = override_length; + } + probe.m_position = { probe_accessor[probe_step * i + 0], probe_accessor[probe_step * i + 1], probe_accessor[probe_step * i + 2]}; probe.m_direction = normal; diff --git a/plugins/probe/src/PlaceProbes.h b/plugins/probe/src/PlaceProbes.h index 40b3b8bf65..e3b5953e8b 100644 --- a/plugins/probe/src/PlaceProbes.h +++ b/plugins/probe/src/PlaceProbes.h @@ -73,6 +73,7 @@ class PlaceProbes : public core::Module { core::param::ParamSlot _method_slot; core::param::ParamSlot _probes_per_unit_slot; core::param::ParamSlot _scale_probe_begin_slot; + core::param::ParamSlot _override_probe_length_slot; private: diff --git a/plugins/probe/src/ProbeClustering.cpp b/plugins/probe/src/ProbeClustering.cpp index b21c3f6e1d..0ee77b3d26 100644 --- a/plugins/probe/src/ProbeClustering.cpp +++ b/plugins/probe/src/ProbeClustering.cpp @@ -53,7 +53,7 @@ megamol::probe::ProbeClustering::ProbeClustering() _print_debug_info_slot.SetUpdateCallback(&ProbeClustering::print_debug_info); MakeSlotAvailable(&_print_debug_info_slot); - _toggle_reps_slot << new core::param::BoolParam(false); + _toggle_reps_slot << new core::param::BoolParam(true); MakeSlotAvailable(&_toggle_reps_slot); _angle_threshold_slot << new core::param::FloatParam(45.0f, 0.0f); @@ -275,6 +275,44 @@ bool megamol::probe::ProbeClustering::get_data_cb(core::Call& c) { bool toggle_reps = _toggle_reps_slot.Param()->Value(); if (toggle_reps) { + auto const num_probes = _probes->getProbeCount(); + // reset representant flag + bool vec_probe = false; + bool distrib_probe = false; + bool float_probe = false; + { + auto const test_probe = _probes->getGenericProbe(0); + vec_probe = std::holds_alternative(test_probe); + distrib_probe = std::holds_alternative(test_probe); + float_probe = std::holds_alternative(test_probe); + } + if (vec_probe) { + for (int i = 0; i < num_probes; ++i) { + auto probe = _probes->getProbe(i); + probe.m_representant = false; + _probes->setProbe(i, probe); + } + } else if (distrib_probe) { + for (int i = 0; i < num_probes; ++i) { + auto probe = _probes->getProbe(i); + probe.m_representant = false; + _probes->setProbe(i, probe); + } + } else if (float_probe) { + for (int i = 0; i < num_probes; ++i) { + auto probe = _probes->getProbe(i); + probe.m_representant = false; + _probes->setProbe(i, probe); + } + } else { + for (int i = 0; i < num_probes; ++i) { + auto probe = _probes->getProbe(i); + probe.m_representant = false; + _probes->setProbe(i, probe); + } + } + + std::unordered_map> cluster_map; cluster_map.reserve(*max_el); @@ -302,13 +340,6 @@ bool megamol::probe::ProbeClustering::get_data_cb(core::Call& c) { cluster_reps.push_back(min_idx); } - bool vec_probe = false; - bool distrib_probe = false; - { - auto const test_probe = _probes->getGenericProbe(0); - vec_probe = std::holds_alternative(test_probe); - distrib_probe = std::holds_alternative(test_probe); - } if (vec_probe) { for (auto const& el : cluster_reps) { auto probe = _probes->getProbe(el); @@ -321,12 +352,18 @@ bool megamol::probe::ProbeClustering::get_data_cb(core::Call& c) { probe.m_representant = true; _probes->setProbe(el, probe); } - } else { + } else if (float_probe) { for (auto const& el : cluster_reps) { auto probe = _probes->getProbe(el); probe.m_representant = true; _probes->setProbe(el, probe); } + } else { + for (auto const& el : cluster_reps) { + auto probe = _probes->getProbe(el); + probe.m_representant = true; + _probes->setProbe(el, probe); + } } /*std::vector indicator(probes->getProbeCount(), 1); for (auto const& el : cluster_reps) { diff --git a/plugins/probe/src/SumGlyphs.cpp b/plugins/probe/src/SumGlyphs.cpp deleted file mode 100644 index 05214a04f6..0000000000 --- a/plugins/probe/src/SumGlyphs.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * SumGlyphs.cpp - * Copyright (C) 2021 by MegaMol Team - * Alle Rechte vorbehalten. - */ - -#include "SumGlyphs.h" -#include "glm/glm.hpp" -#include "mmadios/CallADIOSData.h" -#include "mmcore/param/ColorParam.h" -#include "mmcore/param/EnumParam.h" -#include "probe/CallKDTree.h" -#include "probe/ProbeCalls.h" - - -namespace megamol { -namespace probe { - -SumGlyphs::SumGlyphs() - : Module() - , _version(0) - , _probe_rhs_slot("getProbes", "") - , _probe_lhs_slot("deployMesh", "") { - - this->_probe_rhs_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->_probe_rhs_slot); - - - this->_probe_lhs_slot.SetCallback( - CallProbes::ClassName(), CallProbes::FunctionName(0), &SumGlyphs::getData); - this->_probe_lhs_slot.SetCallback( - CallProbes::ClassName(), CallProbes::FunctionName(1), &SumGlyphs::getMetaData); - this->MakeSlotAvailable(&this->_probe_lhs_slot); - this->_probe_lhs_slot.SetNecessity(core::AbstractCallSlotPresentation::SLOT_REQUIRED); -} - -SumGlyphs::~SumGlyphs() { - this->Release(); -} - -bool SumGlyphs::create() { - return true; -} - -void SumGlyphs::release() {} - -bool SumGlyphs::getData(core::Call& call) { - - CallProbes* lhsProbesCall = dynamic_cast(&call); - if (lhsProbesCall == nullptr) - return false; - - if (!(*lhsProbesCall)(0)) - return false; - const bool lhs_dirty = lhsProbesCall->hasUpdate(); - - auto rhsProbesCall = this->_probe_rhs_slot.CallAs(); - if (rhsProbesCall != nullptr) { - auto meta_data = rhsProbesCall->getMetaData(); - if (!(*rhsProbesCall)(0)) - return false; - const bool rhs_dirty = rhsProbesCall->hasUpdate(); - if (rhs_dirty || lhs_dirty) { - ++_version; - _sum_probe_collection = std::make_shared(); - - auto const probe_count = rhsProbesCall->getData()->getProbeCount(); - auto const probes = rhsProbesCall->getData(); - std::vector> probe_positions(probe_count); - std::map> probes_with_this_clusterid; - for (auto i = 0; i < probe_count; i++) { - auto generic_probe = rhsProbesCall->getData()->getGenericProbe(i); - - int cluster_id; - std::array pos; - - auto visitor = [&cluster_id, &pos](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - cluster_id = arg.m_cluster_id; - pos = arg.m_position; - } else if constexpr (std::is_same_v) { - cluster_id = arg.m_cluster_id; - pos = arg.m_position; - } else if constexpr (std::is_same_v) { - cluster_id = arg.m_cluster_id; - pos = arg.m_position; - } else if constexpr (std::is_same_v) { - cluster_id = arg.m_cluster_id; - pos = arg.m_position; - } else if constexpr (std::is_same_v) { - cluster_id = arg.m_cluster_id; - pos = arg.m_position; - } else { - // unknown probe type, throw error? do nothing? - } - }; - - std::visit(visitor, generic_probe); - - probe_positions[i] = pos; - probes_with_this_clusterid[cluster_id].emplace_back(i); - } - using current_probe_type = std::decay_tgetGenericProbe(0))>; - - - // calculate middle probe distance - auto avg_dist = calculateAverageDistance(probe_positions, 2); - - // check if cluster is connected region - // generate one summed glyph for each region - for (auto& cluster : probes_with_this_clusterid) { - if (cluster.second.size() > 1) { - std::vector> cluster_positions; - cluster_positions.reserve(cluster.second.size()); - std::vector id_translator; - id_translator.reserve(cluster.second.size()); - for (auto probe_id : cluster.second) { - cluster_positions.emplace_back(probe_positions[probe_id]); - id_translator.emplace_back(probe_id); - } - - std::mt19937 rnd; - rnd.seed(std::random_device()()); - std::uniform_int_distribution dist(0, cluster.second.size()); - auto start_index = dist(rnd); - - - std::map> to_check_map; - to_check_map[start_index] = cluster_positions[start_index]; - - // store region - std::vector>> region; - - while (!cluster_positions.empty()) { - region.emplace_back(std::map>()); - while (!to_check_map.empty()) { - - auto old_to_check_map = to_check_map; - - auto kd_tree = my_kd_tree_t( - 3 /*dim*/, cluster_positions, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); - kd_tree.buildIndex(); - - - for (auto sample_point : to_check_map) { - std::vector> res; - auto num_results = kd_tree.radiusSearch( - &sample_point.second[0], 2 * avg_dist, res, nanoflann::SearchParams(10, 0.01f, true)); - - for (auto entry: res) { - to_check_map[std::get<0>(entry)] = cluster_positions[std::get<0>(entry)]; - region.back()[std::get<0>(entry)] = cluster_positions[std::get<0>(entry)]; - } - } - - // erase already checked points - for (auto old_id : old_to_check_map) { - to_check_map.erase(old_id.first); - cluster_positions.erase(std::find(cluster_positions.begin(), cluster_positions.end(), old_id.second)); - } - } - } - - - //current_probe_type sum_probe; - - - } else { - _sum_probe_collection->addProbe(probes->getProbe(cluster.second[0])); - } - } - - - - } - } - - lhsProbesCall->setData(_sum_probe_collection, _version); - - return true; -} - -bool SumGlyphs::getMetaData(core::Call& call) { - - CallProbes* lhsProbesCall = dynamic_cast(&call); - if (lhsProbesCall == nullptr) - return false; - - auto rhsProbesCall = this->_probe_rhs_slot.CallAs(); - if (rhsProbesCall != nullptr) - return false; - - - auto rhs_meta_data = rhsProbesCall->getMetaData(); - auto lhs_meta_data = lhsProbesCall->getMetaData(); - - rhs_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; - - rhsProbesCall->setMetaData(rhs_meta_data); - if (!(*rhsProbesCall)(1)) - return false; - rhs_meta_data = rhsProbesCall->getMetaData(); - - lhs_meta_data.m_frame_cnt = rhs_meta_data.m_frame_cnt; - lhs_meta_data.m_bboxs = rhs_meta_data.m_bboxs; - - // put metadata in mesh call - lhsProbesCall->setMetaData(lhs_meta_data); - - return true; -} - -bool SumGlyphs::parameterChanged(core::param::ParamSlot& p) { - _recalc = true; - return true; -} - -float SumGlyphs::calculateAverageDistance(std::vector> const& input_data, int const num_neighbors) { - auto kd_tree = my_kd_tree_t(3 /*dim*/, input_data, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); - kd_tree.buildIndex(); - int const num_results = num_neighbors + 1; - float distance = 0.0f; - for (auto& pos : input_data) { - std::vector ret_index(num_results); - std::vector sqr_dist(num_results); - nanoflann::KNNResultSet resultSet(num_results); - resultSet.init(ret_index.data(), sqr_dist.data()); - - - kd_tree.findNeighbors(resultSet, &pos[0], nanoflann::SearchParams(10)); - for (int i = 1; i < num_results; ++i) { - distance += std::sqrtf(sqr_dist[i]); - } - } - - return distance / static_cast(input_data.size()*num_neighbors); -} - -float SumGlyphs::getDistance(std::arrayconst& point1, std::array const& point2) { - return std::sqrtf( - std::powf(point2[0] - point1[0], 2) + std::powf(point2[0] - point1[0], 2) + std::powf(point2[0] - point1[0], 2)); -} - -} // namespace probe -} // namespace megamol diff --git a/plugins/probe/src/probe.cpp b/plugins/probe/src/probe.cpp index bad86478b6..2cb61df76b 100644 --- a/plugins/probe/src/probe.cpp +++ b/plugins/probe/src/probe.cpp @@ -31,7 +31,7 @@ #include "ReconstructSurface.h" #include "TableToProbes.h" #include "TessellateBoundingBox.h" -#include "SumGlyphs.h" +#include "FilterProbes.h" namespace megamol::probe { class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { @@ -70,7 +70,7 @@ class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPlug this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); // register calls From 5e2997f3fae6629f1d0f99fab49ba703a89a5be5 Mon Sep 17 00:00:00 2001 From: invor Date: Fri, 24 Jun 2022 14:32:25 +0200 Subject: [PATCH 10/47] Added icosphere to MeshBakery --- plugins/mesh/src/MeshBakery.cpp | 165 +++++++++++++++++++++++++++----- plugins/mesh/src/MeshBakery.h | 8 ++ 2 files changed, 150 insertions(+), 23 deletions(-) diff --git a/plugins/mesh/src/MeshBakery.cpp b/plugins/mesh/src/MeshBakery.cpp index 69a0a2039e..c0e342c48e 100644 --- a/plugins/mesh/src/MeshBakery.cpp +++ b/plugins/mesh/src/MeshBakery.cpp @@ -1,19 +1,33 @@ #include "MeshBakery.h" +#include + #include "mmcore/param/EnumParam.h" +#include "mmcore/param/FloatParam.h" +#include "mmcore/param/IntParam.h" megamol::mesh::MeshBakery::MeshBakery() : AbstractMeshDataSource() , m_version(0) - , m_geometry_type("GeometryType", "...") { - this->m_geometry_type << new megamol::core::param::EnumParam(0); - this->m_geometry_type.Param()->SetTypePair(0, "Quad"); - this->m_geometry_type.Param()->SetTypePair(1, "Cone"); - this->MakeSlotAvailable(&this->m_geometry_type); + , m_geometry_type("GeometryType", "...") + , m_icosphere_radius("IcosphereRadius","...") + , m_icosphere_subdivs("IcosphereSubdivs", "") +{ + m_geometry_type << new megamol::core::param::EnumParam(2); + m_geometry_type.Param()->SetTypePair(0, "Quad"); + m_geometry_type.Param()->SetTypePair(1, "Cone"); + m_geometry_type.Param()->SetTypePair(2, "Icosphere"); + MakeSlotAvailable(&m_geometry_type); + + m_icosphere_radius << new megamol::core::param::FloatParam(1.0f,0.0f); + MakeSlotAvailable(&m_icosphere_radius); + + m_icosphere_subdivs << new megamol::core::param::IntParam(0,0); + MakeSlotAvailable(&m_icosphere_subdivs); } megamol::mesh::MeshBakery::~MeshBakery() { - this->Release(); + Release(); } bool megamol::mesh::MeshBakery::create(void) { @@ -44,40 +58,55 @@ bool megamol::mesh::MeshBakery::getMeshDataCallback(core::Call& caller) { } } - if (m_geometry_type.IsDirty()) { + bool something_has_changed = + m_geometry_type.IsDirty() || m_icosphere_radius.IsDirty() || m_icosphere_subdivs.IsDirty(); + + if (m_vertex_positions.empty() || something_has_changed) { + //TODO bad move, but necessary right now. chaining is broken with this + clearMeshAccessCollection(); + m_geometry_type.ResetDirty(); + m_icosphere_radius.ResetDirty(); + m_icosphere_subdivs.ResetDirty(); ++m_version; + std::array bbox; + + // init default bounding box + bbox[0] = -1.0f; + bbox[1] = -1.0f; + bbox[2] = -1.0f; + bbox[3] = 1.0f; + bbox[4] = 1.0f; + bbox[5] = 1.0f; + auto geometry_type = m_geometry_type.Param()->Value(); //TODO call geometry generating functions switch (geometry_type) { case 0: + m_icosphere_radius.Param()->SetGUIVisible(false); + m_icosphere_subdivs.Param()->SetGUIVisible(false); break; case 1: + m_icosphere_radius.Param()->SetGUIVisible(false); + m_icosphere_subdivs.Param()->SetGUIVisible(false); createConeGeometry(); break; + case 2: + m_icosphere_radius.Param()->SetGUIVisible(true); + m_icosphere_subdivs.Param()->SetGUIVisible(true); + createIcosphereGeometry(m_icosphere_radius.Param()->Value(), + static_cast(m_icosphere_subdivs.Param()->Value())); + for (auto& val : bbox) { + val *= m_icosphere_radius.Param()->Value(); + } + break; default: break; } - std::array bbox; - - bbox[0] = std::numeric_limits::max(); - bbox[1] = std::numeric_limits::max(); - bbox[2] = std::numeric_limits::max(); - bbox[3] = std::numeric_limits::min(); - bbox[4] = std::numeric_limits::min(); - bbox[5] = std::numeric_limits::min(); - - bbox[0] = -1.0f; - bbox[1] = -1.0f; - bbox[2] = -1.0f; - bbox[3] = 1.0f; - bbox[4] = 1.0f; - bbox[5] = 1.0f; - std::vector mesh_attributes; MeshDataAccessCollection::IndexData mesh_indices; @@ -200,3 +229,93 @@ void megamol::mesh::MeshBakery::createConeGeometry() { m_indices.push_back(i + segments); } } + +void megamol::mesh::MeshBakery::createIcosphereGeometry(float radius, unsigned int subdivisions) { + + m_vertex_positions.clear(); + m_vertex_normals.clear(); + m_vertex_tangents.clear(); + m_vertex_uvs.clear(); + m_vertex_colors.clear(); + m_indices.clear(); + + // Create intial icosahedron + float x = 0.525731112119133606f * radius; + float z = 0.850650808352039932f * radius; + float nx = 0.525731112119133606f; + float nz = 0.850650808352039932f; + + m_vertex_positions = {-x, 0.0f, z, x, 0.0f, z, -x, 0.0f, -z, x, 0.0f, -z, 0.0f, z, x, 0.0f, z, -x, 0.0f, -z, x, + 0.0f, -z, -x, z, x, 0.0f, -z, x, 0.0f, z, -x, 0.0f, -z, -x, 0.0f}; + m_vertex_normals = {-nx, 0.0f, nz, nx, 0.0f, nz, -nx, 0.0f, -nz, nx, 0.0f, -nz, 0.0f, nz, nx, 0.0f, nz, -nx, 0.0f, + -nz, nx, 0.0f, -nz, -nx, nz, nx, 0.0f, -nz, nx, 0.0f, nz, -nx, 0.0f, -nz, -nx, 0.0f}; + m_indices = {0, 4, 1, 0, 9, 4, 9, 5, 4, 4, 5, 8, 4, 8, 1, 8, 10, 1, 8, 3, 10, 5, 3, 8, 5, 2, 3, 2, 7, 3, 7, 10, 3, + 7, 6, 10, 7, 11, 6, 11, 0, 6, 0, 1, 6, 6, 1, 10, 9, 0, 11, 9, 11, 2, 9, 2, 5, 7, 2, 11}; + + // Subdivide icosahedron + for (unsigned int subdivs = 0; subdivs < subdivisions; subdivs++) { + std::vector refined_indices; + refined_indices.reserve(m_indices.size() * 3); + + for (int i = 0; i < m_indices.size(); i = i + 3) { + unsigned int idx1 = m_indices[i]; + unsigned int idx2 = m_indices[i + 1]; + unsigned int idx3 = m_indices[i + 2]; + + glm::vec3 newVtx1((m_vertex_positions[idx1 * 3 + 0] + m_vertex_positions[idx2 * 3 + 0]), + (m_vertex_positions[idx1 * 3 + 1] + m_vertex_positions[idx2 * 3 + 1]), + (m_vertex_positions[idx1 * 3 + 2] + m_vertex_positions[idx2 * 3 + 2])); + newVtx1 = glm::normalize(newVtx1); + newVtx1 *= radius; + + glm::vec3 newVtx2((m_vertex_positions[idx2 * 3 + 0] + m_vertex_positions[idx3 * 3 + 0]), + (m_vertex_positions[idx2 * 3 + 1] + m_vertex_positions[idx3 * 3 + 1]), + (m_vertex_positions[idx2 * 3 + 2] + m_vertex_positions[idx3 * 3 + 2])); + newVtx2 = glm::normalize(newVtx2); + newVtx2 *= radius; + + glm::vec3 newVtx3((m_vertex_positions[idx3 * 3 + 0] + m_vertex_positions[idx1 * 3 + 0]), + (m_vertex_positions[idx3 * 3 + 1] + m_vertex_positions[idx1 * 3 + 1]), + (m_vertex_positions[idx3 * 3 + 2] + m_vertex_positions[idx1 * 3 + 2])); + newVtx3 = glm::normalize(newVtx3); + newVtx3 *= radius; + + glm::vec3 newVtxNrml1((m_vertex_normals[idx1 * 3 + 0] + m_vertex_normals[idx2 * 3 + 0]), + (m_vertex_normals[idx1 * 3 + 1] + m_vertex_normals[idx2 * 3 + 1]), + (m_vertex_normals[idx1 * 3 + 2] + m_vertex_normals[idx2 * 3 + 2])); + newVtxNrml1 = glm::normalize(newVtx1); + + glm::vec3 newVtxNrml2((m_vertex_normals[idx2 * 3 + 0] + m_vertex_normals[idx3 * 3 + 0]), + (m_vertex_normals[idx2 * 3 + 1] + m_vertex_normals[idx3 * 3 + 1]), + (m_vertex_normals[idx2 * 3 + 2] + m_vertex_normals[idx3 * 3 + 2])); + newVtxNrml2 = glm::normalize(newVtx2); + + glm::vec3 newVtxNrml3((m_vertex_normals[idx3 * 3 + 0] + m_vertex_normals[idx1 * 3 + 0]), + (m_vertex_normals[idx3 * 3 + 1] + m_vertex_normals[idx1 * 3 + 1]), + (m_vertex_normals[idx3 * 3 + 2] + m_vertex_normals[idx1 * 3 + 2])); + newVtxNrml3 = glm::normalize(newVtx3); + + unsigned int newIdx1 = static_cast(m_vertex_positions.size() / 3); + m_vertex_positions.insert(m_vertex_positions.end(), {newVtx1.x, newVtx1.y, newVtx1.z}); + m_vertex_normals.insert(m_vertex_normals.end(), {newVtxNrml1.x, newVtxNrml1.y, newVtxNrml1.z}); + + unsigned int newIdx2 = newIdx1 + 1; + m_vertex_positions.insert(m_vertex_positions.end(), {newVtx2.x, newVtx2.y, newVtx2.z}); + m_vertex_normals.insert(m_vertex_normals.end(), {newVtxNrml2.x, newVtxNrml2.y, newVtxNrml2.z}); + + unsigned int newIdx3 = newIdx2 + 1; + m_vertex_positions.insert(m_vertex_positions.end(), {newVtx3.x, newVtx3.y, newVtx3.z}); + m_vertex_normals.insert(m_vertex_normals.end(), {newVtxNrml3.x, newVtxNrml3.y, newVtxNrml3.z}); + + refined_indices.insert(refined_indices.end(), + {idx1, newIdx1, newIdx3, newIdx1, idx2, newIdx2, newIdx3, newIdx1, newIdx2, newIdx3, newIdx2, idx3}); + } + + m_indices.clear(); + m_indices = refined_indices; + } + + // fill unused attributes with zeros for now + m_vertex_tangents.resize(m_vertex_normals.size()); + m_vertex_uvs.resize((m_vertex_normals.size() / 3) * 2); +} diff --git a/plugins/mesh/src/MeshBakery.h b/plugins/mesh/src/MeshBakery.h index 09c8104f46..0a6b904501 100644 --- a/plugins/mesh/src/MeshBakery.h +++ b/plugins/mesh/src/MeshBakery.h @@ -73,6 +73,8 @@ class MeshBakery : public AbstractMeshDataSource { void createConeGeometry(); + void createIcosphereGeometry(float radius, unsigned int subdivisions); + uint32_t m_version; std::vector m_vertex_positions; @@ -85,6 +87,12 @@ class MeshBakery : public AbstractMeshDataSource { /** Parameter for selecting the geometry to be generated */ megamol::core::param::ParamSlot m_geometry_type; + + /** Parameter for setting icosphere radius */ + megamol::core::param::ParamSlot m_icosphere_radius; + + /** Parameter for setting icosphere subdivisions */ + megamol::core::param::ParamSlot m_icosphere_subdivs; }; } // namespace mesh From 46718b6fed28bef59fe46f4d8b212f615059d25b Mon Sep 17 00:00:00 2001 From: rauts Date: Thu, 14 Jul 2022 20:00:57 +0200 Subject: [PATCH 11/47] added spherical volume, changed structure and extension map to only hold reference of each container --- .../include/mmospray/CallOSPRayStructure.h | 15 +- .../mmospray/src/AbstractOSPRayRenderer.cpp | 123 +++---- .../mmospray/src/AbstractOSPRayStructure.cpp | 4 +- plugins/mmospray/src/CallOSPRayStructure.cpp | 10 +- plugins/mmospray/src/OSPRayAPIStructure.cpp | 1 - plugins/mmospray/src/OSPRayLineGeometry.cpp | 2 - plugins/mmospray/src/OSPRayRenderer.cpp | 42 +-- plugins/mmospray/src/OSPRaySphereGeometry.cpp | 1 - .../mmospray/src/OSPRaySphericalVolume.cpp | 299 ++++++++++++++++++ plugins/mmospray/src/OSPRaySphericalVolume.h | 80 +++++ .../mmospray/src/OSPRayStructuredVolume.cpp | 3 +- plugins/mmospray/src/mmospray.cpp | 54 ++-- 12 files changed, 514 insertions(+), 120 deletions(-) create mode 100644 plugins/mmospray/src/OSPRaySphericalVolume.cpp create mode 100644 plugins/mmospray/src/OSPRaySphericalVolume.h diff --git a/plugins/mmospray/include/mmospray/CallOSPRayStructure.h b/plugins/mmospray/include/mmospray/CallOSPRayStructure.h index fa7b0d1485..b824d45d40 100644 --- a/plugins/mmospray/include/mmospray/CallOSPRayStructure.h +++ b/plugins/mmospray/include/mmospray/CallOSPRayStructure.h @@ -23,7 +23,7 @@ enum structureTypeEnum { UNINITIALIZED, GEOMETRY, VOLUME, OSPRAY_API_STRUCTURES enum geometryTypeEnum { SPHERES, MESH, LINES, CURVES, CYLINDERS, TEST }; -enum volumeTypeEnum { STRUCTUREDVOLUME, BLOCKBRICKEDVOLUME, GHOSTBLOCKBRICKEDVOLUME }; +enum volumeTypeEnum { STRUCTUREDVOLUME, BLOCKBRICKEDVOLUME, GHOSTBLOCKBRICKEDVOLUME, SPHERICALVOLUME }; enum volumeRepresentationType { VOLUMEREP, ISOSURFACE, SLICE }; @@ -45,12 +45,13 @@ struct sphereStructure { std::shared_ptr spheres; }; -struct structuredVolumeStructure { +struct volumeStructure { std::shared_ptr> tfRGB; std::shared_ptr> tfA; std::array valueRange; const void* voxels; + std::shared_ptr> voxels_shared; std::array gridOrigin; std::array gridSpacing; std::array dimensions; @@ -107,7 +108,7 @@ struct OSPRayStructureContainer { ClippingPlane clippingPlane; bool clippingPlaneChanged = false; - std::variant structure; + std::variant structure; }; @@ -123,8 +124,8 @@ class OSPRayExtendContainer { class CallOSPRayStructure; -typedef std::map OSPRayStrcutrureMap; -typedef std::map OSPRayExtendMap; +typedef std::map OSPRayStrcutrureMap; +typedef std::map OSPRayExtendMap; class CallOSPRayStructure : public megamol::core::Call { @@ -190,11 +191,11 @@ class CallOSPRayStructure : public megamol::core::Call { CallOSPRayStructure& operator=(const CallOSPRayStructure& rhs); void setStructureMap(OSPRayStrcutrureMap* sm); - void addStructure(OSPRayStructureContainer& sc); + void addStructure(OSPRayStructureContainer* sc); bool fillStructureMap(); void setExtendMap(OSPRayExtendMap* em); - void addExtend(OSPRayExtendContainer& ec); + void addExtend(OSPRayExtendContainer* ec); bool fillExtendMap(); void setTime(float time); diff --git a/plugins/mmospray/src/AbstractOSPRayRenderer.cpp b/plugins/mmospray/src/AbstractOSPRayRenderer.cpp index fb3eb4b304..a624e7fdec 100644 --- a/plugins/mmospray/src/AbstractOSPRayRenderer.cpp +++ b/plugins/mmospray/src/AbstractOSPRayRenderer.cpp @@ -570,7 +570,7 @@ void AbstractOSPRayRenderer::fillMaterialContainer( void AbstractOSPRayRenderer::changeMaterial() { - for (auto entry : this->_structureMap) { + for (auto& entry : _structureMap) { auto const& element = entry.second; // custom material settings @@ -578,13 +578,13 @@ void AbstractOSPRayRenderer::changeMaterial() { //ospRelease(this->_materials[entry.first]); this->_materials.erase(entry.first); } - if (element.materialContainer != NULL) { - fillMaterialContainer(entry.first, element); + if (element->materialContainer != NULL) { + fillMaterialContainer(entry.first, *element); _materials[entry.first].commit(); } if (this->_materials[entry.first] != NULL) { - if (element.type == structureTypeEnum::GEOMETRY) { + if (element->type == structureTypeEnum::GEOMETRY) { _geometricModels[entry.first].back().setParam( "material", ::ospray::cpp::CopiedData(_materials[entry.first])); _geometricModels[entry.first].back().commit(); @@ -597,10 +597,10 @@ void AbstractOSPRayRenderer::changeMaterial() { void AbstractOSPRayRenderer::changeTransformation() { - for (auto& entry : this->_baseStructures) { - if (this->_structureMap[entry.first].transformationContainer == nullptr) + for (auto& entry : _baseStructures) { + if (_structureMap[entry.first]->transformationContainer == nullptr) continue; - auto trafo = this->_structureMap[entry.first].transformationContainer; + auto trafo = _structureMap[entry.first]->transformationContainer; ::rkcommon::math::affine3f xfm; xfm.p.x = trafo->pos[0]; xfm.p.y = trafo->pos[1]; @@ -629,13 +629,14 @@ bool AbstractOSPRayRenderer::generateRepresentations() { std::vector<::rkcommon::math::box3f> ghostRegions; std::vector<::rkcommon::math::box3f> regions; - for (auto& entry : this->_structureMap) { + for (auto& entry : _structureMap) { _numCreateGeo = 1; - auto const& element = entry.second; + auto& element = entry.second; // check if structure should be released first - if (element.dataChanged) { + if (element->dataChanged) { + element->dataChanged = false; //for (int i = 0; i < _baseStructures[entry.first].size(); ++i) { // if (_baseStructures[entry.first].types[i] == structureTypeEnum::GEOMETRY) { // ospRelease(std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures[i]).handle()); @@ -679,18 +680,18 @@ bool AbstractOSPRayRenderer::generateRepresentations() { if (_materials[entry.first]) { _materials.erase(entry.first); } - if (element.materialContainer && + if (element->materialContainer && this->_rd_type.Param()->Value() != MPI_RAYCAST) { - fillMaterialContainer(entry.first, element); + fillMaterialContainer(entry.first, *element); _materials[entry.first].commit(); } - switch (element.type) { + switch (element->type) { case structureTypeEnum::UNINITIALIZED: break; case structureTypeEnum::OSPRAY_API_STRUCTURES: { - auto& container = std::get(element.structure); + auto& container = std::get(element->structure); if (container.ospStructures.first.empty()) { // returnValue = false; break; @@ -736,7 +737,7 @@ bool AbstractOSPRayRenderer::generateRepresentations() { _groups[entry.first].commit(); } break; case structureTypeEnum::GEOMETRY: - switch (element.geometryType) { + switch (element->geometryType) { case geometryTypeEnum::TEST: using namespace rkcommon::math; @@ -771,7 +772,7 @@ bool AbstractOSPRayRenderer::generateRepresentations() { break; case geometryTypeEnum::SPHERES: { - auto& container = std::get(element.structure); + auto& container = std::get(element->structure); if (container.spheres == NULL) { core::utility::log::Log::DefaultLog.WriteError( "[OSPRay:generateRepresentations] Representation SPHERES active but no data provided."); @@ -852,7 +853,7 @@ bool AbstractOSPRayRenderer::generateRepresentations() { } // end for num geometies } break; case geometryTypeEnum::MESH: { - auto& container = std::get(element.structure); + auto& container = std::get(element->structure); if (container.mesh == NULL) { core::utility::log::Log::DefaultLog.WriteError( "[OSPRay:generateRepresentations] Representation MESH active but no data provided."); @@ -1009,7 +1010,7 @@ bool AbstractOSPRayRenderer::generateRepresentations() { } break; case geometryTypeEnum::LINES: case geometryTypeEnum::CURVES: { - auto& container = std::get(element.structure); + auto& container = std::get(element->structure); if (container.vertexData == nullptr && container.mesh == nullptr) { // returnValue = false; core::utility::log::Log::DefaultLog.WriteError( @@ -1131,14 +1132,14 @@ bool AbstractOSPRayRenderer::generateRepresentations() { _groups[entry.first] = ::ospray::cpp::Group(); _groups[entry.first].setParam("geometry", ::ospray::cpp::CopiedData(_geometricModels[entry.first])); - if (entry.second.clippingPlane.isValid) { + if (entry.second->clippingPlane.isValid) { _baseStructures[entry.first].emplace_back(::ospray::cpp::Geometry("plane"), GEOMETRY); ::rkcommon::math::vec4f plane; - plane[0] = entry.second.clippingPlane.coeff[0]; - plane[1] = entry.second.clippingPlane.coeff[1]; - plane[2] = entry.second.clippingPlane.coeff[2]; - plane[3] = entry.second.clippingPlane.coeff[3]; + plane[0] = entry.second->clippingPlane.coeff[0]; + plane[1] = entry.second->clippingPlane.coeff[1]; + plane[2] = entry.second->clippingPlane.coeff[2]; + plane[3] = entry.second->clippingPlane.coeff[3]; std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()) .setParam("plane.coefficients", ::ospray::cpp::CopiedData(plane)); std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()).commit(); @@ -1154,47 +1155,63 @@ bool AbstractOSPRayRenderer::generateRepresentations() { break; case structureTypeEnum::VOLUME: { - auto& container = std::get(element.structure); - if (container.voxels == NULL) { - core::utility::log::Log::DefaultLog.WriteError( - "[OSPRay:generateRepresentations] Representation VOLUME active but no data provided."); - break; + auto& container = std::get(element->structure); + switch (element->volumeType) { + case volumeTypeEnum::STRUCTUREDVOLUME: { + + if (container.voxels == NULL) { + core::utility::log::Log::DefaultLog.WriteError( + "[OSPRay:generateRepresentations] Representation STRUCTUREDVOLUME active but no data provided."); + break; + } + + _baseStructures[entry.first].emplace_back( + ::ospray::cpp::Volume("structuredRegular"), structureTypeEnum::VOLUME); + + auto type = static_cast(voxelDataTypeOSP[static_cast(container.voxelDType)]); + + // add data + rkcommon::math::vec3i dims = {container.dimensions[0], container.dimensions[1], container.dimensions[2]}; + auto voxelData = ::ospray::cpp::SharedData(container.voxels, type, dims); + voxelData.commit(); + + + std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].structures.back()).setParam("data", voxelData); + } + break; - _baseStructures[entry.first].emplace_back( - ::ospray::cpp::Volume("structuredRegular"), structureTypeEnum::VOLUME); + case volumeTypeEnum::SPHERICALVOLUME: { + if (!container.voxels_shared) { + core::utility::log::Log::DefaultLog.WriteError( + "[OSPRay:generateRepresentations] Representation SPHERICALVOLUME active but no data provided."); + break; + } - auto type = static_cast(voxelDataTypeOSP[static_cast(container.voxelDType)]); + _baseStructures[entry.first].emplace_back( + ::ospray::cpp::Volume("structuredSpherical"), structureTypeEnum::VOLUME); - // add data - rkcommon::math::vec3i dims = {container.dimensions[0], container.dimensions[1], container.dimensions[2]}; - auto voxelData = ::ospray::cpp::SharedData(container.voxels, type, dims); - voxelData.commit(); + // add data + rkcommon::math::vec3i dims = { + container.dimensions[0], container.dimensions[1], container.dimensions[2]}; + auto voxelData = ::ospray::cpp::SharedData(container.voxels_shared->data(), OSP_FLOAT, dims); + voxelData.commit(); - std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].structures.back()).setParam("data", voxelData); + std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].structures.back()) + .setParam("data", voxelData); + + } + break; + } + - //ospSet3iv(std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "dimensions",element.dimensions->data()); std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].structures.back()) .setParam("gridOrigin", convertToVec3f(container.gridOrigin)); std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].structures.back()) .setParam("gridSpacing", convertToVec3f(container.gridSpacing)); - //std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()).setParam("voxelRange", element.valueRange); - //ospSet1b(std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "singleShade", element.useMIP); - //ospSet1b(std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "gradientShadingEnables", - // element.useGradient); - //ospSet1b(std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "preIntegration", - // element.usePreIntegration); - //ospSet1b(std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "adaptiveSampling", - // element.useAdaptiveSampling); - //ospSet1f( - // std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "adaptiveScalar", element.adaptiveFactor); - //ospSet1f(std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "adaptiveMaxSamplingRate", - // element.adaptiveMaxRate); - //ospSet1f(std::get<::ospray::cpp::Volume>(_baseStructures[entry.first].back()), "samplingRate", element.samplingRate); - auto tf = ::ospray::cpp::TransferFunction("piecewiseLinear"); auto tf_rgb = ::ospray::cpp::SharedData(container.tfRGB->data(), OSP_VEC3F, container.tfRGB->size() / 3); @@ -1307,9 +1324,9 @@ void AbstractOSPRayRenderer::createInstances() { _instances[entry.first] = ::ospray::cpp::Instance(_groups[entry.first]); - if (element.transformationContainer) { + if (element->transformationContainer) { - auto trafo = element.transformationContainer; + auto trafo = element->transformationContainer; ::rkcommon::math::affine3f xfm; xfm.p.x = trafo->pos[0]; xfm.p.y = trafo->pos[1]; diff --git a/plugins/mmospray/src/AbstractOSPRayStructure.cpp b/plugins/mmospray/src/AbstractOSPRayStructure.cpp index 23c15e88a0..c431b550d4 100644 --- a/plugins/mmospray/src/AbstractOSPRayStructure.cpp +++ b/plugins/mmospray/src/AbstractOSPRayStructure.cpp @@ -67,7 +67,7 @@ bool AbstractOSPRayStructure::getStructureCallback(megamol::core::Call& call) { if (os_in != NULL) { if (!this->readData(call)) return false; - os_in->addStructure(this->structureContainer); + os_in->addStructure(&structureContainer); } if (os_out != NULL) { @@ -87,7 +87,7 @@ bool AbstractOSPRayStructure::getExtendsCallback(megamol::core::Call& call) { if (!this->getExtends(call)) { return false; } - os_in->addExtend(this->extendContainer); + os_in->addExtend(&extendContainer); } if (os_out != NULL) { diff --git a/plugins/mmospray/src/CallOSPRayStructure.cpp b/plugins/mmospray/src/CallOSPRayStructure.cpp index f451c7ae87..5b5ef4aad4 100644 --- a/plugins/mmospray/src/CallOSPRayStructure.cpp +++ b/plugins/mmospray/src/CallOSPRayStructure.cpp @@ -40,12 +40,12 @@ CallOSPRayStructure& CallOSPRayStructure::operator=(const CallOSPRayStructure& r } void CallOSPRayStructure::setStructureMap(OSPRayStrcutrureMap* sm) { - this->structureMap = sm; + structureMap = sm; } -void CallOSPRayStructure::addStructure(OSPRayStructureContainer& sc) { - if (sc.isValid) { +void CallOSPRayStructure::addStructure(OSPRayStructureContainer* sc) { + if (sc->isValid) { if (this->structureMap != NULL) { //this->structureMap->insert_or_assign(this, sc); // C++17 this->structureMap->operator[](this) = sc; @@ -65,8 +65,8 @@ void CallOSPRayStructure::setExtendMap(OSPRayExtendMap* em) { } -void CallOSPRayStructure::addExtend(OSPRayExtendContainer& ec) { - if (this->extendMap != NULL) { +void CallOSPRayStructure::addExtend(OSPRayExtendContainer* ec) { + if (extendMap != nullptr) { //this->extendMap->insert_or_assign(this, ec); // C++17 this->extendMap->operator[](this) = ec; } else { diff --git a/plugins/mmospray/src/OSPRayAPIStructure.cpp b/plugins/mmospray/src/OSPRayAPIStructure.cpp index f3de9aeeec..864066b4e7 100644 --- a/plugins/mmospray/src/OSPRayAPIStructure.cpp +++ b/plugins/mmospray/src/OSPRayAPIStructure.cpp @@ -31,7 +31,6 @@ bool OSPRayAPIStructure::readData(megamol::core::Call& call) { CallOSPRayAPIObject* cd = this->getDataSlot.CallAs(); - this->structureContainer.dataChanged = false; if (cd == NULL) return false; if (!(*cd)(2)) diff --git a/plugins/mmospray/src/OSPRayLineGeometry.cpp b/plugins/mmospray/src/OSPRayLineGeometry.cpp index 3cac3fc7bd..fee2bf97dd 100644 --- a/plugins/mmospray/src/OSPRayLineGeometry.cpp +++ b/plugins/mmospray/src/OSPRayLineGeometry.cpp @@ -56,7 +56,6 @@ bool OSPRayLineGeometry::readData(core::Call& call) { curveStructure cs; if (cm != nullptr) { auto meta_data = cm->getMetaData(); - this->structureContainer.dataChanged = false; if (os->getTime() > meta_data.m_frame_cnt) { meta_data.m_frame_ID = meta_data.m_frame_cnt - 1; } else { @@ -80,7 +79,6 @@ bool OSPRayLineGeometry::readData(core::Call& call) { } else { geocalls::LinesDataCall* cd = this->getDataSlot.CallAs(); - this->structureContainer.dataChanged = false; if (cd == NULL) return false; cd->SetTime(os->getTime()); diff --git a/plugins/mmospray/src/OSPRayRenderer.cpp b/plugins/mmospray/src/OSPRayRenderer.cpp index 6e7cc10bbe..e0d2818156 100644 --- a/plugins/mmospray/src/OSPRayRenderer.cpp +++ b/plugins/mmospray/src/OSPRayRenderer.cpp @@ -114,16 +114,16 @@ bool OSPRayRenderer::Render(megamol::core::view::CallRender3D& cr) { _clipping_geo_changed = false; for (auto element : this->_structureMap) { auto structure = element.second; - if (structure.dataChanged) { + if (structure->dataChanged) { _data_has_changed = true; } - if (structure.materialChanged) { + if (structure->materialChanged) { _material_has_changed = true; } - if (structure.transformationChanged) { + if (structure->transformationChanged) { _transformation_has_changed = true; } - if (structure.clippingPlaneChanged) { + if (structure->clippingPlaneChanged) { _clipping_geo_changed = true; } } @@ -441,42 +441,42 @@ bool OSPRayRenderer::GetExtents(megamol::core::view::CallRender3D& cr) { auto element = pair.second; if (frameCnt == 0) { - if (element.boundingBox->IsBoundingBoxValid()) { - finalBox.SetBoundingBox(element.boundingBox->BoundingBox()); - } else if (element.boundingBox->IsClipBoxValid()) { - finalBox.SetBoundingBox(element.boundingBox->ClipBox()); + if (element->boundingBox->IsBoundingBoxValid()) { + finalBox.SetBoundingBox(element->boundingBox->BoundingBox()); + } else if (element->boundingBox->IsClipBoxValid()) { + finalBox.SetBoundingBox(element->boundingBox->ClipBox()); } else { finalBox.SetBoundingBox(vislib::math::Cuboid(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f)); } - if (element.boundingBox->IsClipBoxValid()) { - finalBox.SetClipBox(element.boundingBox->ClipBox()); - } else if (element.boundingBox->IsBoundingBoxValid()) { - finalBox.SetClipBox(element.boundingBox->BoundingBox()); + if (element->boundingBox->IsClipBoxValid()) { + finalBox.SetClipBox(element->boundingBox->ClipBox()); + } else if (element->boundingBox->IsBoundingBoxValid()) { + finalBox.SetClipBox(element->boundingBox->BoundingBox()); } else { finalBox.SetClipBox(vislib::math::Cuboid(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f)); } } else { - if (element.boundingBox->IsBoundingBoxValid()) { + if (element->boundingBox->IsBoundingBoxValid()) { vislib::math::Cuboid box(finalBox.BoundingBox()); - box.Union(element.boundingBox->BoundingBox()); + box.Union(element->boundingBox->BoundingBox()); finalBox.SetBoundingBox(box); - } else if (element.boundingBox->IsClipBoxValid()) { + } else if (element->boundingBox->IsClipBoxValid()) { vislib::math::Cuboid box(finalBox.BoundingBox()); - box.Union(element.boundingBox->BoundingBox()); + box.Union(element->boundingBox->BoundingBox()); finalBox.SetBoundingBox(box); } - if (element.boundingBox->IsClipBoxValid()) { + if (element->boundingBox->IsClipBoxValid()) { vislib::math::Cuboid box(finalBox.ClipBox()); - box.Union(element.boundingBox->ClipBox()); + box.Union(element->boundingBox->ClipBox()); finalBox.SetClipBox(box); - } else if (element.boundingBox->IsBoundingBoxValid()) { + } else if (element->boundingBox->IsBoundingBoxValid()) { vislib::math::Cuboid box(finalBox.ClipBox()); - box.Union(element.boundingBox->BoundingBox()); + box.Union(element->boundingBox->BoundingBox()); finalBox.SetClipBox(box); } } - frameCnt = vislib::math::Max(frameCnt, element.timeFramesCount); + frameCnt = vislib::math::Max(frameCnt, element->timeFramesCount); } cr.SetTimeFramesCount(frameCnt); diff --git a/plugins/mmospray/src/OSPRaySphereGeometry.cpp b/plugins/mmospray/src/OSPRaySphereGeometry.cpp index 985fecfa12..df865a84f8 100644 --- a/plugins/mmospray/src/OSPRaySphereGeometry.cpp +++ b/plugins/mmospray/src/OSPRaySphereGeometry.cpp @@ -49,7 +49,6 @@ bool OSPRaySphereGeometry::readData(megamol::core::Call& call) { flags_size = fcr->getData()->flags->size(); } - this->structureContainer.dataChanged = false; if (cd == NULL) return false; cd->SetTimeStamp(os->getTime()); diff --git a/plugins/mmospray/src/OSPRaySphericalVolume.cpp b/plugins/mmospray/src/OSPRaySphericalVolume.cpp new file mode 100644 index 0000000000..69e37ed8ea --- /dev/null +++ b/plugins/mmospray/src/OSPRaySphericalVolume.cpp @@ -0,0 +1,299 @@ +/* + * OSPRaySphericalVolume.cpp + * Copyright (C) 2022 by MegaMol Team + * Alle Rechte vorbehalten. + */ + +#include "OSPRaySphericalVolume.h" +#include "mmcore/Call.h" +#include "mmadios/CallADIOSData.h" +#include "mmcore/param/BoolParam.h" +#include "mmcore/param/EnumParam.h" +#include "mmcore/param/FloatParam.h" +#include "mmcore/param/StringParam.h" +#include "mmcore/param/Vector3fParam.h" +#include "mmcore/param/FlexEnumParam.h" +#include "mmcore/utility/log/Log.h" +#include "mmcore/view/CallGetTransferFunction.h" + + +using namespace megamol::ospray; + + +OSPRaySphericalVolume::OSPRaySphericalVolume(void) + : AbstractOSPRayStructure() + , getDataSlot("getdata", "Connects to the data source") + , getTFSlot("gettransferfunction", "Connects to a color transfer function module") + , clippingBoxLower("ClippingBox::Left", "Left corner of the clipping Box") + , clippingBoxUpper("ClippingBox::Right", "Right corner of the clipping Box") + , clippingBoxActive("ClippingBox::Active", "Activates the clipping Box") + , repType( + "Representation", "Activates one of the three different volume representations: Volume, Isosurfae, Slice") + , IsoValue("Isosurface::Isovalue", "Sets the isovalue of the isosurface") + , showBoundingBox("showBoundingBox", "Bounding box of the volume data set") + , volumeDataStringSlot("volumeData", "Set name for volume data from adios file") { + + core::param::EnumParam* rt = new core::param::EnumParam(VOLUMEREP); + rt->SetTypePair(VOLUMEREP, "Volume"); + rt->SetTypePair(ISOSURFACE, "Isosurface"); + repType << rt; + repType.SetUpdateCallback(&OSPRaySphericalVolume::paramChanged); + MakeSlotAvailable(&repType); + + clippingBoxActive << new core::param::BoolParam(false); + clippingBoxLower << new core::param::Vector3fParam(-5.0f, -5.0f, -5.0f); + clippingBoxUpper << new core::param::Vector3fParam(0.0f, 5.0f, 5.0f); + clippingBoxActive.SetUpdateCallback(&OSPRaySphericalVolume::paramChanged); + clippingBoxLower.SetUpdateCallback(&OSPRaySphericalVolume::paramChanged); + clippingBoxUpper.SetUpdateCallback(&OSPRaySphericalVolume::paramChanged); + MakeSlotAvailable(&clippingBoxActive); + MakeSlotAvailable(&clippingBoxLower); + MakeSlotAvailable(&clippingBoxUpper); + + IsoValue << new core::param::FloatParam(0.1f); + IsoValue.SetUpdateCallback(&OSPRaySphericalVolume::paramChanged); + MakeSlotAvailable(&IsoValue); + + getDataSlot.SetCompatibleCall(); + MakeSlotAvailable(&getDataSlot); + + getTFSlot.SetCompatibleCall(); + MakeSlotAvailable(&getTFSlot); + + showBoundingBox << new core::param::StringParam(""); + showBoundingBox.Parameter()->SetGUIReadOnly(true); + MakeSlotAvailable(&showBoundingBox); + + volumeDataStringSlot << new core::param::FlexEnumParam("undef"); + volumeDataStringSlot.SetUpdateCallback(&OSPRaySphericalVolume::paramChanged); + MakeSlotAvailable(&volumeDataStringSlot); + + + // this->SetSlotUnavailable(&this->getMaterialSlot); +} + + +bool OSPRaySphericalVolume::readData(core::Call& call) { + + // fill material container + this->processMaterial(); + + // get transformation parameter + //this->processTransformation(); + + // fill clipping plane container + this->processClippingPlane(); + + // read Data, calculate shape parameters, fill data vectors + auto os = dynamic_cast(&call); + auto cd = this->getDataSlot.CallAs(); + auto const cgtf = this->getTFSlot.CallAs(); + + if (cd == nullptr) + return false; + if (cgtf == nullptr) { + core::utility::log::Log::DefaultLog.WriteError("[OSPRaySphericalVolume] No transferfunction connected."); + return false; + } + + uint32_t requested_frame = std::floorf(os->getTime()); + if ((requested_frame >= cd->getFrameCount() && cd->getFrameCount() > 0)) { + requested_frame = cd->getFrameCount() - 1; + } + cd->setFrameIDtoLoad(requested_frame); + + // get meta data + if (!(*cd)(1)) { + megamol::core::utility::log::Log::DefaultLog.WriteError("[OSPRaySphericalVolume] Error during GetHeader"); + return false; + } + + auto availVars = cd->getAvailableVars(); + for (auto var : availVars) { + volumeDataStringSlot.Param()->AddValue(var); + } + const std::string volDataStr = + std::string(this->volumeDataStringSlot.Param()->ValueString()); + + // do inqures + if (volDataStr != "undef") { + if (!cd->inquireVar(volDataStr)) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "[OSPRaySphericalVolume] variable \"%s\" doe not exist.", volDataStr.c_str()); + return false; + } + } + const std::string bboxStr = "global_box"; + if (!cd->inquireVar(bboxStr)) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "[OSPRaySphericalVolume] variable \"%s\" does not exist.", bboxStr.c_str()); + } + const std::string gridOrigStr = "vol_grid_origin"; + if (!cd->inquireVar(gridOrigStr)) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "[OSPRaySphericalVolume] variable \"%s\" does not exist.", gridOrigStr.c_str()); + } + const std::string gridSpacingStr = "vol_grid_spacing"; + if (!cd->inquireVar(gridSpacingStr)) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "[OSPRaySphericalVolume] variable \"%s\" does not exist.", gridSpacingStr.c_str()); + } + + if (!(*cd)(0)) { + megamol::core::utility::log::Log::DefaultLog.WriteError("[OSPRaySphericalVolume] Error during GetData"); + return false; + } + + // do the callback to set the dirty flag + if (!(*cgtf)(0)) + return false; + + auto tf_dirty = cgtf->IsDirty(); + if (datahash != cd->getDataHash() || this->time != os->getTime() || _trigger_recalc || tf_dirty) { + datahash = cd->getDataHash(); + time = os->getTime(); + structureContainer.dataChanged = true; + _trigger_recalc = false; + } else { + return true; + } + + auto bbox = cd->getData(bboxStr) + ->GetAsFloat(); + auto data = cd->getData(volDataStr) + ->GetAsFloat(); + auto gridOrigin = cd->getData(gridOrigStr)->GetAsFloat(); + auto gridSpacing = cd->getData(gridSpacingStr)->GetAsFloat(); + + + this->extendContainer.boundingBox = std::make_shared(); + this->extendContainer.boundingBox->SetBoundingBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]); + + std::stringstream bbox_stream; + bbox_stream << "LEFT: " << extendContainer.boundingBox->BoundingBox().Left() << ";" << std::endl; + bbox_stream << "BOTTOM: " << extendContainer.boundingBox->BoundingBox().Bottom() << ";" << std::endl; + bbox_stream << "BACK: " << extendContainer.boundingBox->BoundingBox().Back() << ";" << std::endl; + bbox_stream << "RIGHT: " << extendContainer.boundingBox->BoundingBox().Right() << ";" << std::endl; + bbox_stream << "TOP: " << extendContainer.boundingBox->BoundingBox().Top() << ";" << std::endl; + bbox_stream << "FRONT: " << extendContainer.boundingBox->BoundingBox().Front(); + this->showBoundingBox.Param()->SetValue(bbox_stream.str().c_str()); + this->extendContainer.timeFramesCount = cd->getFrameCount(); + this->extendContainer.isValid = true; + + + auto res = cd->getData(volDataStr)->getShape(); + assert(res.size() == 3); + + unsigned int const voxelCount = res[0] * res[1] * res[2]; + assert(data.size() == voxelCount); + + std::array dimensions = { + static_cast(res[0]), static_cast(res[1]), static_cast(res[2])}; + + voxelDataType voxelType = voxelDataType::FLOAT; + + // get color transfer function + std::vector rgb; + std::vector a; + std::array minmax = {*std::min_element(data.begin(), data.end()), *std::max_element(data.begin(),data.end())}; + cgtf->SetRange(minmax); + if ((*cgtf)(0)) { + if (cgtf->TFTextureFormat() == core::view::CallGetTransferFunction::TextureFormat::TEXTURE_FORMAT_RGBA) { + auto const numColors = cgtf->TextureSize(); + rgb.resize(3 * numColors); + a.resize(numColors); + auto const texture = cgtf->GetTextureData(); + + for (unsigned int i = 0; i < numColors; ++i) { + rgb[i * 3 + 0] = texture[i * 4 + 0]; + rgb[i * 3 + 1] = texture[i * 4 + 1]; + rgb[i * 3 + 2] = texture[i * 4 + 2]; + a[i] = texture[i * 4 + 3]; + } + } else { + auto const texSize = cgtf->TextureSize(); + rgb.resize(3 * texSize); + a.resize(texSize); + auto const texture = cgtf->GetTextureData(); + + for (unsigned int i = 0; i < texSize; ++i) { + rgb[i * 3 + 0] = texture[i * 4 + 0]; + rgb[i * 3 + 1] = texture[i * 4 + 1]; + rgb[i * 3 + 2] = texture[i * 4 + 2]; + a[i] = i / (texSize - 1.0f); + } + core::utility::log::Log::DefaultLog.WriteWarn( + "OSPRaySphericalVolume: No alpha channel in transfer function " + "connected to module. Adding alpha ramp to RGB colors.\n"); + } + } else { + core::utility::log::Log::DefaultLog.WriteError( + "OSPRaySphericalVolume: No transfer function connected to module"); + return false; + } + cgtf->ResetDirty(); + + // Write stuff into the structureContainer + + this->structureContainer.type = structureTypeEnum::VOLUME; + this->structureContainer.volumeType = volumeTypeEnum::SPHERICALVOLUME; + volumeStructure svs; + + svs.volRepType = (volumeRepresentationType)this->repType.Param()->Value(); + svs.voxels_shared = std::make_shared>(data); + svs.gridOrigin = { gridOrigin[0], gridOrigin[1], gridOrigin[2]}; + svs.gridSpacing = { gridSpacing[0], gridSpacing[1], gridSpacing[2]}; + svs.dimensions = dimensions; + svs.voxelCount = voxelCount; + svs.valueRange = minmax; + svs.tfRGB = std::make_shared>(std::move(rgb)); + svs.tfA = std::make_shared>(std::move(a)); + svs.voxelDType = voxelType; + + svs.clippingBoxActive = this->clippingBoxActive.Param()->Value(); + std::array cbl = {this->clippingBoxLower.Param()->Value().GetX(), + this->clippingBoxLower.Param()->Value().GetY(), + this->clippingBoxLower.Param()->Value().GetZ()}; + svs.clippingBoxLower = cbl; + std::array cbu = {this->clippingBoxUpper.Param()->Value().GetX(), + this->clippingBoxUpper.Param()->Value().GetY(), + this->clippingBoxUpper.Param()->Value().GetZ()}; + svs.clippingBoxUpper = cbu; + + svs.isoValue = this->IsoValue.Param()->Value(); + + this->structureContainer.structure = svs; + + return true; +} + + +OSPRaySphericalVolume::~OSPRaySphericalVolume() { + this->Release(); +} + +bool OSPRaySphericalVolume::create() { + return true; +} + +void OSPRaySphericalVolume::release() {} + + +bool OSPRaySphericalVolume::getExtends(core::Call& call) { + auto os = dynamic_cast(&call); + auto cd = this->getDataSlot.CallAs(); + + if (cd == nullptr) + return false; + + if (!this->readData(call)) + return false; + + return true; +} + +bool OSPRaySphericalVolume::paramChanged(core::param::ParamSlot& p) { + + _trigger_recalc = true; + return true; +} diff --git a/plugins/mmospray/src/OSPRaySphericalVolume.h b/plugins/mmospray/src/OSPRaySphericalVolume.h new file mode 100644 index 0000000000..c78e8b53a6 --- /dev/null +++ b/plugins/mmospray/src/OSPRaySphericalVolume.h @@ -0,0 +1,80 @@ +/* + * OSPRaySphericalVolume.h + * Copyright (C) 2022 by MegaMol Team + * Alle Rechte vorbehalten. + */ +#pragma once + +#include "mmcore/CallerSlot.h" +#include "mmcore/param/ParamSlot.h" +#include "mmospray/AbstractOSPRayStructure.h" + +namespace megamol { +namespace ospray { + +class OSPRaySphericalVolume : public AbstractOSPRayStructure { + +public: + /** + * Answer the name of this module. + * + * @return The name of this module. + */ + static const char* ClassName(void) { + return "OSPRaySphericalVolume"; + } + + /** + * Answer a human readable description of this module. + * + * @return A human readable description of this module. + */ + static const char* Description(void) { + return "Creator for OSPRay spherical volumes."; + } + + /** + * Answers whether this module is available on the current system. + * + * @return 'true' if the module is available, 'false' otherwise. + */ + static bool IsAvailable(void) { + return true; + } + + /** Dtor. */ + virtual ~OSPRaySphericalVolume(void); + + /** Ctor. */ + OSPRaySphericalVolume(void); + +protected: + virtual bool create(); + virtual void release(); + + virtual bool readData(core::Call& call); + virtual bool getExtends(core::Call& call); + + bool paramChanged(core::param::ParamSlot& p); + + bool _trigger_recalc = false; + + /** The call for data */ + core::CallerSlot getDataSlot; + + /** The call for Transfer function */ + core::CallerSlot getTFSlot; + + megamol::core::param::ParamSlot clippingBoxLower; + megamol::core::param::ParamSlot clippingBoxUpper; + megamol::core::param::ParamSlot clippingBoxActive; + megamol::core::param::ParamSlot showBoundingBox; + + megamol::core::param::ParamSlot volumeDataStringSlot; + + megamol::core::param::ParamSlot repType; + megamol::core::param::ParamSlot IsoValue; +}; + +} // namespace ospray +} // namespace megamol diff --git a/plugins/mmospray/src/OSPRayStructuredVolume.cpp b/plugins/mmospray/src/OSPRayStructuredVolume.cpp index c55a41befa..5339f98f2a 100644 --- a/plugins/mmospray/src/OSPRayStructuredVolume.cpp +++ b/plugins/mmospray/src/OSPRayStructuredVolume.cpp @@ -76,7 +76,6 @@ bool OSPRayStructuredVolume::readData(core::Call& call) { auto cd = this->getDataSlot.CallAs(); auto const cgtf = this->getTFSlot.CallAs(); - this->structureContainer.dataChanged = false; if (cd == nullptr) return false; if (cgtf == nullptr) { @@ -211,7 +210,7 @@ bool OSPRayStructuredVolume::readData(core::Call& call) { this->structureContainer.type = structureTypeEnum::VOLUME; this->structureContainer.volumeType = volumeTypeEnum::STRUCTUREDVOLUME; - structuredVolumeStructure svs; + volumeStructure svs; svs.volRepType = (volumeRepresentationType)this->repType.Param()->Value(); svs.voxels = cd->GetData(); diff --git a/plugins/mmospray/src/mmospray.cpp b/plugins/mmospray/src/mmospray.cpp index d41e4775c8..9c58706bb9 100644 --- a/plugins/mmospray/src/mmospray.cpp +++ b/plugins/mmospray/src/mmospray.cpp @@ -32,14 +32,15 @@ #include "mmospray/CallOSPRayMaterial.h" #include "mmospray/CallOSPRayStructure.h" #include "mmospray/CallOSPRayTransformation.h" +#include "OSPRaySphericalVolume.h" namespace megamol::ospray { -class MMOSPRayPluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { +class MMOSPRayPluginInstance : public core::utility::plugins::AbstractPluginInstance { REGISTERPLUGIN(MMOSPRayPluginInstance) public: MMOSPRayPluginInstance(void) - : megamol::core::utility::plugins::AbstractPluginInstance("mmospray", "CPU Raytracing"){}; + : AbstractPluginInstance("mmospray", "CPU Raytracing"){}; ~MMOSPRayPluginInstance() override = default; @@ -48,36 +49,37 @@ class MMOSPRayPluginInstance : public megamol::core::utility::plugins::AbstractP // register modules - this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); // register calls - this->call_descriptions.RegisterAutoDescription(); - this->call_descriptions.RegisterAutoDescription(); - this->call_descriptions.RegisterAutoDescription(); - this->call_descriptions.RegisterAutoDescription(); + this->call_descriptions.RegisterAutoDescription(); + this->call_descriptions.RegisterAutoDescription(); + this->call_descriptions.RegisterAutoDescription(); + this->call_descriptions.RegisterAutoDescription(); } }; } // namespace megamol::ospray From 8f3128ad16f7b7f34dae67b275e07d5d7bd33d58 Mon Sep 17 00:00:00 2001 From: invor Date: Sat, 16 Jul 2022 12:46:21 +0200 Subject: [PATCH 12/47] Add primitive type to gltf loader --- .../include/mesh/MeshDataAccessCollection.h | 2 +- plugins/mesh/src/gltf/glTFFileLoader.cpp | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/plugins/mesh/include/mesh/MeshDataAccessCollection.h b/plugins/mesh/include/mesh/MeshDataAccessCollection.h index 3feba3542e..8f8766551b 100644 --- a/plugins/mesh/include/mesh/MeshDataAccessCollection.h +++ b/plugins/mesh/include/mesh/MeshDataAccessCollection.h @@ -22,7 +22,7 @@ class MeshDataAccessCollection { public: enum ValueType { BYTE, UNSIGNED_BYTE, SHORT, UNSIGNED_SHORT, INT, UNSIGNED_INT, HALF_FLOAT, FLOAT, DOUBLE }; enum AttributeSemanticType { POSITION, NORMAL, COLOR, TEXCOORD, TANGENT, UNKNOWN, ID }; - enum PrimitiveType { TRIANGLES, QUADS, LINES, LINE_STRIP, TRIANGLE_FAN }; + enum PrimitiveType { TRIANGLES, QUADS, LINES, LINE_STRIP, TRIANGLE_FAN, TRIANGLE_STRIP }; static constexpr unsigned int convertToGLType(ValueType value_type) { unsigned int retval = 0; diff --git a/plugins/mesh/src/gltf/glTFFileLoader.cpp b/plugins/mesh/src/gltf/glTFFileLoader.cpp index e4dc2d8ff0..9b805d50d3 100644 --- a/plugins/mesh/src/gltf/glTFFileLoader.cpp +++ b/plugins/mesh/src/gltf/glTFFileLoader.cpp @@ -176,10 +176,32 @@ bool megamol::mesh::GlTFFileLoader::getMeshDataCallback(core::Call& caller) { attrib_byte_stride, attrib_byte_offset, attrib_semantic}); } + MeshDataAccessCollection::PrimitiveType primitive_type; + + switch (model->meshes[mesh_idx].primitives[primitive_idx].mode) { + case TINYGLTF_MODE_LINE: + primitive_type = MeshDataAccessCollection::PrimitiveType::LINES; + break; + case TINYGLTF_MODE_LINE_STRIP: + primitive_type = MeshDataAccessCollection::PrimitiveType::LINE_STRIP; + break; + case TINYGLTF_MODE_TRIANGLES: + primitive_type = MeshDataAccessCollection::PrimitiveType::TRIANGLES; + break; + case TINYGLTF_MODE_TRIANGLE_STRIP: + primitive_type = MeshDataAccessCollection::PrimitiveType::TRIANGLE_STRIP; + break; + case TINYGLTF_MODE_TRIANGLE_FAN: + primitive_type = MeshDataAccessCollection::PrimitiveType::TRIANGLE_FAN; + break; + default: + break; + } + std::string identifier = m_glTFFilename_slot.Param()->Value().generic_u8string() + model->meshes[mesh_idx].name + "_" + std::to_string(primitive_idx); - m_mesh_access_collection.first->addMesh(identifier, mesh_attributes, mesh_indices); + m_mesh_access_collection.first->addMesh(identifier, mesh_attributes, mesh_indices, primitive_type); m_mesh_access_collection.second.push_back(identifier); auto max_data = From 3300783167b3a33cb1808efcd336dd3119d7199b Mon Sep 17 00:00:00 2001 From: invor Date: Sat, 16 Jul 2022 13:39:18 +0200 Subject: [PATCH 13/47] temporary line shader --- plugins/mesh_gl/shaders/line.btf | 17 +++++++++++++++++ .../mesh_gl/shaders/mesh_gl/line.frag.glsl | 5 +++++ .../mesh_gl/shaders/mesh_gl/line.vert.glsl | 19 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 plugins/mesh_gl/shaders/line.btf create mode 100644 plugins/mesh_gl/shaders/mesh_gl/line.frag.glsl create mode 100644 plugins/mesh_gl/shaders/mesh_gl/line.vert.glsl diff --git a/plugins/mesh_gl/shaders/line.btf b/plugins/mesh_gl/shaders/line.btf new file mode 100644 index 0000000000..4031aaba7d --- /dev/null +++ b/plugins/mesh_gl/shaders/line.btf @@ -0,0 +1,17 @@ + + + + + + 430 + commondefines.glsl + mesh_gl/line.vert.glsl + + + + 430 + commondefines.glsl + mesh_gl/line.frag.glsl + + + diff --git a/plugins/mesh_gl/shaders/mesh_gl/line.frag.glsl b/plugins/mesh_gl/shaders/mesh_gl/line.frag.glsl new file mode 100644 index 0000000000..f1b962c752 --- /dev/null +++ b/plugins/mesh_gl/shaders/mesh_gl/line.frag.glsl @@ -0,0 +1,5 @@ +out layout(location = 0) vec4 frag_colour; + +void main(void) { + frag_colour = vec4(1.0); +} \ No newline at end of file diff --git a/plugins/mesh_gl/shaders/mesh_gl/line.vert.glsl b/plugins/mesh_gl/shaders/mesh_gl/line.vert.glsl new file mode 100644 index 0000000000..38fc02d0eb --- /dev/null +++ b/plugins/mesh_gl/shaders/mesh_gl/line.vert.glsl @@ -0,0 +1,19 @@ +#extension GL_ARB_shader_draw_parameters : require + +struct MeshShaderParams +{ + mat4 transform; +}; + +layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; + +uniform mat4 view_mx; +uniform mat4 proj_mx; + +layout(location = 0) in vec3 v_position; + +void main() +{ + mat4 object_transform = mesh_shader_params[gl_DrawIDARB].transform; + gl_Position = proj_mx * view_mx * object_transform * vec4(v_position,1.0); +} \ No newline at end of file From 63433352d259856764533ed4d50ac94240220528 Mon Sep 17 00:00:00 2001 From: rauts Date: Mon, 18 Jul 2022 15:51:17 +0200 Subject: [PATCH 14/47] removed one wrong dirty cycle --- core/src/view/TransferFunction.cpp | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/core/src/view/TransferFunction.cpp b/core/src/view/TransferFunction.cpp index da3fb356aa..f13572797d 100644 --- a/core/src/view/TransferFunction.cpp +++ b/core/src/view/TransferFunction.cpp @@ -35,11 +35,11 @@ bool TransferFunction::requestTF(core::Call& call) { bool something_has_changed = false; // update transfer function if tf param is dirty - if (this->tfParam.IsDirty()) { + if (tfParam.IsDirty()) { // Check if range of initially loaded project value should be ignored auto tf_param_value = this->tfParam.Param()->Value(); - this->ignore_project_range = TransferFunctionParam::IgnoreProjectRange(tf_param_value); - this->tfParam.ResetDirty(); + ignore_project_range = TransferFunctionParam::IgnoreProjectRange(tf_param_value); + tfParam.ResetDirty(); something_has_changed = true; } @@ -47,10 +47,10 @@ bool TransferFunction::requestTF(core::Call& call) { if (cgtf->UpdateRange() && this->ignore_project_range) { // Update changed range propagated from the module via the call if (cgtf->ConsumeRangeUpdate()) { - auto tf_param_value = this->tfParam.Param()->Value(); - auto tmp_range = this->range; - auto tmp_interpol = this->interpolMode; - auto tmp_tex_size = this->texSize; + auto tf_param_value = tfParam.Param()->Value(); + auto tmp_range = range; + auto tmp_interpol = interpolMode; + auto tmp_tex_size = texSize; TransferFunctionParam::NodeVector_t tmp_nodes; if (TransferFunctionParam::GetParsedTransferFunctionData( @@ -59,7 +59,8 @@ bool TransferFunction::requestTF(core::Call& call) { std::string tf_str; if (TransferFunctionParam::GetDumpedTransferFunction( tf_str, tmp_nodes, tmp_interpol, tmp_tex_size, cgtf->Range())) { - this->tfParam.Param()->SetValue(tf_str); + tfParam.Param()->SetValue(tf_str); + tfParam.ResetDirty(); } } something_has_changed = true; @@ -69,22 +70,22 @@ bool TransferFunction::requestTF(core::Call& call) { if (something_has_changed) { // Get current values from parameter string (Values are checked, too). TransferFunctionParam::NodeVector_t tmp_nodes; - if (!TransferFunctionParam::GetParsedTransferFunctionData(this->tfParam.Param()->Value(), - tmp_nodes, this->interpolMode, this->texSize, this->range)) { + if (!TransferFunctionParam::GetParsedTransferFunctionData(tfParam.Param()->Value(), + tmp_nodes, interpolMode, texSize, range)) { return false; } // Apply interpolation and generate texture data. - if (this->interpolMode == TransferFunctionParam::InterpolationMode::LINEAR) { - this->tex = TransferFunctionParam::LinearInterpolation(this->texSize, tmp_nodes); - } else if (this->interpolMode == TransferFunctionParam::InterpolationMode::GAUSS) { - this->tex = TransferFunctionParam::GaussInterpolation(this->texSize, tmp_nodes); + if (interpolMode == TransferFunctionParam::InterpolationMode::LINEAR) { + tex = TransferFunctionParam::LinearInterpolation(texSize, tmp_nodes); + } else if (interpolMode == TransferFunctionParam::InterpolationMode::GAUSS) { + tex = TransferFunctionParam::GaussInterpolation(texSize, tmp_nodes); } - ++this->version; + ++version; } - cgtf->SetTexture(this->texSize, this->tex.data(), this->texFormat, this->range, this->version); + cgtf->SetTexture(texSize, tex.data(), texFormat, range, version); return true; } From 6eb8dcfd949f74b5fd0e7418d5f9e642eeb5ac6a Mon Sep 17 00:00:00 2001 From: rauts Date: Mon, 18 Jul 2022 16:00:34 +0200 Subject: [PATCH 15/47] update --- plugins/datatools/src/AddParticleColors.cpp | 24 ++++++++--- plugins/mmadios/src/adiosDataSource.cpp | 5 +++ plugins/mmospray/CMakeLists.txt | 3 +- .../include/mmospray/CallOSPRayStructure.h | 3 +- .../mmospray/src/AbstractOSPRayRenderer.cpp | 39 +++++++++++++++--- plugins/mmospray/src/OSPRayLineGeometry.cpp | 9 +--- plugins/mmospray/src/OSPRayLineGeometry.h | 2 - .../mmospray/src/OSPRaySphericalVolume.cpp | 34 ++++++++++----- plugins/mmospray/src/OSPRaySphericalVolume.h | 2 + .../mmospray/src/OSPRayStructuredVolume.cpp | 12 +++--- plugins/probe/src/ElementColoring.cpp | 33 +++++++++++---- plugins/probe/src/PlaceProbes.cpp | 41 +++++++++++++++++++ plugins/probe/src/PlaceProbes.h | 4 ++ plugins/probe/src/SampleAlongProbes.h | 2 + 14 files changed, 166 insertions(+), 47 deletions(-) diff --git a/plugins/datatools/src/AddParticleColors.cpp b/plugins/datatools/src/AddParticleColors.cpp index 2fbdcccc29..a45793331b 100644 --- a/plugins/datatools/src/AddParticleColors.cpp +++ b/plugins/datatools/src/AddParticleColors.cpp @@ -43,19 +43,33 @@ bool megamol::datatools::AddParticleColors::manipulateData( core::view::CallGetTransferFunction* cgtf = _tf_slot.CallAs(); if (cgtf == nullptr) return false; - if (!(*cgtf)()) + if (!(*cgtf)(0)) return false; outData = inData; - - if (_frame_id != inData.FrameID() || _in_data_hash != inData.DataHash() || cgtf->IsDirty()) { - auto const tf = cgtf->GetTextureData(); - auto const tf_size = cgtf->TextureSize(); + const auto cgtf_dirty = cgtf->IsDirty(); + if (_frame_id != inData.FrameID() || _in_data_hash != inData.DataHash() || cgtf_dirty) { auto const pl_count = outData.GetParticleListCount(); + assert(pl_count > 0); _colors.clear(); _colors.resize(pl_count); + auto global_min_i = outData.AccessParticles(0).GetMinColourIndexValue(); + auto global_max_i = outData.AccessParticles(0).GetMaxColourIndexValue(); + for (unsigned int plidx = 0; plidx < pl_count; ++plidx) { + auto& parts = outData.AccessParticles(plidx); + auto const min_i = parts.GetMinColourIndexValue(); + auto const max_i = parts.GetMaxColourIndexValue(); + global_min_i = std::min(global_min_i,min_i); + global_max_i = std::max(global_max_i, max_i); + } + + cgtf->SetRange({global_min_i,global_max_i}); + if (!(*cgtf)(0)) + return false; + auto const tf = cgtf->GetTextureData(); + auto const tf_size = cgtf->TextureSize(); for (unsigned int plidx = 0; plidx < pl_count; ++plidx) { auto& parts = outData.AccessParticles(plidx); if (parts.GetColourDataType() != geocalls::SimpleSphericalParticles::COLDATA_FLOAT_I && diff --git a/plugins/mmadios/src/adiosDataSource.cpp b/plugins/mmadios/src/adiosDataSource.cpp index c3fdb67d60..c2f9193069 100644 --- a/plugins/mmadios/src/adiosDataSource.cpp +++ b/plugins/mmadios/src/adiosDataSource.cpp @@ -271,6 +271,11 @@ bool adiosDataSource::getHeaderCallback(core::Call& caller) { // adiosInst->AtIO("Input").SetParameters({{"verbose", "4"}}); io->SetParameter("verbose", "5"); auto fname = this->filenameSlot.Param()->Value().generic_u8string(); + if (fname.empty()) { + core::utility::log::Log::DefaultLog.WriteError( + "[adiosDataSource] No File given!"); + return false; + } #ifdef _WIN32 std::replace(fname.begin(), fname.end(), '/', '\\'); #endif diff --git a/plugins/mmospray/CMakeLists.txt b/plugins/mmospray/CMakeLists.txt index aa8298ab6f..8217d8a580 100644 --- a/plugins/mmospray/CMakeLists.txt +++ b/plugins/mmospray/CMakeLists.txt @@ -6,6 +6,7 @@ megamol_plugin(mmospray BUILD_DEFAULT OFF DEPENDS_PLUGINS + mmadios geometry_calls datatools protein_calls @@ -16,7 +17,7 @@ if (mmospray_PLUGIN_ENABLED) find_package(ospray CONFIG REQUIRED) find_package(rkcommon CONFIG REQUIRED) - target_link_libraries(mmospray PUBLIC ospray::ospray ospray::ospray_module_ispc rkcommon::rkcommon) + target_link_libraries(mmospray PUBLIC ospray::ospray rkcommon::rkcommon) if (WIN32) install(DIRECTORY "${OSPRAY_ROOT}/bin/" DESTINATION "bin" FILES_MATCHING PATTERN "*.dll") diff --git a/plugins/mmospray/include/mmospray/CallOSPRayStructure.h b/plugins/mmospray/include/mmospray/CallOSPRayStructure.h index b824d45d40..e1b6a008da 100644 --- a/plugins/mmospray/include/mmospray/CallOSPRayStructure.h +++ b/plugins/mmospray/include/mmospray/CallOSPRayStructure.h @@ -51,10 +51,9 @@ struct volumeStructure { std::array valueRange; const void* voxels; - std::shared_ptr> voxels_shared; std::array gridOrigin; std::array gridSpacing; - std::array dimensions; + std::array dimensions; std::array clippingBoxLower; std::array clippingBoxUpper; float isoValue; diff --git a/plugins/mmospray/src/AbstractOSPRayRenderer.cpp b/plugins/mmospray/src/AbstractOSPRayRenderer.cpp index a624e7fdec..3bc535143e 100644 --- a/plugins/mmospray/src/AbstractOSPRayRenderer.cpp +++ b/plugins/mmospray/src/AbstractOSPRayRenderer.cpp @@ -1155,11 +1155,12 @@ bool AbstractOSPRayRenderer::generateRepresentations() { break; case structureTypeEnum::VOLUME: { + auto& container = std::get(element->structure); switch (element->volumeType) { case volumeTypeEnum::STRUCTUREDVOLUME: { - if (container.voxels == NULL) { + if (container.voxels == nullptr) { core::utility::log::Log::DefaultLog.WriteError( "[OSPRay:generateRepresentations] Representation STRUCTUREDVOLUME active but no data provided."); break; @@ -1171,7 +1172,8 @@ bool AbstractOSPRayRenderer::generateRepresentations() { auto type = static_cast(voxelDataTypeOSP[static_cast(container.voxelDType)]); // add data - rkcommon::math::vec3i dims = {container.dimensions[0], container.dimensions[1], container.dimensions[2]}; + rkcommon::math::vec3ul dims = { + container.dimensions[0], container.dimensions[1], container.dimensions[2]}; auto voxelData = ::ospray::cpp::SharedData(container.voxels, type, dims); voxelData.commit(); @@ -1182,7 +1184,7 @@ bool AbstractOSPRayRenderer::generateRepresentations() { break; case volumeTypeEnum::SPHERICALVOLUME: { - if (!container.voxels_shared) { + if (container.voxels == nullptr) { core::utility::log::Log::DefaultLog.WriteError( "[OSPRay:generateRepresentations] Representation SPHERICALVOLUME active but no data provided."); break; @@ -1192,9 +1194,9 @@ bool AbstractOSPRayRenderer::generateRepresentations() { ::ospray::cpp::Volume("structuredSpherical"), structureTypeEnum::VOLUME); // add data - rkcommon::math::vec3i dims = { + rkcommon::math::vec3ul dims = { container.dimensions[0], container.dimensions[1], container.dimensions[2]}; - auto voxelData = ::ospray::cpp::SharedData(container.voxels_shared->data(), OSP_FLOAT, dims); + auto voxelData = ::ospray::cpp::SharedData(container.voxels, OSP_FLOAT, dims); voxelData.commit(); @@ -1290,6 +1292,33 @@ bool AbstractOSPRayRenderer::generateRepresentations() { _groups[entry.first].commit(); break; } + + _groups[entry.first] = ::ospray::cpp::Group(); + if (element->volumeType == volumeRepresentationType::ISOSURFACE) { + _groups[entry.first].setParam("geometry", ::ospray::cpp::CopiedData(_geometricModels[entry.first])); + } else { + _groups[entry.first].setParam("volume", ::ospray::cpp::CopiedData(_volumetricModels[entry.first])); + } + if (entry.second->clippingPlane.isValid) { + _baseStructures[entry.first].emplace_back(::ospray::cpp::Geometry("plane"), GEOMETRY); + + ::rkcommon::math::vec4f plane; + plane[0] = entry.second->clippingPlane.coeff[0]; + plane[1] = entry.second->clippingPlane.coeff[1]; + plane[2] = entry.second->clippingPlane.coeff[2]; + plane[3] = entry.second->clippingPlane.coeff[3]; + std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()) + .setParam("plane.coefficients", ::ospray::cpp::CopiedData(plane)); + std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()).commit(); + + _clippingModels[entry.first].emplace_back(::ospray::cpp::GeometricModel( + std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()))); + _clippingModels[entry.first].back().commit(); + + _groups[entry.first].setParam( + "clippingGeometry", ::ospray::cpp::CopiedData(_clippingModels[entry.first])); + } + _groups[entry.first].commit(); } break; } diff --git a/plugins/mmospray/src/OSPRayLineGeometry.cpp b/plugins/mmospray/src/OSPRayLineGeometry.cpp index fee2bf97dd..f1c7ca0741 100644 --- a/plugins/mmospray/src/OSPRayLineGeometry.cpp +++ b/plugins/mmospray/src/OSPRayLineGeometry.cpp @@ -8,7 +8,6 @@ #include "geometry_calls/LinesDataCall.h" #include "mesh/MeshCalls.h" #include "mmcore/Call.h" -#include "mmcore/param/BoolParam.h" #include "mmcore/param/FloatParam.h" #include "mmcore/utility/log/Log.h" #include "mmospray/CallOSPRayStructure.h" @@ -21,8 +20,7 @@ OSPRayLineGeometry::OSPRayLineGeometry(void) : AbstractOSPRayStructure() , getDataSlot("getdata", "Connects to the data source") , getLineDataSlot("getLineData", "") - , globalRadiusSlot("globalRadius", "Sets the radius of the lines") - , smoothSlot("smooth", "Set whether to smooth the lines") { + , globalRadiusSlot("globalRadius", "Sets the radius of the lines") { this->getDataSlot.SetCompatibleCall(); this->MakeSlotAvailable(&this->getDataSlot); @@ -33,8 +31,6 @@ OSPRayLineGeometry::OSPRayLineGeometry(void) this->globalRadiusSlot << new core::param::FloatParam(0.01); this->MakeSlotAvailable(&this->globalRadiusSlot); - this->smoothSlot << new core::param::BoolParam(false); - this->MakeSlotAvailable(&this->smoothSlot); } @@ -189,9 +185,8 @@ ospray::OSPRayLineGeometry::InterfaceIsDirty() bool OSPRayLineGeometry::InterfaceIsDirty() { CallOSPRayMaterial* cm = this->getMaterialSlot.CallAs(); cm->getMaterialParameter(); - if (cm->InterfaceIsDirty() || this->globalRadiusSlot.IsDirty() || this->smoothSlot.IsDirty()) { + if (cm->InterfaceIsDirty() || this->globalRadiusSlot.IsDirty()) { this->globalRadiusSlot.ResetDirty(); - this->smoothSlot.ResetDirty(); return true; } else { return false; diff --git a/plugins/mmospray/src/OSPRayLineGeometry.h b/plugins/mmospray/src/OSPRayLineGeometry.h index 5e4acc84d0..eb225bd050 100644 --- a/plugins/mmospray/src/OSPRayLineGeometry.h +++ b/plugins/mmospray/src/OSPRayLineGeometry.h @@ -65,8 +65,6 @@ class OSPRayLineGeometry : public AbstractOSPRayStructure { core::CallerSlot getLineDataSlot; core::param::ParamSlot globalRadiusSlot; - - core::param::ParamSlot smoothSlot; }; } // namespace ospray diff --git a/plugins/mmospray/src/OSPRaySphericalVolume.cpp b/plugins/mmospray/src/OSPRaySphericalVolume.cpp index 69e37ed8ea..b1eba3ed10 100644 --- a/plugins/mmospray/src/OSPRaySphericalVolume.cpp +++ b/plugins/mmospray/src/OSPRaySphericalVolume.cpp @@ -112,10 +112,10 @@ bool OSPRaySphericalVolume::readData(core::Call& call) { for (auto var : availVars) { volumeDataStringSlot.Param()->AddValue(var); } - const std::string volDataStr = - std::string(this->volumeDataStringSlot.Param()->ValueString()); // do inqures + const std::string volDataStr = + std::string(this->volumeDataStringSlot.Param()->ValueString()); if (volDataStr != "undef") { if (!cd->inquireVar(volDataStr)) { megamol::core::utility::log::Log::DefaultLog.WriteError( @@ -138,6 +138,11 @@ bool OSPRaySphericalVolume::readData(core::Call& call) { megamol::core::utility::log::Log::DefaultLog.WriteError( "[OSPRaySphericalVolume] variable \"%s\" does not exist.", gridSpacingStr.c_str()); } + const std::string gridResStr = "vol_grid_resolution"; + if (!cd->inquireVar(gridResStr)) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "[OSPRaySphericalVolume] variable \"%s\" does not exist.", gridSpacingStr.c_str()); + } if (!(*cd)(0)) { megamol::core::utility::log::Log::DefaultLog.WriteError("[OSPRaySphericalVolume] Error during GetData"); @@ -164,7 +169,7 @@ bool OSPRaySphericalVolume::readData(core::Call& call) { ->GetAsFloat(); auto gridOrigin = cd->getData(gridOrigStr)->GetAsFloat(); auto gridSpacing = cd->getData(gridSpacingStr)->GetAsFloat(); - + auto gridRes = cd->getData(gridResStr)->GetAsUInt32(); this->extendContainer.boundingBox = std::make_shared(); this->extendContainer.boundingBox->SetBoundingBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]); @@ -181,21 +186,28 @@ bool OSPRaySphericalVolume::readData(core::Call& call) { this->extendContainer.isValid = true; - auto res = cd->getData(volDataStr)->getShape(); - assert(res.size() == 3); - unsigned int const voxelCount = res[0] * res[1] * res[2]; + unsigned int const voxelCount = gridRes[0] * gridRes[1] * gridRes[2]; assert(data.size() == voxelCount); - std::array dimensions = { - static_cast(res[0]), static_cast(res[1]), static_cast(res[2])}; + std::array const dimensions = {gridRes[0], gridRes[1], gridRes[2]}; + + voxelDataType const voxelType = voxelDataType::FLOAT; - voxelDataType voxelType = voxelDataType::FLOAT; + // resort data + _resorted_data.reserve(dimensions[0] * dimensions[1]*dimensions[2]); + for (int phi = 0; phi < dimensions[2]; ++phi) { + for (int theta = 0; theta < dimensions[1]; ++theta) { + for (int r = 0; r < dimensions[0]; ++r) { + _resorted_data.emplace_back(data[r + dimensions[0] * (theta + dimensions[1] * phi)]); + } + } + } // get color transfer function std::vector rgb; std::vector a; - std::array minmax = {*std::min_element(data.begin(), data.end()), *std::max_element(data.begin(),data.end())}; + std::array const minmax = {*std::min_element(data.begin(), data.end()), *std::max_element(data.begin(),data.end())}; cgtf->SetRange(minmax); if ((*cgtf)(0)) { if (cgtf->TFTextureFormat() == core::view::CallGetTransferFunction::TextureFormat::TEXTURE_FORMAT_RGBA) { @@ -240,7 +252,7 @@ bool OSPRaySphericalVolume::readData(core::Call& call) { volumeStructure svs; svs.volRepType = (volumeRepresentationType)this->repType.Param()->Value(); - svs.voxels_shared = std::make_shared>(data); + svs.voxels = _resorted_data.data(); svs.gridOrigin = { gridOrigin[0], gridOrigin[1], gridOrigin[2]}; svs.gridSpacing = { gridSpacing[0], gridSpacing[1], gridSpacing[2]}; svs.dimensions = dimensions; diff --git a/plugins/mmospray/src/OSPRaySphericalVolume.h b/plugins/mmospray/src/OSPRaySphericalVolume.h index c78e8b53a6..09cfb36bea 100644 --- a/plugins/mmospray/src/OSPRaySphericalVolume.h +++ b/plugins/mmospray/src/OSPRaySphericalVolume.h @@ -74,6 +74,8 @@ class OSPRaySphericalVolume : public AbstractOSPRayStructure { megamol::core::param::ParamSlot repType; megamol::core::param::ParamSlot IsoValue; + + std::vector _resorted_data; }; } // namespace ospray diff --git a/plugins/mmospray/src/OSPRayStructuredVolume.cpp b/plugins/mmospray/src/OSPRayStructuredVolume.cpp index 5339f98f2a..54e3f4f313 100644 --- a/plugins/mmospray/src/OSPRayStructuredVolume.cpp +++ b/plugins/mmospray/src/OSPRayStructuredVolume.cpp @@ -119,12 +119,12 @@ bool OSPRayStructuredVolume::readData(core::Call& call) { } unsigned int const voxelCount = metadata->Resolution[0] * metadata->Resolution[1] * metadata->Resolution[2]; - std::array gridOrigin = {metadata->Origin[0], metadata->Origin[1], metadata->Origin[2]}; - std::array gridSpacing = { + const std::array gridOrigin = {metadata->Origin[0], metadata->Origin[1], metadata->Origin[2]}; + const std::array gridSpacing = { metadata->SliceDists[0][0], metadata->SliceDists[1][0], metadata->SliceDists[2][0]}; - std::array dimensions = {static_cast(metadata->Resolution[0]), - static_cast(metadata->Resolution[1]), - static_cast(metadata->Resolution[2])}; //< TODO HAZARD explicit narrowing + const std::array dimensions = {static_cast(metadata->Resolution[0]), + static_cast(metadata->Resolution[1]), + static_cast(metadata->Resolution[2])}; unsigned int const maxDim = std::max(metadata->Resolution[0], std::max(metadata->Resolution[1], metadata->Resolution[2])); @@ -167,7 +167,7 @@ bool OSPRayStructuredVolume::readData(core::Call& call) { // get color transfer function std::vector rgb; std::vector a; - std::array minmax = { + const std::array minmax = { static_cast(metadata->MinValues[0]), static_cast(metadata->MaxValues[0])}; cgtf->SetRange(minmax); if ((*cgtf)(0)) { diff --git a/plugins/probe/src/ElementColoring.cpp b/plugins/probe/src/ElementColoring.cpp index 86739e6a8a..3d02118e12 100644 --- a/plugins/probe/src/ElementColoring.cpp +++ b/plugins/probe/src/ElementColoring.cpp @@ -80,23 +80,30 @@ bool ElementColoring::getData(core::Call& call) { auto const probe_count = cp->getData()->getProbeCount(); std::vector cluster_ids(probe_count); + std::vector> vertex_ids(probe_count); for (auto i = 0; i < probe_count; i++) { auto generic_probe = cp->getData()->getGenericProbe(i); int cluster_id; + std::vector vertex_id; - auto visitor = [&cluster_id](auto&& arg) { + auto visitor = [&cluster_id, &vertex_id](auto&& arg) { using T = std::decay_t; if constexpr (std::is_same_v) { cluster_id = arg.m_cluster_id; + vertex_id = arg.m_vert_ids; } else if constexpr (std::is_same_v) { cluster_id = arg.m_cluster_id; + vertex_id = arg.m_vert_ids; } else if constexpr (std::is_same_v) { cluster_id = arg.m_cluster_id; + vertex_id = arg.m_vert_ids; } else if constexpr (std::is_same_v) { cluster_id = arg.m_cluster_id; + vertex_id = arg.m_vert_ids; } else if constexpr (std::is_same_v) { cluster_id = arg.m_cluster_id; + vertex_id = arg.m_vert_ids; } else { // unknown probe type, throw error? do nothing? } @@ -105,6 +112,8 @@ bool ElementColoring::getData(core::Call& call) { std::visit(visitor, generic_probe); cluster_ids[i] = cluster_id; + vertex_ids[i] = vertex_id; + } auto cluster_ids_sorted = cluster_ids; @@ -174,17 +183,25 @@ bool ElementColoring::getData(core::Call& call) { } } } else { - std::string mesh_id; - for (auto& m : _mesh_collection_copy.accessMeshes()) { - mesh_id = m.first; + // no elements case + std::pair mesh = + *_mesh_collection_copy.accessMeshes().begin(); + std::string mesh_id = mesh.first; + + int num_vertices = 0; + for (auto& attr : mesh.second.attributes) { + if (attr.semantic == mesh::MeshDataAccessCollection::AttributeSemanticType::POSITION) { + num_vertices = attr.byte_size / attr.stride; + } } + _mesh_copy.resize(1); - _vertColors.resize(probe_count); + _vertColors.resize(num_vertices,{1.0f,1.0f,1.0f,1.0f}); for (int j = 0; j < probe_count; ++j) { auto current_id = cluster_ids[j]; auto current_color = hsvSpiralColor(current_id - lowest_cluster_id, num_clusters); // id can be -1 - - _vertColors[j] = {current_color.x, current_color.y, current_color.z, 1.0f}; + auto& id = vertex_ids[j]; + _vertColors[id[0]] = {current_color.x, current_color.y, current_color.z, 1.0f}; } auto col_attr = mesh::MeshDataAccessCollection::VertexAttribute(); col_attr.component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; @@ -223,7 +240,7 @@ bool ElementColoring::getData(core::Call& call) { auto current_color = _fallbackColor.Param()->GetArray(); _vertColors.resize(num_verts); - for (uint64_t j = 0; j < num_verts; ++j) { + for (int j = 0; j < num_verts; ++j) { _vertColors[j] = current_color; } auto col_attr = mesh::MeshDataAccessCollection::VertexAttribute(); diff --git a/plugins/probe/src/PlaceProbes.cpp b/plugins/probe/src/PlaceProbes.cpp index 721544b605..2ce7512782 100644 --- a/plugins/probe/src/PlaceProbes.cpp +++ b/plugins/probe/src/PlaceProbes.cpp @@ -9,6 +9,8 @@ #include "mmcore/param/FloatParam.h" #include "probe/MeshUtilities.h" #include "probe/ProbeCalls.h" +#include "mmcore/view/CallClipPlane.h" +#include "mmcore/view/ClipPlane.h" #include @@ -27,6 +29,7 @@ megamol::probe::PlaceProbes::PlaceProbes() , _load_probe_positions_slot("loadProbePositions", "Load saved probe positions") , _scale_probe_begin_slot("distanceFromSurfaceFactor", "") , _override_probe_length_slot("overrideProbeLength", "") + , _clipplane_slot("getClipplane", "") , _longest_edge_index(0) { this->_probe_slot.SetCallback(CallProbes::ClassName(), CallProbes::FunctionName(0), &PlaceProbes::getData); @@ -48,6 +51,9 @@ megamol::probe::PlaceProbes::PlaceProbes() this->_centerline_slot.SetCompatibleCall(); this->MakeSlotAvailable(&this->_centerline_slot); + this->_clipplane_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->_clipplane_slot); + core::param::EnumParam* ep = new core::param::EnumParam(0); ep->SetTypePair(0, "vertices"); ep->SetTypePair(1, "dart_throwing"); @@ -629,6 +635,7 @@ bool megamol::probe::PlaceProbes::placeProbes() { if (this->_method_slot.Param()->Value() == 0) { this->vertexSampling(vertices); + processClipplane(); mesh::CallMesh* ccl = this->_centerline_slot.CallAs(); if (ccl == nullptr) { this->placeByCenterpoint(); @@ -643,10 +650,13 @@ bool megamol::probe::PlaceProbes::placeProbes() { } } else if (this->_method_slot.Param()->Value() == 1) { this->dartSampling(vertices, _mesh->accessMeshes().begin()->second.indices, distanceIndicator); + processClipplane(); } else if (this->_method_slot.Param()->Value() == 2) { this->forceDirectedSampling(_mesh->accessMeshes().begin()->second); + processClipplane(); } else if (this->_method_slot.Param()->Value() == 3) { this->loadFromFile(); + processClipplane(); } else if (this->_method_slot.Param()->Value() == 4) { for (auto& mesh : _mesh->accessMeshes()) { @@ -672,6 +682,7 @@ bool megamol::probe::PlaceProbes::placeProbes() { } this->vertexNormalSampling(vertices, normals, probe_ids); + processClipplane(); } } else if (this->_method_slot.Param()->Value() == 5) { @@ -698,6 +709,7 @@ bool megamol::probe::PlaceProbes::placeProbes() { } this->faceNormalSampling(vertices, normals, probe_ids, mesh.second.indices); + processClipplane(); } } @@ -1047,5 +1059,34 @@ bool PlaceProbes::parameterChanged(core::param::ParamSlot& p) { return true; } +void PlaceProbes::processClipplane() { + // process clipplane + auto ccp = this->_clipplane_slot.CallAs(); + + if ((ccp != nullptr) && (*ccp)()) { + glm::vec3 normal = { + ccp->GetPlane().Normal().GetX(), ccp->GetPlane().Normal().GetY(), ccp->GetPlane().Normal().GetZ()}; + float d = ccp->GetPlane().D(); + + auto probePositions = _probePositions; + auto probeVertices = _probeVertices; + _probePositions.clear(); + _probeVertices.clear(); + _probePositions.reserve(probePositions.size()); + _probeVertices.reserve(probePositions.size()); + for (int i = 0; i < probePositions.size(); ++i) { + auto point = glm::vec3( + probePositions[i][0], probePositions[i][1], probePositions[i][2]); + if (glm::dot(normal, point ) + d > 0) { + _probePositions.emplace_back(probePositions[i]); + _probeVertices.emplace_back(probeVertices[i]); + } + } + _probePositions.shrink_to_fit(); + _probeVertices.shrink_to_fit(); + + } +} + } // namespace probe } // namespace megamol diff --git a/plugins/probe/src/PlaceProbes.h b/plugins/probe/src/PlaceProbes.h index e3b5953e8b..55dfee901c 100644 --- a/plugins/probe/src/PlaceProbes.h +++ b/plugins/probe/src/PlaceProbes.h @@ -70,6 +70,8 @@ class PlaceProbes : public core::Module { core::CalleeSlot _probe_positions_slot; + core::CallerSlot _clipplane_slot; + core::param::ParamSlot _method_slot; core::param::ParamSlot _probes_per_unit_slot; core::param::ParamSlot _scale_probe_begin_slot; @@ -77,6 +79,7 @@ class PlaceProbes : public core::Module { private: + bool getData(core::Call& call); bool getMetaData(core::Call& call); @@ -98,6 +101,7 @@ class PlaceProbes : public core::Module { bool getADIOSMetaData(core::Call& call); bool loadFromFile(); bool parameterChanged(core::param::ParamSlot& p); + void processClipplane(); uint32_t _longest_edge_index; diff --git a/plugins/probe/src/SampleAlongProbes.h b/plugins/probe/src/SampleAlongProbes.h index a44f182a5e..de9ee957bf 100644 --- a/plugins/probe/src/SampleAlongProbes.h +++ b/plugins/probe/src/SampleAlongProbes.h @@ -163,6 +163,8 @@ void SampleAlongPobes::doScalarSampling(const std::shared_ptr& tre probe.m_begin = arg.m_begin; probe.m_end = arg.m_end; probe.m_cluster_id = arg.m_cluster_id; + probe.m_geo_ids = arg.m_geo_ids; + probe.m_vert_ids = arg.m_vert_ids; auto sample_step = probe.m_end / static_cast(samples_per_probe); auto radius = 0.5 * sample_step * sample_radius_factor; From 063e756b48f189b09976e0624ba705546ce48462 Mon Sep 17 00:00:00 2001 From: becherml Date: Wed, 20 Jul 2022 17:38:48 +0200 Subject: [PATCH 16/47] fix mmstd includes --- plugins/mmospray/src/OSPRaySphericalVolume.cpp | 2 +- plugins/probe/src/PlaceProbes.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/mmospray/src/OSPRaySphericalVolume.cpp b/plugins/mmospray/src/OSPRaySphericalVolume.cpp index b1eba3ed10..033da2f537 100644 --- a/plugins/mmospray/src/OSPRaySphericalVolume.cpp +++ b/plugins/mmospray/src/OSPRaySphericalVolume.cpp @@ -14,7 +14,7 @@ #include "mmcore/param/Vector3fParam.h" #include "mmcore/param/FlexEnumParam.h" #include "mmcore/utility/log/Log.h" -#include "mmcore/view/CallGetTransferFunction.h" +#include "mmstd/renderer/CallGetTransferFunction.h" using namespace megamol::ospray; diff --git a/plugins/probe/src/PlaceProbes.cpp b/plugins/probe/src/PlaceProbes.cpp index 44c81212fd..54da7be669 100644 --- a/plugins/probe/src/PlaceProbes.cpp +++ b/plugins/probe/src/PlaceProbes.cpp @@ -9,8 +9,8 @@ #include "mmcore/param/FloatParam.h" #include "probe/MeshUtilities.h" #include "probe/ProbeCalls.h" -#include "mmcore/view/CallClipPlane.h" -#include "mmcore/view/ClipPlane.h" +#include "mmstd/renderer/CallClipPlane.h" +#include "mmstd/renderer/ClipPlane.h" #include From fa3a6dd920253779dd02d9cd7c7cd6265913b505 Mon Sep 17 00:00:00 2001 From: rauts Date: Thu, 21 Jul 2022 12:11:37 +0200 Subject: [PATCH 17/47] [WIP] Convert lines for OSPRay --- plugins/mmospray/src/OSPRayLineGeometry.cpp | 70 ++++++++++++++++++++- plugins/mmospray/src/OSPRayLineGeometry.h | 8 +++ plugins/probe/src/ExtractProbeGeometry.cpp | 2 +- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/plugins/mmospray/src/OSPRayLineGeometry.cpp b/plugins/mmospray/src/OSPRayLineGeometry.cpp index f1c7ca0741..e4b6038eeb 100644 --- a/plugins/mmospray/src/OSPRayLineGeometry.cpp +++ b/plugins/mmospray/src/OSPRayLineGeometry.cpp @@ -68,7 +68,75 @@ bool OSPRayLineGeometry::readData(core::Call& call) { this->time = os->getTime(); this->structureContainer.dataChanged = true; this->extendContainer.boundingBox = std::make_shared(meta_data.m_bboxs); - cs.mesh = cm->getData(); + _converted_data = nullptr; + _converted_data = std::make_shared(); + + _converted_index = {0}; + _converted_indices.type = mesh::MeshDataAccessCollection::ValueType::UNSIGNED_INT; + _converted_indices.byte_size = _converted_index.size() * sizeof(uint32_t); + _converted_indices.data = reinterpret_cast(_converted_index.data()); + + + _converted_attribs.clear(); + _converted_vertices.clear(); + + + auto num_meshes = cm->getData()->accessMeshes().size(); + + auto first_mesh = cm->getData()->accessMeshes().begin(); + for (int m = 0; m < num_meshes; ++m) { + auto current_mesh = std::next(first_mesh,m); + if (current_mesh->second.primitive_type == mesh::MeshDataAccessCollection::LINES) { + _converted_vertices.emplace_back(); + _converted_attribs.emplace_back(); + + auto num_indices = first_mesh->second.indices.byte_size / + mesh::MeshDataAccessCollection::getByteSize(first_mesh->second.indices.type); + + _converted_vertices.back().resize(num_indices); + _converted_attribs.back().resize(num_indices/2); + + + auto indices = reinterpret_cast(current_mesh->second.indices.data); + float* vertices; + + for (auto& attr : current_mesh->second.attributes) { + if (attr.semantic == mesh::MeshDataAccessCollection::POSITION) { + vertices = reinterpret_cast(attr.data); + } + } + + for (int i = 0; i < _converted_attribs.back().size(); ++i) { + + std::array const vert0 = { + vertices[3 * indices[0] + 0], vertices[3 * indices[0] + 1], vertices[3 * indices[0] + 2]}; + std::array const vert1 = { + vertices[3 * indices[1] + 0], vertices[3 * indices[1] + 1], vertices[3 * indices[1] + 2]}; + + _converted_vertices.back()[2 * i + 0] = vert0; + _converted_vertices.back()[2 * i + 1] = vert1; + + _converted_attribs.back()[i].resize(1); + _converted_attribs.back()[i][0].semantic = mesh::MeshDataAccessCollection::AttributeSemanticType::POSITION; + _converted_attribs.back()[i][0].component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; + _converted_attribs.back()[i][0].byte_size = 2 * sizeof(std::array); + _converted_attribs.back()[i][0].component_cnt = 3; + _converted_attribs.back()[i][0].stride = 3 * sizeof(float); + _converted_attribs.back()[i][0].data = + reinterpret_cast(_converted_vertices.back()[2 * i + 0].data()); + + std::stringstream mesh_id; + mesh_id << current_mesh->first << i; + + _converted_data->addMesh(mesh_id.str(), _converted_attribs.back()[i], _converted_indices, + mesh::MeshDataAccessCollection::LINE_STRIP); + } + } else { + // leave non line meshes untouched + _converted_data->addMesh(current_mesh->first, current_mesh->second.attributes, current_mesh->second.indices, current_mesh->second.primitive_type); + } + } + cs.mesh = _converted_data; structureContainer.structure = cs; } diff --git a/plugins/mmospray/src/OSPRayLineGeometry.h b/plugins/mmospray/src/OSPRayLineGeometry.h index eb225bd050..0d28ed3b32 100644 --- a/plugins/mmospray/src/OSPRayLineGeometry.h +++ b/plugins/mmospray/src/OSPRayLineGeometry.h @@ -65,6 +65,14 @@ class OSPRayLineGeometry : public AbstractOSPRayStructure { core::CallerSlot getLineDataSlot; core::param::ParamSlot globalRadiusSlot; + + std::shared_ptr _converted_data; + std::vector>> _converted_attribs; + mesh::MeshDataAccessCollection::IndexData _converted_indices; + + std::array _converted_index; + std::vector>> _converted_vertices; + }; } // namespace ospray diff --git a/plugins/probe/src/ExtractProbeGeometry.cpp b/plugins/probe/src/ExtractProbeGeometry.cpp index 681bae9e40..95698db2c7 100644 --- a/plugins/probe/src/ExtractProbeGeometry.cpp +++ b/plugins/probe/src/ExtractProbeGeometry.cpp @@ -121,7 +121,7 @@ std::shared_ptr megamol::probe::Extract // put data in line std::string identifier = std::string(FullName()) + "_pl_" + std::to_string(i); - line->addMesh(identifier, _line_attribs[i], _line_indices); + line->addMesh(identifier, _line_attribs[i], _line_indices, mesh::MeshDataAccessCollection::LINE_STRIP); } _line = line; From 729df1be23d1cf9e63da9837d0c593173827fc0c Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 22 Jul 2022 18:29:37 +0200 Subject: [PATCH 18/47] tried to fix blend2d ended up making it optional instead --- externals/CMakeExternals.cmake | 12 +++++++----- plugins/probe/CMakeLists.txt | 11 +++++++++-- plugins/probe/src/GenerateGlyphs.cpp | 5 +++++ plugins/probe/src/GenerateGlyphs.h | 3 ++- plugins/probe/src/probe.cpp | 4 ++++ 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/externals/CMakeExternals.cmake b/externals/CMakeExternals.cmake index a69a0b1862..94670026e0 100644 --- a/externals/CMakeExternals.cmake +++ b/externals/CMakeExternals.cmake @@ -229,7 +229,7 @@ function(require_external NAME) endif () if (WIN32) - set(BLEND2D_LIB "bin/blend2d.dll") + #set(BLEND2D_LIB "bin/blend2d.dll") set(BLEND2D_IMPORT_LIB "lib/blend2d.lib") else () set(BLEND2D_LIB "lib/libblend2d.a") @@ -238,10 +238,11 @@ function(require_external NAME) require_external(asmjit) external_get_property(asmjit SOURCE_DIR) - add_external_project(blend2d SHARED + add_external_project(blend2d STATIC GIT_REPOSITORY https://github.com/blend2d/blend2d.git GIT_TAG "8aeac6cb34b00898ae725bd76eb3bb2c7cffcf86" - BUILD_BYPRODUCTS "/${BLEND2D_IMPORT_LIB}" "/${BLEND2D_LIB}" + #BUILD_BYPRODUCTS "/${BLEND2D_IMPORT_LIB}" "/${BLEND2D_LIB}" + BUILD_BYPRODUCTS "/${BLEND2D_IMPORT_LIB}" CMAKE_ARGS -DASMJIT_DIR=${SOURCE_DIR} -DBLEND2D_STATIC=ON) @@ -249,8 +250,9 @@ function(require_external NAME) add_external_library(blend2d DEPENDS asmjit INCLUDE_DIR "include" - LIBRARY ${BLEND2D_LIB} - IMPORT_LIBRARY ${BLEND2D_IMPORT_LIB}) + LIBRARY ${BLEND2D_IMPORT_LIB}) + # LIBRARY ${BLEND2D_LIB} + # IMPORT_LIBRARY ${BLEND2D_IMPORT_LIB}) # chemfiles elseif(NAME STREQUAL "chemfiles") diff --git a/plugins/probe/CMakeLists.txt b/plugins/probe/CMakeLists.txt index 70d95e3503..57b28daf67 100644 --- a/plugins/probe/CMakeLists.txt +++ b/plugins/probe/CMakeLists.txt @@ -3,6 +3,11 @@ # All rights reserved. # +option(ENABLE_BLEND2D "Use Blend2d" OFF) +if (ENABLE_BLEND2D) + set(BLEND_TARGETS asmjit blend2d) +endif() + megamol_plugin(probe BUILD_DEFAULT OFF DEPENDS_PLUGINS @@ -13,12 +18,14 @@ megamol_plugin(probe geometry_calls DEPENDS_EXTERNALS libigl - asmjit - blend2d + ${BLEND_TARGETS} PUBLIC Eigen nanoflann) if (probe_PLUGIN_ENABLED) + if (ENABLE_BLEND2D) + target_compile_definitions(probe PRIVATE "HAS_BLEND2D") + endif() file(GLOB_RECURSE ospray_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "probe_ospray/src/*.cpp") file(GLOB_RECURSE ospray_headers RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "probe_ospray/src/*.h") file(GLOB_RECURSE ospray_public_headers RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "probe_ospray/include/*.h") diff --git a/plugins/probe/src/GenerateGlyphs.cpp b/plugins/probe/src/GenerateGlyphs.cpp index c154f48b88..c8a605b430 100644 --- a/plugins/probe/src/GenerateGlyphs.cpp +++ b/plugins/probe/src/GenerateGlyphs.cpp @@ -4,6 +4,8 @@ * Alle Rechte vorbehalten. */ +#ifdef HAS_BLEND2D + #include #include "DrawTextureUtility.h" @@ -654,3 +656,6 @@ bool GenerateGlyphs::paramChanged(core::param::ParamSlot& p) { } } // namespace probe } // namespace megamol + + +#endif diff --git a/plugins/probe/src/GenerateGlyphs.h b/plugins/probe/src/GenerateGlyphs.h index 70434a509f..3a93a81700 100644 --- a/plugins/probe/src/GenerateGlyphs.h +++ b/plugins/probe/src/GenerateGlyphs.h @@ -5,7 +5,7 @@ */ #pragma once - +#ifdef HAS_BLEND2D #include "DrawTextureUtility.h" #include "mesh/ImageDataAccessCollection.h" #include "mesh/MeshDataAccessCollection.h" @@ -105,3 +105,4 @@ class GenerateGlyphs : public core::Module { } // namespace probe } // namespace megamol +#endif diff --git a/plugins/probe/src/probe.cpp b/plugins/probe/src/probe.cpp index 2cb61df76b..aab4dfee38 100644 --- a/plugins/probe/src/probe.cpp +++ b/plugins/probe/src/probe.cpp @@ -10,7 +10,9 @@ #include "ConstructKDTree.h" #include "ExtractCenterline.h" #include "ExtractProbeGeometry.h" +#ifdef HAS_BLEND2D #include "GenerateGlyphs.h" +#endif #include "ManipulateMesh.h" #include "PlaceProbes.h" #include "ProbesToTable.h" @@ -51,7 +53,9 @@ class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPlug this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); +#ifdef HAS_BLEND2D this->module_descriptions.RegisterAutoDescription(); +#endif this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); From f73de1552281f85fef0b0cf458b713dc72dcc433 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 22 Jul 2022 18:30:02 +0200 Subject: [PATCH 19/47] fixed return in billboard --- plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp b/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp index a7898550ff..6b73123dc1 100644 --- a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp +++ b/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp @@ -869,6 +869,7 @@ bool megamol::probe_gl::ProbeBillboardGlyphRenderTasks::addAllRenderTasks() { m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), m_clusterID_glyph_identifiers.begin(), m_clusterID_glyph_identifiers.end()); } + return true; } void megamol::probe_gl::ProbeBillboardGlyphRenderTasks::updateAllRenderTasks() { From 6d515c049485183e2f42534d525e7cbb6ea47577 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 22 Jul 2022 18:30:37 +0200 Subject: [PATCH 20/47] missing staged file for blend2d commit --- plugins/probe/src/DrawTextureUtility.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/probe/src/DrawTextureUtility.h b/plugins/probe/src/DrawTextureUtility.h index 585cb10779..f23d603184 100644 --- a/plugins/probe/src/DrawTextureUtility.h +++ b/plugins/probe/src/DrawTextureUtility.h @@ -5,7 +5,7 @@ */ #pragma once - +#ifdef HAS_BLEND2D #include "blend2d.h" #include "mmcore/utility/log/Log.h" #include @@ -409,3 +409,4 @@ inline void DrawTextureUtility::drawRadarGlyph(std::vector& data, std::array< } // namespace probe } // namespace megamol +#endif From 894074ea446fa2be17c9c710a6a2ebf1ba7546ac Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 22 Jul 2022 18:31:52 +0200 Subject: [PATCH 21/47] added conversion of line data (obj, gltf) to ospray line geometry --- .../include/mmospray/CallOSPRayStructure.h | 3 + .../mmospray/src/AbstractOSPRayRenderer.cpp | 21 ++++- plugins/mmospray/src/OSPRayLineGeometry.cpp | 91 +++++++++++-------- plugins/mmospray/src/OSPRayLineGeometry.h | 7 +- 4 files changed, 79 insertions(+), 43 deletions(-) diff --git a/plugins/mmospray/include/mmospray/CallOSPRayStructure.h b/plugins/mmospray/include/mmospray/CallOSPRayStructure.h index e1b6a008da..18e95379ae 100644 --- a/plugins/mmospray/include/mmospray/CallOSPRayStructure.h +++ b/plugins/mmospray/include/mmospray/CallOSPRayStructure.h @@ -27,6 +27,8 @@ enum volumeTypeEnum { STRUCTUREDVOLUME, BLOCKBRICKEDVOLUME, GHOSTBLOCKBRICKEDVOL enum volumeRepresentationType { VOLUMEREP, ISOSURFACE, SLICE }; +enum curveRepresentationType { FLAT, ROUND, RIBBON, DISJOINT }; + enum class voxelDataType : uint8_t { UCHAR = 0, SHORT = 1, USHORT = 2, FLOAT = 3, DOUBLE = 4 }; static std::string voxelDataTypeS[] = {"uchar", "short", "ushort", "float", "double"}; @@ -79,6 +81,7 @@ struct curveStructure { std::shared_ptr> vertexData; std::shared_ptr> colorData; std::shared_ptr> indexData; + curveRepresentationType representation = ROUND; unsigned int vertexLength; unsigned int dataStride; unsigned int colorLength; diff --git a/plugins/mmospray/src/AbstractOSPRayRenderer.cpp b/plugins/mmospray/src/AbstractOSPRayRenderer.cpp index 1cc5cc72fb..a37a2b32ef 100644 --- a/plugins/mmospray/src/AbstractOSPRayRenderer.cpp +++ b/plugins/mmospray/src/AbstractOSPRayRenderer.cpp @@ -1086,9 +1086,26 @@ bool AbstractOSPRayRenderer::generateRepresentations() { std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()) .setParam("radius", container.globalRadius); - // TODO: Add user input support for this + auto repType = OSP_ROUND; + switch (container.representation) { + case (curveRepresentationType::FLAT): { + repType = OSP_FLAT; + break; + } + case (curveRepresentationType::RIBBON): { + repType = OSP_RIBBON; + break; + } + case (curveRepresentationType::DISJOINT): { + repType = OSP_DISJOINT; + break; + } + default: + break; + } std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()) - .setParam("type", OSP_ROUND); + .setParam("type", repType); + // TODO: Add user input support for this std::get<::ospray::cpp::Geometry>(_baseStructures[entry.first].structures.back()) .setParam("basis", OSP_LINEAR); diff --git a/plugins/mmospray/src/OSPRayLineGeometry.cpp b/plugins/mmospray/src/OSPRayLineGeometry.cpp index e4b6038eeb..dfb5e3d1fa 100644 --- a/plugins/mmospray/src/OSPRayLineGeometry.cpp +++ b/plugins/mmospray/src/OSPRayLineGeometry.cpp @@ -9,6 +9,7 @@ #include "mesh/MeshCalls.h" #include "mmcore/Call.h" #include "mmcore/param/FloatParam.h" +#include "mmcore/param/EnumParam.h" #include "mmcore/utility/log/Log.h" #include "mmospray/CallOSPRayStructure.h" @@ -20,16 +21,25 @@ OSPRayLineGeometry::OSPRayLineGeometry(void) : AbstractOSPRayStructure() , getDataSlot("getdata", "Connects to the data source") , getLineDataSlot("getLineData", "") - , globalRadiusSlot("globalRadius", "Sets the radius of the lines") { + , globalRadiusSlot("globalRadius", "Sets the radius of the lines") + , representationSlot("lineRepresentation", "Sets the representation type of the line structure") { - this->getDataSlot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->getDataSlot); + getDataSlot.SetCompatibleCall(); + MakeSlotAvailable(&getDataSlot); - this->getLineDataSlot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->getLineDataSlot); + getLineDataSlot.SetCompatibleCall(); + MakeSlotAvailable(&getLineDataSlot); - this->globalRadiusSlot << new core::param::FloatParam(0.01); - this->MakeSlotAvailable(&this->globalRadiusSlot); + globalRadiusSlot << new core::param::FloatParam(0.01); + MakeSlotAvailable(&globalRadiusSlot); + + auto repType = new megamol::core::param::EnumParam(curveRepresentationType::ROUND); + repType->SetTypePair(curveRepresentationType::ROUND, "round"); + repType->SetTypePair(curveRepresentationType::FLAT, "flat"); + repType->SetTypePair(curveRepresentationType::RIBBON, "ribbon"); + repType->SetTypePair(curveRepresentationType::DISJOINT, "disjoint"); + this->representationSlot << repType; + MakeSlotAvailable(&representationSlot); } @@ -71,12 +81,6 @@ bool OSPRayLineGeometry::readData(core::Call& call) { _converted_data = nullptr; _converted_data = std::make_shared(); - _converted_index = {0}; - _converted_indices.type = mesh::MeshDataAccessCollection::ValueType::UNSIGNED_INT; - _converted_indices.byte_size = _converted_index.size() * sizeof(uint32_t); - _converted_indices.data = reinterpret_cast(_converted_index.data()); - - _converted_attribs.clear(); _converted_vertices.clear(); @@ -89,12 +93,14 @@ bool OSPRayLineGeometry::readData(core::Call& call) { if (current_mesh->second.primitive_type == mesh::MeshDataAccessCollection::LINES) { _converted_vertices.emplace_back(); _converted_attribs.emplace_back(); + _converted_index.emplace_back(); + _converted_indices.emplace_back(); - auto num_indices = first_mesh->second.indices.byte_size / - mesh::MeshDataAccessCollection::getByteSize(first_mesh->second.indices.type); + auto num_indices = first_mesh->second.indices.byte_size / mesh::MeshDataAccessCollection::getByteSize(first_mesh->second.indices.type); _converted_vertices.back().resize(num_indices); - _converted_attribs.back().resize(num_indices/2); + _converted_attribs.back().resize(1); + _converted_index.back().reserve(num_indices / 2); auto indices = reinterpret_cast(current_mesh->second.indices.data); @@ -106,31 +112,36 @@ bool OSPRayLineGeometry::readData(core::Call& call) { } } - for (int i = 0; i < _converted_attribs.back().size(); ++i) { + for (int i = 0; i < num_indices/2; ++i) { std::array const vert0 = { - vertices[3 * indices[0] + 0], vertices[3 * indices[0] + 1], vertices[3 * indices[0] + 2]}; + vertices[3 * indices[2*i + 0] + 0], vertices[3 * indices[2*i + 0] + 1], vertices[3 * indices[2*i + 0] + 2]}; std::array const vert1 = { - vertices[3 * indices[1] + 0], vertices[3 * indices[1] + 1], vertices[3 * indices[1] + 2]}; - + vertices[3 * indices[2*i + 1] + 0], vertices[3 * indices[2*i + 1] + 1], vertices[3 * indices[2*i + 1] + 2]}; _converted_vertices.back()[2 * i + 0] = vert0; _converted_vertices.back()[2 * i + 1] = vert1; + _converted_index.back().emplace_back(2 * i); - _converted_attribs.back()[i].resize(1); - _converted_attribs.back()[i][0].semantic = mesh::MeshDataAccessCollection::AttributeSemanticType::POSITION; - _converted_attribs.back()[i][0].component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; - _converted_attribs.back()[i][0].byte_size = 2 * sizeof(std::array); - _converted_attribs.back()[i][0].component_cnt = 3; - _converted_attribs.back()[i][0].stride = 3 * sizeof(float); - _converted_attribs.back()[i][0].data = - reinterpret_cast(_converted_vertices.back()[2 * i + 0].data()); + } - std::stringstream mesh_id; - mesh_id << current_mesh->first << i; - _converted_data->addMesh(mesh_id.str(), _converted_attribs.back()[i], _converted_indices, - mesh::MeshDataAccessCollection::LINE_STRIP); - } + _converted_attribs.back().resize(1); + _converted_attribs.back()[0].semantic = + mesh::MeshDataAccessCollection::AttributeSemanticType::POSITION; + _converted_attribs.back()[0].component_type = mesh::MeshDataAccessCollection::ValueType::FLOAT; + _converted_attribs.back()[0].byte_size = _converted_vertices.back().size() * sizeof(std::array); + _converted_attribs.back()[0].component_cnt = 3; + _converted_attribs.back()[0].stride = 3 * sizeof(float); + _converted_attribs.back()[0].data = + reinterpret_cast(_converted_vertices.back().data()); + + + _converted_indices.back().type = mesh::MeshDataAccessCollection::ValueType::UNSIGNED_INT; + _converted_indices.back().byte_size = _converted_index.back().size() * sizeof(uint32_t); + _converted_indices.back().data = reinterpret_cast(_converted_index.back().data()); + + _converted_data->addMesh(current_mesh->first, _converted_attribs.back(), _converted_indices.back(), + mesh::MeshDataAccessCollection::LINE_STRIP); } else { // leave non line meshes untouched _converted_data->addMesh(current_mesh->first, current_mesh->second.attributes, current_mesh->second.indices, current_mesh->second.primitive_type); @@ -229,9 +240,12 @@ bool OSPRayLineGeometry::readData(core::Call& call) { cs.indexData = std::make_shared>(std::move(index)); } - this->structureContainer.type = structureTypeEnum::GEOMETRY; - this->structureContainer.geometryType = geometryTypeEnum::LINES; + + + structureContainer.type = structureTypeEnum::GEOMETRY; + structureContainer.geometryType = geometryTypeEnum::LINES; cs.globalRadius = globalRadiusSlot.Param()->Value(); + cs.representation = curveRepresentationType(representationSlot.Param()->Value()); structureContainer.structure = cs; return true; @@ -251,10 +265,11 @@ void OSPRayLineGeometry::release() {} ospray::OSPRayLineGeometry::InterfaceIsDirty() */ bool OSPRayLineGeometry::InterfaceIsDirty() { - CallOSPRayMaterial* cm = this->getMaterialSlot.CallAs(); + CallOSPRayMaterial* cm = getMaterialSlot.CallAs(); cm->getMaterialParameter(); - if (cm->InterfaceIsDirty() || this->globalRadiusSlot.IsDirty()) { - this->globalRadiusSlot.ResetDirty(); + if (cm->InterfaceIsDirty() || globalRadiusSlot.IsDirty() || representationSlot.IsDirty()) { + globalRadiusSlot.ResetDirty(); + representationSlot.ResetDirty(); return true; } else { return false; diff --git a/plugins/mmospray/src/OSPRayLineGeometry.h b/plugins/mmospray/src/OSPRayLineGeometry.h index 0d28ed3b32..e815bf3431 100644 --- a/plugins/mmospray/src/OSPRayLineGeometry.h +++ b/plugins/mmospray/src/OSPRayLineGeometry.h @@ -65,12 +65,13 @@ class OSPRayLineGeometry : public AbstractOSPRayStructure { core::CallerSlot getLineDataSlot; core::param::ParamSlot globalRadiusSlot; + core::param::ParamSlot representationSlot; std::shared_ptr _converted_data; - std::vector>> _converted_attribs; - mesh::MeshDataAccessCollection::IndexData _converted_indices; + std::vector> _converted_attribs; + std::vector _converted_indices; - std::array _converted_index; + std::vector> _converted_index; std::vector>> _converted_vertices; }; From 520ef8ae46459fb27f21fcf62eeedd380a75c527 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 22 Jul 2022 18:32:22 +0200 Subject: [PATCH 22/47] mesh selector was doing strange things, fixed that --- plugins/probe/src/MeshSelector.cpp | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/plugins/probe/src/MeshSelector.cpp b/plugins/probe/src/MeshSelector.cpp index 2d32ae572d..15d6b6ed49 100644 --- a/plugins/probe/src/MeshSelector.cpp +++ b/plugins/probe/src/MeshSelector.cpp @@ -219,16 +219,26 @@ bool MeshSelector::getData(core::Call& call) { cm->setMetaData(mesh_meta_data); } - auto const& mesh = cd->getData()->accessMeshes().begin()->second; + auto const& first_mesh = cd->getData()->accessMeshes().begin()->second; if (something_changed || _recalc) { + _meshNumberSlot.Param()->ClearValues(); + int const num_meshes = cd->getData()->accessMeshes().size(); + for (int i = 0; i < num_meshes; i++) { + auto const current_mesh = std::next(cd->getData()->accessMeshes().begin(), i); + for (auto& attr : current_mesh->second.attributes) { + if (attr.semantic == mesh::MeshDataAccessCollection::POSITION) { + _meshNumberSlot.Param()->AddValue(std::to_string(i)); + } + } + } _selected_mesh = std::stoi(_meshNumberSlot.Param()->Value()); + auto const selected_mesh = std::next(cd->getData()->accessMeshes().begin(), _selected_mesh); - _meshNumberSlot.Param()->ClearValues(); if (_splitMeshSlot.Param()->Value()) { if (_grouped_indices.empty() || cd->hasUpdate()) - this->splitMesh(mesh); + this->splitMesh(selected_mesh->second); assert(_grouped_indices.size() > 0); @@ -236,21 +246,13 @@ bool MeshSelector::getData(core::Call& call) { _meshNumberSlot.Param()->AddValue(std::to_string(i)); } } else { - int num_meshes = 0; - for (int i = 0; i < mesh.attributes.size(); i++) { - if (mesh.attributes.data()->semantic == mesh::MeshDataAccessCollection::POSITION) { - _meshNumberSlot.Param()->AddValue(std::to_string(num_meshes)); - num_meshes++; - } - } - _mesh_attribs.resize(1); - _mesh_attribs[0] = mesh.attributes[_selected_mesh]; + + _mesh_attribs = selected_mesh->second.attributes; _mesh_indices.resize(1); - _mesh_indices[0] = mesh.indices; + _mesh_indices[0] = selected_mesh->second.indices; } - ++_version; } @@ -264,9 +266,9 @@ bool MeshSelector::getData(core::Call& call) { _mesh_indices[0].type = mesh::MeshDataAccessCollection::ValueType::UNSIGNED_INT; _mesh_indices[0].byte_size = _grouped_indices[_selected_mesh].size() * sizeof(std::array); _mesh_indices[0].data = reinterpret_cast(_grouped_indices[_selected_mesh].data()); - + auto const selected_mesh = std::next(cd->getData()->accessMeshes().begin(), _selected_mesh); out_mesh_collection.addMesh( - identifier, mesh.attributes, _mesh_indices[0], mesh::MeshDataAccessCollection::PrimitiveType::TRIANGLES); + identifier, selected_mesh->second.attributes, _mesh_indices[0], mesh::MeshDataAccessCollection::PrimitiveType::TRIANGLES); // debugging stuff // for (int i = 0; i < _grouped_indices.size(); ++i) { // _mesh_indices[i].type = mesh::MeshDataAccessCollection::ValueType::UNSIGNED_INT; From 2aee1caad7a69bd555357b7f87e106e373ecee8c Mon Sep 17 00:00:00 2001 From: invor Date: Sat, 6 Aug 2022 03:01:59 +0200 Subject: [PATCH 23/47] Update probe_gl to new mesh_gl monolithic renderer desing --- plugins/probe_gl/shaders/FilterByProbe.btf | 24 - .../glyphs/clusterID_probe_glyph.frag.glsl | 0 .../glyphs/clusterID_probe_glyph.vert.glsl | 0 .../glyphs/clusterID_probe_struct.inc.glsl | 0 .../{ => probe_gl}/glyphs/extensions.inc.glsl | 0 .../scalar_distribution_probe_glyph.frag.glsl | 0 ...alar_distribution_probe_glyph_v2.vert.glsl | 0 .../scalar_distribution_probe_struct.inc.glsl | 0 .../glyphs/scalar_probe_glyph.frag.glsl | 0 .../glyphs/scalar_probe_glyph.vert.glsl | 0 .../glyphs/scalar_probe_glyph_v2.frag.glsl | 0 .../glyphs/scalar_probe_glyph_v2.vert.glsl | 0 .../glyphs/scalar_probe_struct.inc.glsl | 0 .../glyphs/textured_probe_glyph.frag.glsl | 0 .../glyphs/textured_probe_glyph.vert.glsl | 0 .../glyphs/vector_probe_glyph.frag.glsl | 0 .../glyphs/vector_probe_glyph.vert.glsl | 0 .../glyphs/vector_probe_struct.inc.glsl | 0 .../{ => probe_gl}/hull/dfr_hull.frag.glsl | 0 .../{ => probe_gl}/hull/dfr_hull.tesc.glsl | 0 .../{ => probe_gl}/hull/dfr_hull.tese.glsl | 0 .../hull/dfr_hull_patch.vert.glsl | 0 .../hull/dfr_hull_tri.vert.glsl | 0 .../{ => probe_gl}/hull/dfr_hull_vertex.glsl | 0 .../hull/dfr_shell_elements.frag.glsl | 0 .../hull/dfr_shell_elements.vert.glsl | 0 .../probes/dfr_interaction_probe.frag.glsl | 0 .../probes/dfr_interaction_probe.vert.glsl | 0 .../probes/dfr_probeDetailView.frag.glsl | 0 .../probes/dfr_probeDetailView.tesc.glsl | 0 .../probes/dfr_probeDetailView.tese.glsl | 0 .../probes/dfr_probeDetailView.vert.glsl | 0 .../dfr_probeDetailViewUI_fragment.glsl | 0 .../utility/dfr_probeDetailViewUI_vertex.glsl | 0 .../utility/filterAll.comp.glsl} | 3 + .../utility/filterNone.comp.glsl} | 3 + .../utility/hsv-spiral_colors.inc.glsl | 0 .../utility/random_colors_lut.inc.glsl | 0 .../utility/setFlags.comp.glsl} | 3 + plugins/probe_gl/src/FilterByProbe.cpp | 110 +- plugins/probe_gl/src/FilterByProbe.h | 10 +- .../src/ProbeBillboardGlyphMaterial.cpp | 258 ----- .../src/ProbeBillboardGlyphMaterial.h | 83 -- .../src/ProbeBillboardGlyphRenderTasks.cpp | 1005 ----------------- ...rTasks.cpp => ProbeDetailViewRenderer.cpp} | 171 +-- ...enderTasks.h => ProbeDetailViewRenderer.h} | 38 +- plugins/probe_gl/src/ProbeGlyphRenderer.cpp | 903 +++++++++++++++ ...lyphRenderTasks.h => ProbeGlyphRenderer.h} | 43 +- plugins/probe_gl/src/ProbeHullRenderTasks.cpp | 303 ----- plugins/probe_gl/src/ProbeHullRenderer.cpp | 201 ++++ ...eHullRenderTasks.h => ProbeHullRenderer.h} | 32 +- plugins/probe_gl/src/ProbeRenderTasks.cpp | 340 ------ plugins/probe_gl/src/ProbeRenderer.cpp | 287 +++++ .../{ProbeRenderTasks.h => ProbeRenderer.h} | 41 +- .../src/ProbeShellElementsRenderTasks.cpp | 264 ----- .../src/ProbeShellElementsRenderer.cpp | 174 +++ ...erTasks.h => ProbeShellElementsRenderer.h} | 28 +- plugins/probe_gl/src/probe_gl.cpp | 18 +- 58 files changed, 1745 insertions(+), 2597 deletions(-) delete mode 100644 plugins/probe_gl/shaders/FilterByProbe.btf rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/clusterID_probe_glyph.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/clusterID_probe_glyph.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/clusterID_probe_struct.inc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/extensions.inc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_distribution_probe_glyph.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_distribution_probe_struct.inc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_probe_glyph.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_probe_glyph.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_probe_glyph_v2.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_probe_glyph_v2.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/scalar_probe_struct.inc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/textured_probe_glyph.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/textured_probe_glyph.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/vector_probe_glyph.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/vector_probe_glyph.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/glyphs/vector_probe_struct.inc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_hull.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_hull.tesc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_hull.tese.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_hull_patch.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_hull_tri.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_hull_vertex.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_shell_elements.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/hull/dfr_shell_elements.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/probes/dfr_interaction_probe.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/probes/dfr_interaction_probe.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/probes/dfr_probeDetailView.frag.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/probes/dfr_probeDetailView.tesc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/probes/dfr_probeDetailView.tese.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/probes/dfr_probeDetailView.vert.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/utility/dfr_probeDetailViewUI_fragment.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/utility/dfr_probeDetailViewUI_vertex.glsl (100%) rename plugins/probe_gl/shaders/{utility/filterAll.glsl => probe_gl/utility/filterAll.comp.glsl} (87%) rename plugins/probe_gl/shaders/{utility/filterNone.glsl => probe_gl/utility/filterNone.comp.glsl} (87%) rename plugins/probe_gl/shaders/{ => probe_gl}/utility/hsv-spiral_colors.inc.glsl (100%) rename plugins/probe_gl/shaders/{ => probe_gl}/utility/random_colors_lut.inc.glsl (100%) rename plugins/probe_gl/shaders/{utility/setFlags.glsl => probe_gl/utility/setFlags.comp.glsl} (90%) delete mode 100644 plugins/probe_gl/src/ProbeBillboardGlyphMaterial.cpp delete mode 100644 plugins/probe_gl/src/ProbeBillboardGlyphMaterial.h delete mode 100644 plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp rename plugins/probe_gl/src/{ProbeDetailViewRenderTasks.cpp => ProbeDetailViewRenderer.cpp} (76%) rename plugins/probe_gl/src/{ProbeDetailViewRenderTasks.h => ProbeDetailViewRenderer.h} (72%) create mode 100644 plugins/probe_gl/src/ProbeGlyphRenderer.cpp rename plugins/probe_gl/src/{ProbeBillboardGlyphRenderTasks.h => ProbeGlyphRenderer.h} (86%) delete mode 100644 plugins/probe_gl/src/ProbeHullRenderTasks.cpp create mode 100644 plugins/probe_gl/src/ProbeHullRenderer.cpp rename plugins/probe_gl/src/{ProbeHullRenderTasks.h => ProbeHullRenderer.h} (66%) delete mode 100644 plugins/probe_gl/src/ProbeRenderTasks.cpp create mode 100644 plugins/probe_gl/src/ProbeRenderer.cpp rename plugins/probe_gl/src/{ProbeRenderTasks.h => ProbeRenderer.h} (60%) delete mode 100644 plugins/probe_gl/src/ProbeShellElementsRenderTasks.cpp create mode 100644 plugins/probe_gl/src/ProbeShellElementsRenderer.cpp rename plugins/probe_gl/src/{ProbeShellElementsRenderTasks.h => ProbeShellElementsRenderer.h} (70%) diff --git a/plugins/probe_gl/shaders/FilterByProbe.btf b/plugins/probe_gl/shaders/FilterByProbe.btf deleted file mode 100644 index 3ab5d2d669..0000000000 --- a/plugins/probe_gl/shaders/FilterByProbe.btf +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - 430 - - utility/setFlags.glsl - - - - 430 - - utility/filterAll.glsl - - - - 430 - - utility/filterNone.glsl - - - diff --git a/plugins/probe_gl/shaders/glyphs/clusterID_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/clusterID_probe_glyph.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.frag.glsl diff --git a/plugins/probe_gl/shaders/glyphs/clusterID_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/clusterID_probe_glyph.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.vert.glsl diff --git a/plugins/probe_gl/shaders/glyphs/clusterID_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_struct.inc.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/clusterID_probe_struct.inc.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_struct.inc.glsl diff --git a/plugins/probe_gl/shaders/glyphs/extensions.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/extensions.inc.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/extensions.inc.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/extensions.inc.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_distribution_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_distribution_probe_glyph.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_distribution_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_distribution_probe_struct.inc.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_probe_glyph.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_probe_glyph.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_probe_glyph_v2.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_probe_glyph_v2.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_probe_glyph_v2.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl diff --git a/plugins/probe_gl/shaders/glyphs/scalar_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_struct.inc.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/scalar_probe_struct.inc.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_struct.inc.glsl diff --git a/plugins/probe_gl/shaders/glyphs/textured_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/textured_probe_glyph.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/textured_probe_glyph.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/textured_probe_glyph.frag.glsl diff --git a/plugins/probe_gl/shaders/glyphs/textured_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/textured_probe_glyph.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/textured_probe_glyph.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/textured_probe_glyph.vert.glsl diff --git a/plugins/probe_gl/shaders/glyphs/vector_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/vector_probe_glyph.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl diff --git a/plugins/probe_gl/shaders/glyphs/vector_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/vector_probe_glyph.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl diff --git a/plugins/probe_gl/shaders/glyphs/vector_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_struct.inc.glsl similarity index 100% rename from plugins/probe_gl/shaders/glyphs/vector_probe_struct.inc.glsl rename to plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_struct.inc.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_hull.frag.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_hull.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.frag.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_hull.tesc.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.tesc.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_hull.tesc.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.tesc.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_hull.tese.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.tese.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_hull.tese.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.tese.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_hull_patch.vert.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull_patch.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_hull_patch.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_hull_patch.vert.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_hull_tri.vert.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull_tri.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_hull_tri.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_hull_tri.vert.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_hull_vertex.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull_vertex.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_hull_vertex.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_hull_vertex.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_shell_elements.frag.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_shell_elements.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_shell_elements.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_shell_elements.frag.glsl diff --git a/plugins/probe_gl/shaders/hull/dfr_shell_elements.vert.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_shell_elements.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/hull/dfr_shell_elements.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/hull/dfr_shell_elements.vert.glsl diff --git a/plugins/probe_gl/shaders/probes/dfr_interaction_probe.frag.glsl b/plugins/probe_gl/shaders/probe_gl/probes/dfr_interaction_probe.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/probes/dfr_interaction_probe.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/probes/dfr_interaction_probe.frag.glsl diff --git a/plugins/probe_gl/shaders/probes/dfr_interaction_probe.vert.glsl b/plugins/probe_gl/shaders/probe_gl/probes/dfr_interaction_probe.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/probes/dfr_interaction_probe.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/probes/dfr_interaction_probe.vert.glsl diff --git a/plugins/probe_gl/shaders/probes/dfr_probeDetailView.frag.glsl b/plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.frag.glsl similarity index 100% rename from plugins/probe_gl/shaders/probes/dfr_probeDetailView.frag.glsl rename to plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.frag.glsl diff --git a/plugins/probe_gl/shaders/probes/dfr_probeDetailView.tesc.glsl b/plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.tesc.glsl similarity index 100% rename from plugins/probe_gl/shaders/probes/dfr_probeDetailView.tesc.glsl rename to plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.tesc.glsl diff --git a/plugins/probe_gl/shaders/probes/dfr_probeDetailView.tese.glsl b/plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.tese.glsl similarity index 100% rename from plugins/probe_gl/shaders/probes/dfr_probeDetailView.tese.glsl rename to plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.tese.glsl diff --git a/plugins/probe_gl/shaders/probes/dfr_probeDetailView.vert.glsl b/plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.vert.glsl similarity index 100% rename from plugins/probe_gl/shaders/probes/dfr_probeDetailView.vert.glsl rename to plugins/probe_gl/shaders/probe_gl/probes/dfr_probeDetailView.vert.glsl diff --git a/plugins/probe_gl/shaders/utility/dfr_probeDetailViewUI_fragment.glsl b/plugins/probe_gl/shaders/probe_gl/utility/dfr_probeDetailViewUI_fragment.glsl similarity index 100% rename from plugins/probe_gl/shaders/utility/dfr_probeDetailViewUI_fragment.glsl rename to plugins/probe_gl/shaders/probe_gl/utility/dfr_probeDetailViewUI_fragment.glsl diff --git a/plugins/probe_gl/shaders/utility/dfr_probeDetailViewUI_vertex.glsl b/plugins/probe_gl/shaders/probe_gl/utility/dfr_probeDetailViewUI_vertex.glsl similarity index 100% rename from plugins/probe_gl/shaders/utility/dfr_probeDetailViewUI_vertex.glsl rename to plugins/probe_gl/shaders/probe_gl/utility/dfr_probeDetailViewUI_vertex.glsl diff --git a/plugins/probe_gl/shaders/utility/filterAll.glsl b/plugins/probe_gl/shaders/probe_gl/utility/filterAll.comp.glsl similarity index 87% rename from plugins/probe_gl/shaders/utility/filterAll.glsl rename to plugins/probe_gl/shaders/probe_gl/utility/filterAll.comp.glsl index d181f7b53b..c2758d4f6c 100644 --- a/plugins/probe_gl/shaders/utility/filterAll.glsl +++ b/plugins/probe_gl/shaders/probe_gl/utility/filterAll.comp.glsl @@ -1,3 +1,6 @@ +#version 450 + +#include "mmstd_gl/flags/bitflags.inc.glsl" layout(std430, binding = 1) buffer Flags { uint flagsArray[]; diff --git a/plugins/probe_gl/shaders/utility/filterNone.glsl b/plugins/probe_gl/shaders/probe_gl/utility/filterNone.comp.glsl similarity index 87% rename from plugins/probe_gl/shaders/utility/filterNone.glsl rename to plugins/probe_gl/shaders/probe_gl/utility/filterNone.comp.glsl index 28937ab3b7..8e72d83bde 100644 --- a/plugins/probe_gl/shaders/utility/filterNone.glsl +++ b/plugins/probe_gl/shaders/probe_gl/utility/filterNone.comp.glsl @@ -1,3 +1,6 @@ +#version 450 + +#include "mmstd_gl/flags/bitflags.inc.glsl" layout(std430, binding = 1) buffer Flags { uint flagsArray[]; diff --git a/plugins/probe_gl/shaders/utility/hsv-spiral_colors.inc.glsl b/plugins/probe_gl/shaders/probe_gl/utility/hsv-spiral_colors.inc.glsl similarity index 100% rename from plugins/probe_gl/shaders/utility/hsv-spiral_colors.inc.glsl rename to plugins/probe_gl/shaders/probe_gl/utility/hsv-spiral_colors.inc.glsl diff --git a/plugins/probe_gl/shaders/utility/random_colors_lut.inc.glsl b/plugins/probe_gl/shaders/probe_gl/utility/random_colors_lut.inc.glsl similarity index 100% rename from plugins/probe_gl/shaders/utility/random_colors_lut.inc.glsl rename to plugins/probe_gl/shaders/probe_gl/utility/random_colors_lut.inc.glsl diff --git a/plugins/probe_gl/shaders/utility/setFlags.glsl b/plugins/probe_gl/shaders/probe_gl/utility/setFlags.comp.glsl similarity index 90% rename from plugins/probe_gl/shaders/utility/setFlags.glsl rename to plugins/probe_gl/shaders/probe_gl/utility/setFlags.comp.glsl index 64a0748a0c..b221920b40 100644 --- a/plugins/probe_gl/shaders/utility/setFlags.glsl +++ b/plugins/probe_gl/shaders/probe_gl/utility/setFlags.comp.glsl @@ -1,3 +1,6 @@ +#version 450 + +#include "mmstd_gl/flags/bitflags.inc.glsl" layout(std430, binding = 0) readonly buffer InputIDs { uint ids[]; diff --git a/plugins/probe_gl/src/FilterByProbe.cpp b/plugins/probe_gl/src/FilterByProbe.cpp index 2df30fc309..5896309f4b 100644 --- a/plugins/probe_gl/src/FilterByProbe.cpp +++ b/plugins/probe_gl/src/FilterByProbe.cpp @@ -3,7 +3,7 @@ #include "ProbeEvents.h" #include "ProbeGlCalls.h" #include "mmcore/CoreInstance.h" -#include "mmcore_gl/utility/ShaderSourceFactory.h" +#include "mmcore_gl/utility/ShaderFactory.h" #include "mmstd/event/EventCall.h" #include "mmstd_gl/flags/FlagCallsGL.h" #include "probe/CallKDTree.h" @@ -44,50 +44,20 @@ FilterByProbe::~FilterByProbe() { } bool FilterByProbe::create() { - try { - // create shader program - m_setFlags_prgm = std::make_unique(); - m_filterAll_prgm = std::make_unique(); - m_filterNone_prgm = std::make_unique(); - - vislib_gl::graphics::gl::ShaderSource setFlags_src; - vislib_gl::graphics::gl::ShaderSource filterAll_src; - vislib_gl::graphics::gl::ShaderSource filterNone_src; - - auto ssf = - std::make_shared(instance()->Configuration().ShaderDirectories()); - - if (!ssf->MakeShaderSource("FilterByProbe::setFlags", setFlags_src)) - return false; - if (!m_setFlags_prgm->Compile(setFlags_src.Code(), setFlags_src.Count())) - return false; - if (!m_setFlags_prgm->Link()) - return false; + auto const shader_options = msf::ShaderFactoryOptionsOpenGL(GetCoreInstance()->GetShaderPaths()); - if (!ssf->MakeShaderSource("FilterByProbe::filterAll", filterAll_src)) - return false; - if (!m_filterAll_prgm->Compile(filterAll_src.Code(), filterAll_src.Count())) - return false; - if (!m_filterAll_prgm->Link()) - return false; + try { + m_setFlags_prgm = + core::utility::make_glowl_shader("setFlags", shader_options, "probe_gl/utility/setFlags.comp.glsl"); - if (!ssf->MakeShaderSource("FilterByProbe::filterNone", filterNone_src)) - return false; - if (!m_filterNone_prgm->Compile(filterNone_src.Code(), filterNone_src.Count())) - return false; - if (!m_filterNone_prgm->Link()) - return false; + m_filterAll_prgm = + core::utility::make_glowl_shader("filterAll", shader_options, "probe_gl/utility/filterAll.comp.glsl"); - } catch (vislib_gl::graphics::gl::AbstractOpenGLShader::CompileException ce) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader (@%s): %s\n", - vislib_gl::graphics::gl::AbstractOpenGLShader::CompileException::CompileActionName(ce.FailedAction()), - ce.GetMsgA()); - return false; - } catch (vislib::Exception e) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: %s\n", e.GetMsgA()); - return false; - } catch (...) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: Unknown exception\n"); + m_filterNone_prgm = + core::utility::make_glowl_shader("filterAll", shader_options, "probe_gl/utility/filterNone.comp.glsl"); + } catch (std::runtime_error const& ex) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); return false; } @@ -194,19 +164,19 @@ bool FilterByProbe::Render(mmstd_gl::CallRender3DGL& call) { auto flag_data = readFlags->getData(); { - m_filterNone_prgm->Enable(); + m_filterNone_prgm->use(); auto flag_cnt = static_cast(flag_data->flags->getByteSize() / sizeof(GLuint)); - glUniform1ui(m_filterNone_prgm->ParameterLocation("flag_cnt"), flag_cnt); + m_filterNone_prgm->setUniform("flag_cnt", flag_cnt); - flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER, 1); - m_filterNone_prgm->Dispatch(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); + glDispatchCompute(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); ::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); - m_filterNone_prgm->Disable(); + glUseProgram(0); } writeFlags->setData(readFlags->getData(), m_version); @@ -245,7 +215,7 @@ bool FilterByProbe::Render(mmstd_gl::CallRender3DGL& call) { for (int j = 0; j < samples_per_probe; j++) { - std::array sample_point; + std::array sample_point; sample_point[0] = position[0] + j * sample_step * direction[0]; sample_point[1] = position[1] + j * sample_step * direction[1]; sample_point[2] = position[2] + j * sample_step * direction[2]; @@ -295,32 +265,30 @@ bool FilterByProbe::Render(mmstd_gl::CallRender3DGL& call) { std::make_unique(GL_SHADER_STORAGE_BUFFER, indices, GL_DYNAMIC_DRAW); if (!indices.empty()) { - m_filterAll_prgm->Enable(); + m_filterAll_prgm->use(); auto flag_cnt = static_cast(flag_data->flags->getByteSize() / sizeof(GLuint)); - glUniform1ui(m_filterAll_prgm->ParameterLocation("flag_cnt"), flag_cnt); + m_filterAll_prgm->setUniform("flag_cnt", flag_cnt); - flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER, 1); - m_filterAll_prgm->Dispatch(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); + glDispatchCompute(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); ::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); - m_filterAll_prgm->Disable(); - - m_setFlags_prgm->Enable(); + m_setFlags_prgm->use(); - glUniform1ui(m_setFlags_prgm->ParameterLocation("id_cnt"), static_cast(indices.size())); + m_setFlags_prgm->setUniform("id_cnt", static_cast(indices.size())); kdtree_ids->bind(0); - flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER, 1); - m_setFlags_prgm->Dispatch(static_cast(std::ceil(indices.size() / 64.0f)), 1, 1); + glDispatchCompute(static_cast(std::ceil(indices.size() / 64.0f)), 1, 1); ::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); - m_setFlags_prgm->Disable(); + glUseProgram(0); } writeFlags->setData(readFlags->getData(), m_version); @@ -359,12 +327,12 @@ bool FilterByProbe::Render(mmstd_gl::CallRender3DGL& call) { float depth = std::min(end, pending_filter_event.back().depth); //float depth = pending_filter_event.back().depth; - std::array sample_point; + std::array sample_point; sample_point[0] = position[0] + depth * direction[0]; sample_point[1] = position[1] + depth * direction[1]; sample_point[2] = position[2] + depth * direction[2]; - std::vector> res; + std::vector> res; auto num_neighbors = tree->radiusSearch( &sample_point[0], radius, res, nanoflann::SearchParams(10, 0.01f, true)); @@ -407,32 +375,30 @@ bool FilterByProbe::Render(mmstd_gl::CallRender3DGL& call) { std::make_unique(GL_SHADER_STORAGE_BUFFER, indices, GL_DYNAMIC_DRAW); if (!indices.empty()) { - m_filterAll_prgm->Enable(); + m_filterAll_prgm->use(); auto flag_cnt = static_cast(flag_data->flags->getByteSize() / sizeof(GLuint)); - glUniform1ui(m_filterAll_prgm->ParameterLocation("flag_cnt"), flag_cnt); + m_filterAll_prgm->setUniform("flag_cnt", flag_cnt); - flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER, 1); - m_filterAll_prgm->Dispatch(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); + glDispatchCompute(static_cast(std::ceil(flag_cnt / 64.0f)), 1, 1); ::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); - m_filterAll_prgm->Disable(); - - m_setFlags_prgm->Enable(); + m_setFlags_prgm->use(); - glUniform1ui(m_setFlags_prgm->ParameterLocation("id_cnt"), static_cast(indices.size())); + m_setFlags_prgm->setUniform("id_cnt", static_cast(indices.size())); kdtree_ids->bind(0); - flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER,1); + flag_data->flags->bindBase(GL_SHADER_STORAGE_BUFFER, 1); - m_setFlags_prgm->Dispatch(static_cast(std::ceil(indices.size() / 64.0f)), 1, 1); + glDispatchCompute(static_cast(std::ceil(indices.size() / 64.0f)), 1, 1); ::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); - m_setFlags_prgm->Disable(); + glUseProgram(0); } writeFlags->setData(readFlags->getData(), m_version); diff --git a/plugins/probe_gl/src/FilterByProbe.h b/plugins/probe_gl/src/FilterByProbe.h index 71abfd9078..8f375653b0 100644 --- a/plugins/probe_gl/src/FilterByProbe.h +++ b/plugins/probe_gl/src/FilterByProbe.h @@ -12,7 +12,7 @@ #include "mmstd_gl/renderer/CallRender3DGL.h" #include "mmstd_gl/renderer/Renderer3DModuleGL.h" -#include "vislib_gl/graphics/gl/GLSLComputeShader.h" +#include "glowl/GLSLProgram.hpp" namespace megamol { namespace probe_gl { @@ -97,20 +97,18 @@ class FilterByProbe : public megamol::mmstd_gl::Renderer3DModuleGL { void PreRender(mmstd_gl::CallRender3DGL& call); private: - typedef vislib_gl::graphics::gl::GLSLComputeShader GLSLComputeShader; - uint32_t m_version; std::vector m_probe_selection; /** Shader program for setting flags based on incoming user manipulations */ - std::unique_ptr m_setFlags_prgm; + std::unique_ptr m_setFlags_prgm; /** Shader program for filtering all data within a flag storage */ - std::unique_ptr m_filterAll_prgm; + std::unique_ptr m_filterAll_prgm; /** Shader program for clearing filters on all data within a flag storage */ - std::unique_ptr m_filterNone_prgm; + std::unique_ptr m_filterNone_prgm; core::CallerSlot m_probes_slot; diff --git a/plugins/probe_gl/src/ProbeBillboardGlyphMaterial.cpp b/plugins/probe_gl/src/ProbeBillboardGlyphMaterial.cpp deleted file mode 100644 index 401a5edfc2..0000000000 --- a/plugins/probe_gl/src/ProbeBillboardGlyphMaterial.cpp +++ /dev/null @@ -1,258 +0,0 @@ -#include "ProbeBillboardGlyphMaterial.h" - -#include "mesh/MeshCalls.h" -#include "mmcore_gl/utility/ShaderSourceFactory.h" -#include "probe/ProbeCalls.h" - -megamol::probe_gl::ProbeBillboardGlyphMaterial::ProbeBillboardGlyphMaterial() - : m_version(0) - , m_glyph_images_slot("GetProbes", "Slot for accessing a probe collection") { - - this->m_glyph_images_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_glyph_images_slot); -} - -megamol::probe_gl::ProbeBillboardGlyphMaterial::~ProbeBillboardGlyphMaterial() {} - -bool megamol::probe_gl::ProbeBillboardGlyphMaterial::create() { - - - auto create_progam = [this](vislib::StringA shader_base_name) -> std::shared_ptr { - vislib_gl::graphics::gl::ShaderSource vert_shader_src; - vislib_gl::graphics::gl::ShaderSource frag_shader_src; - - vislib::StringA vertShaderName = shader_base_name + "::vertex"; - vislib::StringA fragShaderName = shader_base_name + "::fragment"; - - auto ssf = - std::make_shared(instance()->Configuration().ShaderDirectories()); - - if (!ssf->MakeShaderSource(vertShaderName.PeekBuffer(), vert_shader_src)) { - throw; - } - if (!ssf->MakeShaderSource(fragShaderName.PeekBuffer(), frag_shader_src)) { - throw; - } - - std::string vertex_src(vert_shader_src.WholeCode(), (vert_shader_src.WholeCode()).Length()); - std::string fragment_src(frag_shader_src.WholeCode(), (frag_shader_src.WholeCode()).Length()); - - std::vector> shader_srcs; - shader_srcs.push_back({glowl::GLSLProgram::ShaderType::Vertex, vertex_src}); - shader_srcs.push_back({glowl::GLSLProgram::ShaderType::Fragment, fragment_src}); - - auto shader_prgm = std::make_unique(shader_srcs); - shader_prgm->setDebugLabel(std::string(shader_base_name)); // TODO debug label not set in time for catch... - - return shader_prgm; - }; - - try { - this->m_textured_glyph_prgm = create_progam("TexturedProbeGlyph"); - } catch (glowl::GLSLProgramException const& exc) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error during shader program creation of\"%s\": %s. [%s, %s, line %d]\n", "TexturedProbeGlyph", exc.what(), - __FILE__, __FUNCTION__, __LINE__); - return false; - } catch (vislib::Exception e) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: %s\n", e.GetMsgA()); - return false; - } catch (...) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: Unknown exception\n"); - return false; - } - - try { - this->m_scalar_probe_glyph_prgm = create_progam("ScalarProbeGlyph"); - } catch (glowl::GLSLProgramException const& exc) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error during shader program creation of\"%s\": %s. [%s, %s, line %d]\n", "ScalarProbeGlyph", exc.what(), - __FILE__, __FUNCTION__, __LINE__); - return false; - } catch (vislib::Exception e) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: %s\n", e.GetMsgA()); - return false; - } catch (...) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: Unknown exception\n"); - return false; - } - - try { - this->m_scalar_distribution_probe_glyph_prgm = create_progam("ScalarDistributionProbeGlyph"); - } catch (glowl::GLSLProgramException const& exc) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error during shader program creation of\"%s\": %s. [%s, %s, line %d]\n", "ScalarDistributionProbeGlyph", - exc.what(), __FILE__, __FUNCTION__, __LINE__); - return false; - } catch (vislib::Exception e) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: %s\n", e.GetMsgA()); - return false; - } catch (...) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: Unknown exception\n"); - return false; - } - - try { - this->m_vector_probe_glyph_prgm = create_progam("VectorProbeGlyph"); - } catch (glowl::GLSLProgramException const& exc) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error during shader program creation of\"%s\": %s. [%s, %s, line %d]\n", "VectorProbeGlyph", exc.what(), - __FILE__, __FUNCTION__, __LINE__); - return false; - } catch (vislib::Exception e) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: %s\n", e.GetMsgA()); - return false; - } catch (...) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: Unknown exception\n"); - return false; - } - - try { - this->m_clusterID_glyph_prgm = create_progam("ClusterIDGlyph"); - } catch (glowl::GLSLProgramException const& exc) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error during shader program creation of\"%s\": %s. [%s, %s, line %d]\n", "ClusterIDGlyph", exc.what(), - __FILE__, __FUNCTION__, __LINE__); - return false; - } catch (vislib::Exception e) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: %s\n", e.GetMsgA()); - return false; - } catch (...) { - megamol::core::utility::log::Log::DefaultLog.WriteError("Unable to compile shader: Unknown exception\n"); - return false; - } - - // Set initial state of module - ++m_version; - m_material_collection.first = std::make_shared(); - m_material_collection.first->addMaterial("ProbeBillboard_Textured", m_textured_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_Textured"); - m_material_collection.first->addMaterial("ProbeBillboard_Scalar", m_scalar_probe_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_Scalar"); - m_material_collection.first->addMaterial( - "ProbeBillboard_ScalarDistribution", m_scalar_distribution_probe_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_ScalarDistribution"); - m_material_collection.first->addMaterial("ProbeBillboard_Vector", m_vector_probe_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_Vector"); - m_material_collection.first->addMaterial("ProbeBillboard_ClusterID", m_clusterID_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_ClusterID"); - - return true; -} - -bool megamol::probe_gl::ProbeBillboardGlyphMaterial::getDataCallback(core::Call& caller) { - - mesh_gl::CallGPUMaterialData* lhs_mtl_call = dynamic_cast(&caller); - mesh_gl::CallGPUMaterialData* rhs_mtl_call = this->m_mtl_callerSlot.CallAs(); - - if (lhs_mtl_call == NULL) { - return false; - } - - auto gpu_mtl_collections = std::make_shared>>(); - // if there is a material connection to the right, issue callback - if (rhs_mtl_call != nullptr) { - (*rhs_mtl_call)(0); - if (rhs_mtl_call->hasUpdate()) { - ++m_version; - } - gpu_mtl_collections = rhs_mtl_call->getData(); - } - gpu_mtl_collections->push_back(m_material_collection.first); - - mesh::CallImage* ic = this->m_glyph_images_slot.CallAs(); - if (ic != NULL) { - if (!(*ic)(0)) - return false; - - auto image_meta_data = ic->getMetaData(); - - // something has changed in the neath... - bool something_has_changed = ic->hasUpdate(); - - if (something_has_changed) { - ++m_version; - - auto img_data = ic->getData(); - - // use first image to determine size -> assumes same size for all images - auto img_height = img_data->accessImages().front().height; - auto img_width = img_data->accessImages().front().width; - auto img_format = - mesh::ImageDataAccessCollection::convertToGLInternalFormat(img_data->accessImages().front().format); - - glowl::TextureLayout tex_layout; - tex_layout.width = img_width; - tex_layout.height = img_height; - tex_layout.depth = 2048; - tex_layout.levels = 1; - // TODO - tex_layout.format = GL_RGBA; - tex_layout.type = GL_UNSIGNED_BYTE; - // TODO - tex_layout.internal_format = img_format; - - tex_layout.int_parameters = { - {GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR}, {GL_TEXTURE_MAG_FILTER, GL_LINEAR}}; - - size_t img_cnt = img_data->accessImages().size(); - size_t required_tx_arrays = static_cast(std::ceil(static_cast(img_cnt) / 2048.0)); - - std::vector> textures(required_tx_arrays, nullptr); - for (auto& tx_array : textures) { - auto new_tex_ptr = std::make_shared("ProbeGlyph", tex_layout, nullptr); - tx_array = std::static_pointer_cast(new_tex_ptr); - } - - auto images = img_data->accessImages(); - for (size_t i = 0; i < images.size(); ++i) { - auto texture_idx = i / 2048; - auto slice_idx = i % 2048; - textures[texture_idx]->bindTexture(); - - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, slice_idx, tex_layout.width, tex_layout.height, 1, - tex_layout.format, tex_layout.type, images[i].data); - - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - } - - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); - - for (auto& identifier : m_material_collection.second) { - m_material_collection.first->deleteMaterial(identifier); - } - m_material_collection.second.clear(); - - m_material_collection.first->addMaterial("ProbeBillboard_Textured", m_textured_glyph_prgm, textures); - m_material_collection.second.push_back("ProbeBillboard_Textured"); - m_material_collection.first->addMaterial("ProbeBillboard_Scalar", m_scalar_probe_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_Scalar"); - m_material_collection.first->addMaterial("ProbeBillboard_Vector", m_vector_probe_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_Vector"); - m_material_collection.first->addMaterial("ProbeBillboard_ClusterID", m_clusterID_glyph_prgm); - m_material_collection.second.push_back("ProbeBillboard_ClusterID"); - } - } - - lhs_mtl_call->setData(gpu_mtl_collections, m_version); - - return true; -} - -bool megamol::probe_gl::ProbeBillboardGlyphMaterial::getMetaDataCallback(core::Call& caller) { - - // if (!mesh::AbstractGPUMaterialDataSource::getMetaDataCallback(caller)) return false; - - // auto lhs_mtl_call = dynamic_cast(&caller); - auto glyph_image_call = m_glyph_images_slot.CallAs(); - // - // auto lhs_mtl_meta_data = lhs_mtl_call->getMetaData(); - // auto glyph_image_meta_data = glyph_image_call->getMetaData(); - - if (glyph_image_call != NULL) { - if (!(*glyph_image_call)(1)) - return false; - } - - return true; -} diff --git a/plugins/probe_gl/src/ProbeBillboardGlyphMaterial.h b/plugins/probe_gl/src/ProbeBillboardGlyphMaterial.h deleted file mode 100644 index 81a64661ed..0000000000 --- a/plugins/probe_gl/src/ProbeBillboardGlyphMaterial.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ProbeBillboardGlyphMaterial.h - * - * Copyright (C) 2019 by Universitaet Stuttgart (VISUS). - * All rights reserved. - */ - -#ifndef PROBE_BILLBOARD_GLYPH_MATERIAL_H_INCLUDED -#define PROBE_BILLBOARD_GLYPH_MATERIAL_H_INCLUDED - -#include "mesh_gl/AbstractGPUMaterialDataSource.h" - -namespace megamol { -namespace probe_gl { - -class ProbeBillboardGlyphMaterial : public mesh_gl::AbstractGPUMaterialDataSource { -public: - /** - * Answer the name of this module. - * - * @return The name of this module. - */ - static const char* ClassName(void) { - return "ProbeBillboardGlyphMaterial"; - } - - /** - * Answer a human readable description of this module. - * - * @return A human readable description of this module. - */ - static const char* Description(void) { - return "..."; - } - - /** - * Answers whether this module is available on the current system. - * - * @return 'true' if the module is available, 'false' otherwise. - */ - static bool IsAvailable(void) { - return true; - } - - ProbeBillboardGlyphMaterial(); - ~ProbeBillboardGlyphMaterial(); - -protected: - bool create(); - - bool getDataCallback(core::Call& caller); - - bool getMetaDataCallback(core::Call& caller); - -private: - typedef glowl::GLSLProgram ShaderProgram; - - uint32_t m_version; - - /** Shader program for textured billboards */ - std::shared_ptr m_textured_glyph_prgm; - - /** Shader program for realtime GPU rendered glyph for vector probes */ - std::shared_ptr m_vector_probe_glyph_prgm; - - /** Shader program for realtime GPU rendered glyph for scalar probes */ - std::shared_ptr m_scalar_probe_glyph_prgm; - - /** Shader program for realtime GPU rendered glyph for scalar distribution probes */ - std::shared_ptr m_scalar_distribution_probe_glyph_prgm; - - /** Shader program for displaying cluster IDs of probes */ - std::shared_ptr m_clusterID_glyph_prgm; - - core::CallerSlot m_glyph_images_slot; -}; - - -} // namespace probe_gl -} // namespace megamol - - -#endif // !PROBE_BILLBOARD_GLYPH_MATERIAL_H_INCLUDED diff --git a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp b/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp deleted file mode 100644 index 62ad889f85..0000000000 --- a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.cpp +++ /dev/null @@ -1,1005 +0,0 @@ -#include "ProbeBillboardGlyphRenderTasks.h" - -#include "ProbeEvents.h" -#include "ProbeGlCalls.h" -#include "mmstd/event/EventCall.h" -#include "mmstd_gl/renderer/CallGetTransferFunctionGL.h" -#include "probe/ProbeCalls.h" - -#include "glm/glm.hpp" -#include "glm/gtc/type_ptr.hpp" -#include "glm/gtx/transform.hpp" -#include "mmcore/param/BoolParam.h" -#include "mmcore/param/ColorParam.h" -#include "mmcore/param/EnumParam.h" -#include "mmcore/param/FloatParam.h" - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "imgui_impl_opengl3.h" -#include "imgui_stdlib.h" -#include - -bool megamol::probe_gl::ProbeBillboardGlyphRenderTasks::create() { - - auto retval = mesh_gl::AbstractGPURenderTaskDataSource::create(); - - // Create local copy of transfer function texture (for compatibility with material pipeline) - glowl::TextureLayout tex_layout; - tex_layout.width = 1; - tex_layout.height = 1; - tex_layout.depth = 1; - tex_layout.levels = 1; - // TODO - tex_layout.format = GL_RGBA; - tex_layout.type = GL_FLOAT; - // TODO - tex_layout.internal_format = GL_RGBA32F; - tex_layout.int_parameters = { - {GL_TEXTURE_MIN_FILTER, GL_NEAREST}, {GL_TEXTURE_MAG_FILTER, GL_LINEAR}, {GL_TEXTURE_WRAP_S, GL_CLAMP}}; - try { - this->m_transfer_function = std::make_shared("ProbeTransferFunction", tex_layout, nullptr); - } catch (glowl::TextureException const& exc) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error on transfer texture view pre-creation: %s. [%s, %s, line %d]\n", exc.what(), __FILE__, __FUNCTION__, - __LINE__); - } - // TODO intialize with value indicating that no transfer function is connected - this->m_transfer_function->makeResident(); - - - m_material_collection = std::make_shared(); - // textured glyph shader program - try { - std::vector shaderfiles = { - "glyphs/textured_probe_glyph.vert.glsl", "glyphs/textured_probe_glyph.frag.glsl"}; - m_material_collection->addMaterial(this->instance(), "TexturedProbeGlyph", shaderfiles); - } catch (const std::exception& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - // scalar glyph shader program - try { - std::vector shaderfiles = { - "glyphs/scalar_probe_glyph_v2.vert.glsl", "glyphs/scalar_probe_glyph_v2.frag.glsl"}; - m_material_collection->addMaterial(this->instance(), "ScalarProbeGlyph", shaderfiles); - } catch (const std::exception& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - // scalar distribution glyph shader program - try { - std::vector shaderfiles = { - "glyphs/scalar_distribution_probe_glyph_v2.vert.glsl", "glyphs/scalar_distribution_probe_glyph.frag.glsl"}; - m_material_collection->addMaterial(this->instance(), "ScalarDistributionProbeGlyph", shaderfiles); - } catch (const std::exception& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - // vector glyph shader program - try { - std::vector shaderfiles = { - "glyphs/vector_probe_glyph.vert.glsl", "glyphs/vector_probe_glyph.frag.glsl"}; - m_material_collection->addMaterial(this->instance(), "VectorProbeGlyph", shaderfiles); - } catch (const std::exception& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - // cluster ID glyph shader program - try { - std::vector shaderfiles = { - "glyphs/clusterID_probe_glyph.vert.glsl", "glyphs/clusterID_probe_glyph.frag.glsl"}; - m_material_collection->addMaterial(this->instance(), "ClusterIDProbeGlyph", shaderfiles); - } catch (const std::exception& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - - return retval; -} - -void megamol::probe_gl::ProbeBillboardGlyphRenderTasks::release() {} - -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::ProbeBillboardGlyphRenderTasks() - : m_version(0) - , m_imgui_context(nullptr) - , m_transfer_function_Slot("GetTransferFunction", "Slot for accessing a transfer function") - , m_probes_slot("GetProbes", "Slot for accessing a probe collection") - , m_event_slot("GetProbeEvents", "") - , m_billboard_dummy_mesh(nullptr) - , m_billboard_size_slot("BillBoardSize", "Sets the scaling factor of the texture billboards") - , m_rendering_mode_slot("RenderingMode", "Glyph rendering mode") - , m_use_interpolation_slot("UseInterpolation", "Interpolate between samples") - , m_show_canvas_slot("ShowGlyphCanvas", "Render glyphs with opaque background") - , m_canvas_color_slot("GlyphCanvasColor", "Color used for the background of individual glyphs") - , m_tf_range({0.0f, 0.0f}) - , m_show_glyphs(true) { - - this->m_transfer_function_Slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_transfer_function_Slot); - - this->m_probes_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_probes_slot); - - this->m_event_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_event_slot); - - this->m_billboard_size_slot << new core::param::FloatParam(1.0f); - this->MakeSlotAvailable(&this->m_billboard_size_slot); - - this->m_rendering_mode_slot << new megamol::core::param::EnumParam(0); - this->m_rendering_mode_slot.Param()->SetTypePair(0, "Precomputed"); - this->m_rendering_mode_slot.Param()->SetTypePair(1, "Realtime"); - this->m_rendering_mode_slot.Param()->SetTypePair(2, "ClusterID"); - this->MakeSlotAvailable(&this->m_rendering_mode_slot); - - this->m_use_interpolation_slot << new core::param::BoolParam(true); - this->MakeSlotAvailable(&this->m_use_interpolation_slot); - - this->m_show_canvas_slot << new core::param::BoolParam(true); - this->MakeSlotAvailable(&this->m_show_canvas_slot); - - this->m_canvas_color_slot << new core::param::ColorParam(1.0, 1.0, 1.0, 1.0); - this->MakeSlotAvailable(&this->m_canvas_color_slot); -} - -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::~ProbeBillboardGlyphRenderTasks() {} - -bool megamol::probe_gl::ProbeBillboardGlyphRenderTasks::getDataCallback(core::Call& caller) { - - auto err = glGetError(); - if (err != GL_NO_ERROR) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Unexpeced OpenGL error: %i. [%s, %s, line %d]\n", err, __FILE__, __FUNCTION__, __LINE__); - } - - mesh_gl::CallGPURenderTaskData* lhs_rtc = dynamic_cast(&caller); - if (lhs_rtc == NULL) { - return false; - } - - mesh_gl::CallGPURenderTaskData* rhs_rtc = this->m_renderTask_rhs_slot.CallAs(); - - auto gpu_render_tasks = std::make_shared>>(); - if (rhs_rtc != nullptr) { - if (!(*rhs_rtc)(0)) { - return false; - } - if (rhs_rtc->hasUpdate()) { - ++m_version; - } - gpu_render_tasks = rhs_rtc->getData(); - } - gpu_render_tasks->push_back(m_rendertask_collection.first); - - // create an empty dummy mesh, actual billboard geometry will be build in vertex shader - if (m_billboard_dummy_mesh == nullptr) { - std::vector data_ptrs = {}; - std::vector byte_sizes = {}; - std::vector indices = {0, 1, 2, 3, 4, 5}; - std::vector vertex_layout = {}; - - m_billboard_dummy_mesh = std::make_shared( - data_ptrs, byte_sizes, vertex_layout, indices.data(), 6 * 4, GL_UNSIGNED_INT, GL_TRIANGLES, GL_STATIC_DRAW); - } - - probe::CallProbes* pc = this->m_probes_slot.CallAs(); - if (pc == NULL) { - return false; - } - if (!(*pc)(0)) { - return false; - } - - auto* tfc = this->m_transfer_function_Slot.CallAs(); - if (tfc != NULL) { - ((*tfc)(0)); - } - - bool something_has_changed = - pc->hasUpdate() || this->m_billboard_size_slot.IsDirty() || this->m_rendering_mode_slot.IsDirty(); - - if (something_has_changed) { - ++m_version; - - this->m_billboard_size_slot.ResetDirty(); - this->m_rendering_mode_slot.ResetDirty(); - auto probes = pc->getData(); - - auto visitor = [this](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - - } else if constexpr (std::is_same_v>) { - m_tf_range = arg; - } else if constexpr (std::is_same_v>) { - // TODO - } else { - // unknown probe type, throw error? do nothing? - } - }; - - std::visit(visitor, probes->getGenericGlobalMinMax()); - - //for (auto& identifier : m_rendertask_collection.second) { - // m_rendertask_collection.first->deleteRenderTask(identifier); - //} - m_rendertask_collection.first->clear(); - m_rendertask_collection.second.clear(); - - - auto probe_cnt = probes->getProbeCount(); - - m_type_index_map.clear(); - m_type_index_map.reserve(probe_cnt); - - m_textured_glyph_identifiers.clear(); - m_vector_probe_glyph_identifiers.clear(); - m_scalar_probe_glyph_identifiers.clear(); - m_scalar_distribution_probe_glyph_identifiers.clear(); - m_clusterID_glyph_identifiers.clear(); - - m_textured_glyph_data.clear(); - m_vector_probe_glyph_data.clear(); - m_scalar_probe_glyph_data.clear(); - m_scalar_distribution_probe_glyph_data.clear(); - m_clusterID_glyph_data.clear(); - - m_textured_gylph_draw_commands.clear(); - m_vector_probe_gylph_draw_commands.clear(); - m_scalar_probe_gylph_draw_commands.clear(); - m_scalar_distribution_probe_gylph_draw_commands.clear(); - m_clusterID_gylph_draw_commands.clear(); - - m_textured_gylph_draw_commands.reserve(probe_cnt); - m_textured_glyph_data.reserve(probe_cnt); - - m_vector_probe_gylph_draw_commands.reserve(probe_cnt); - m_vector_probe_glyph_data.reserve(probe_cnt); - - m_scalar_probe_gylph_draw_commands.reserve(probe_cnt); - m_scalar_probe_glyph_data.reserve(probe_cnt); - - m_scalar_distribution_probe_gylph_draw_commands.reserve(probe_cnt); - m_scalar_distribution_probe_glyph_data.reserve(probe_cnt); - - m_clusterID_gylph_draw_commands.reserve(probe_cnt); - m_clusterID_glyph_data.reserve(probe_cnt); - - // draw command looks the same for all billboards because geometry is reused - glowl::DrawElementsCommand draw_command; - draw_command.base_instance = 0; - draw_command.base_vertex = 0; - draw_command.cnt = 6; - draw_command.first_idx = 0; - draw_command.instance_cnt = 1; - - // scale in constant over all billboards - float scale = this->m_billboard_size_slot.Param()->Value(); - - if (m_rendering_mode_slot.Param()->Value() == 0) { - // use precomputed textures if available - - auto mat = m_material_collection->getMaterial("TexturedProbeGlyph"); - if (mat.shader_program != nullptr && mat.textures.size() > 0) { - for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { - - assert(probe_cnt <= (mat.textures.size() * 2048)); - - auto generic_probe = probes->getGenericProbe(probe_idx); - - GLuint64 texture_handle = mat.textures[probe_idx / 2048]->getTextureHandle(); - float slice_idx = probe_idx % 2048; - mat.textures[probe_idx / 2048]->makeResident(); - - auto visitor = [draw_command, scale, texture_handle, slice_idx, probe_idx, this](auto&& arg) { - using T = std::decay_t; - - auto glyph_data = createTexturedGlyphData(arg, probe_idx, texture_handle, slice_idx, scale); - m_textured_gylph_draw_commands.push_back(draw_command); - this->m_textured_glyph_data.push_back(glyph_data); - - m_textured_glyph_identifiers.emplace_back( - std::string(FullName()) + "_tg_" + std::to_string(probe_idx)); - - this->m_type_index_map.push_back({std::type_index(typeid(TexturedGlyphData)), probe_idx}); - }; - - std::visit(visitor, generic_probe); - } - } - - } else if (m_rendering_mode_slot.Param()->Value() == 1) { - - for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { - - auto generic_probe = probes->getGenericProbe(probe_idx); - - auto visitor = [draw_command, scale, probe_idx, this](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - - auto sp_idx = m_scalar_probe_glyph_data.size(); - - auto glyph_data = createScalarProbeGlyphData(arg, probe_idx, scale); - m_scalar_probe_gylph_draw_commands.push_back(draw_command); - this->m_scalar_probe_glyph_data.push_back(glyph_data); - - m_scalar_probe_glyph_identifiers.emplace_back( - std::string(FullName()) + "_sg_" + std::to_string(probe_idx)); - - this->m_type_index_map.push_back({std::type_index(typeid(GlyphScalarProbeData)), sp_idx}); - - } else if constexpr (std::is_same_v) { - auto sp_idx = m_scalar_distribution_probe_glyph_data.size(); - - auto glyph_data = createScalarDistributionProbeGlyphData(arg, probe_idx, scale); - m_scalar_distribution_probe_gylph_draw_commands.push_back(draw_command); - this->m_scalar_distribution_probe_glyph_data.push_back(glyph_data); - - m_scalar_distribution_probe_glyph_identifiers.emplace_back( - std::string(FullName()) + "_sdg_" + std::to_string(probe_idx)); - - this->m_type_index_map.push_back( - {std::type_index(typeid(GlyphScalarDistributionProbeData)), sp_idx}); - } else if constexpr (std::is_same_v) { - // TODO - } else if constexpr (std::is_same_v) { - - auto vp_idx = m_vector_probe_glyph_data.size(); - - auto glyph_data = createVectorProbeGlyphData(arg, probe_idx, scale); - m_vector_probe_gylph_draw_commands.push_back(draw_command); - this->m_vector_probe_glyph_data.push_back(glyph_data); - - m_vector_probe_glyph_identifiers.emplace_back( - std::string(FullName()) + "_vg_" + std::to_string(probe_idx)); - - this->m_type_index_map.push_back({std::type_index(typeid(GlyphVectorProbeData)), vp_idx}); - - } else { - // unknown probe type, throw error? do nothing? - } - }; - - std::visit(visitor, generic_probe); - } - - // scan all scalar probes to compute global min/max - //float min = std::numeric_limits::max(); - //float max = std::numeric_limits::min(); - //for (auto& data : m_scalar_probe_glyph_data) { - // min = std::min(data.min_value, min); - // max = std::max(data.max_value, max); - //} - //for (auto& data : m_scalar_probe_glyph_data) { - // data.min_value = min; - // data.max_value = max; - //} - } else { - int total_cluster_cnt = 0; - for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { - - auto generic_probe = probes->getGenericProbe(probe_idx); - - auto visitor = [draw_command, scale, probe_idx, &total_cluster_cnt, this](auto&& arg) { - using T = std::decay_t; - - auto glyph_data = createClusterIDGlyphData(arg, probe_idx, scale); - m_clusterID_gylph_draw_commands.push_back(draw_command); - this->m_clusterID_glyph_data.push_back(glyph_data); - - total_cluster_cnt = std::max(total_cluster_cnt, glyph_data.cluster_id); - - m_clusterID_glyph_identifiers.push_back( - std::string(FullName()) + "_cg_" + std::to_string(probe_idx)); - - this->m_type_index_map.push_back({std::type_index(typeid(GlyphClusterIDData)), probe_idx}); - }; - - std::visit(visitor, generic_probe); - } - - for (auto& glyph_data : m_clusterID_glyph_data) { - glyph_data.total_cluster_cnt = total_cluster_cnt; - } - } - - addAllRenderTasks(); - } - - bool per_frame_data_has_changed = this->m_use_interpolation_slot.IsDirty() || this->m_show_canvas_slot.IsDirty() || - this->m_canvas_color_slot.IsDirty() || ((tfc != NULL) ? tfc->IsDirty() : false) || - m_rendertask_collection.first->getPerFrameBuffers().empty(); - - if (per_frame_data_has_changed) { - this->m_use_interpolation_slot.ResetDirty(); - this->m_show_canvas_slot.ResetDirty(); - this->m_canvas_color_slot.ResetDirty(); - - if (tfc != NULL) { - tfc->SetRange(m_tf_range); - ((*tfc)()); - m_tf_range = tfc->Range(); - } - - // Update transfer texture only if it available and has changed - if (tfc != NULL) { - - if (tfc->IsDirty()) { - //++m_version; - tfc->ResetDirty(); - - this->m_transfer_function->makeNonResident(); - this->m_transfer_function.reset(); - - { - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - // "Do something cop!" - std::cerr << "GL error during transfer function update" << err << std::endl; - } - } - - glowl::TextureLayout tex_layout; - tex_layout.width = tfc->TextureSize(); - tex_layout.height = 1; - tex_layout.depth = 1; - tex_layout.levels = 1; - // TODO - tex_layout.format = GL_RGBA; - tex_layout.type = GL_FLOAT; - // TODO - tex_layout.internal_format = GL_RGBA32F; - tex_layout.int_parameters = {{GL_TEXTURE_MIN_FILTER, GL_NEAREST}, {GL_TEXTURE_MAG_FILTER, GL_LINEAR}, - {GL_TEXTURE_WRAP_S, GL_CLAMP}}; - try { - this->m_transfer_function = std::make_shared( - "ProbeTransferFunction", tex_layout, (GLvoid*)tfc->GetTextureData()); - } catch (glowl::TextureException const& exc) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error on transfer texture view creation: %s. [%s, %s, line %d]\n", exc.what(), __FILE__, - __FUNCTION__, __LINE__); - } - - this->m_transfer_function->makeResident(); - { - auto err = glGetError(); - if (err != GL_NO_ERROR) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Error on making transfer texture view resident: %i. [%s, %s, line %d]\n", err, __FILE__, - __FUNCTION__, __LINE__); - } - } - - m_tf_range = tfc->Range(); - } - } - - GLuint64 texture_handle = this->m_transfer_function->getTextureHandle(); - - std::array data; - data[0].use_interpolation = m_use_interpolation_slot.Param()->Value(); - data[0].show_canvas = m_show_canvas_slot.Param()->Value(); - data[0].canvas_color = m_canvas_color_slot.Param()->Value(); - data[0].tf_texture_handle = texture_handle; - data[0].tf_min = std::get<0>(m_tf_range); - data[0].tf_max = std::get<1>(m_tf_range); - - std::string identifier = std::string(FullName()) + "_perFrameData"; - if (m_rendertask_collection.first->getPerFrameBuffers().empty()) { - m_rendertask_collection.first->addPerFrameDataBuffer(identifier, data, 1); - } else { - m_rendertask_collection.first->updatePerFrameDataBuffer(identifier, data, 1); - } - } - - // check for pending events - auto call_event_storage = this->m_event_slot.CallAs(); - if (call_event_storage != NULL) { - if ((!(*call_event_storage)(0))) - return false; - - auto event_collection = call_event_storage->getData(); - - // process pobe clear selection events - { - auto pending_events = event_collection->get(); - if (!pending_events.empty()) { - for (auto& draw_data : m_scalar_probe_glyph_data) { - draw_data.state = 0; - } - for (auto& draw_data : m_vector_probe_glyph_data) { - draw_data.state = 0; - } - for (auto& draw_data : m_clusterID_glyph_data) { - draw_data.state = 0; - } - - updateAllRenderTasks(); - } - } - - // process probe highlight events - { - auto pending_highlight_events = event_collection->get(); - for (auto& evt : pending_highlight_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - per_probe_data[0].state = 1; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - per_probe_data[0].state = 1; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - per_probe_data[0].state = 1; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - - // bool my_tool_active = true; - // float my_color[4] = {0.0, 0.0, 0.0, 0.0}; - // - // // ImGui::NewFrame(); - // // Create a window called "My First Tool", with a menu bar. - // auto ctx = reinterpret_cast(this->GetCoreInstance()->GetCurrentImGuiContext()); - // if (ctx != nullptr) { - // ImGui::SetCurrentContext(ctx); - // ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar); - // if (ImGui::BeginMenuBar()) { - // if (ImGui::BeginMenu("File")) { - // if (ImGui::MenuItem("Open..", "Ctrl+O")) { /* Do stuff */ - // } - // if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Do stuff */ - // } - // if (ImGui::MenuItem("Close", "Ctrl+W")) { - // my_tool_active = false; - // } - // ImGui::EndMenu(); - // } - // ImGui::EndMenuBar(); - // } - // - // // Edit a color (stored as ~4 floats) - // ImGui::ColorEdit4("Color", my_color); - // - // // Plot some values - // const float my_values[] = {0.2f, 0.1f, 1.0f, 0.5f, 0.9f, 2.2f}; - // ImGui::PlotLines("Frame Times", my_values, IM_ARRAYSIZE(my_values)); - // - // // Display contents in a scrolling region - // ImGui::TextColored(ImVec4(1, 1, 0, 1), "Important Stuff"); - // ImGui::BeginChild("Scrolling"); - // for (int n = 0; n < 50; n++) ImGui::Text("%04d: Some text", n); - // ImGui::EndChild(); - // ImGui::End(); - // } - } - } - - // process probe dehighlight events - { - auto pending_dehighlight_events = event_collection->get(); - for (auto& evt : pending_dehighlight_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process probe selection events - { - auto pending_select_events = event_collection->get(); - for (auto& evt : pending_select_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = 2; - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_ProbeBillboard_Scalar"; - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = 2; - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_ProbeBillboard_Vector"; - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = 2; - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_ProbeBillboard_ClusterID"; - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process probe deselection events - { - auto pending_deselect_events = event_collection->get(); - for (auto& evt : pending_deselect_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = 0; - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = 0; - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = 0; - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process probe exclusive selection events - { - auto pending_events = event_collection->get(); - if (!pending_events.empty()) { - - for (auto& draw_data : m_scalar_probe_glyph_data) { - draw_data.state = 0; - } - for (auto& draw_data : m_vector_probe_glyph_data) { - draw_data.state = 0; - } - for (auto& draw_data : m_clusterID_glyph_data) { - draw_data.state = 0; - } - - auto probe_type = m_type_index_map[pending_events.back().obj_id].first; - auto probe_idx = m_type_index_map[pending_events.back().obj_id].second; - - // multiple exclusive selections make no sense, just apply the last one - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = 2; - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = 2; - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = 2; - } - - updateAllRenderTasks(); - } - } - - // process probe selection toggle events - { - auto pending_select_events = event_collection->get(); - for (auto& evt : pending_select_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = - m_scalar_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = - m_vector_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = m_clusterID_glyph_data[probe_idx].state == 2 ? 0 : 2; - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process toggle show glyph events - { - auto pending_deselect_events = event_collection->get(); - for (auto& evt : pending_deselect_events) { - m_show_glyphs = !m_show_glyphs; - - if (m_show_glyphs) { - addAllRenderTasks(); - } else { - clearAllRenderTasks(); - } - } - } - } - - lhs_rtc->setData(gpu_render_tasks, m_version); - - return true; -} - -bool megamol::probe_gl::ProbeBillboardGlyphRenderTasks::getMetaDataCallback(core::Call& caller) { - - if (!AbstractGPURenderTaskDataSource::getMetaDataCallback(caller)) - return false; - - mesh_gl::CallGPURenderTaskData* lhs_rt_call = dynamic_cast(&caller); - auto probe_call = m_probes_slot.CallAs(); - if (probe_call == NULL) - return false; - - auto lhs_meta_data = lhs_rt_call->getMetaData(); - - auto probe_meta_data = probe_call->getMetaData(); - probe_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; - probe_call->setMetaData(probe_meta_data); - if (!(*probe_call)(1)) - return false; - probe_meta_data = probe_call->getMetaData(); - - lhs_meta_data.m_frame_cnt = std::min(lhs_meta_data.m_frame_cnt, probe_meta_data.m_frame_cnt); - - auto bbox = lhs_meta_data.m_bboxs.BoundingBox(); - bbox.Union(probe_meta_data.m_bboxs.BoundingBox()); - lhs_meta_data.m_bboxs.SetBoundingBox(bbox); - - auto cbbox = lhs_meta_data.m_bboxs.ClipBox(); - cbbox.Union(probe_meta_data.m_bboxs.ClipBox()); - lhs_meta_data.m_bboxs.SetClipBox(cbbox); - - lhs_rt_call->setMetaData(lhs_meta_data); - - return true; -} - -bool megamol::probe_gl::ProbeBillboardGlyphRenderTasks::addAllRenderTasks() { - - std::shared_ptr textured_shader(nullptr); - std::shared_ptr scalar_shader(nullptr); - std::shared_ptr scalar_distribution_shader(nullptr); - std::shared_ptr vector_shader(nullptr); - std::shared_ptr clusterID_shader(nullptr); - - auto textured_query = m_material_collection->getMaterials().find("TexturedProbeGlyph"); - auto scalar_query = m_material_collection->getMaterials().find("ScalarProbeGlyph"); - auto scalar_distribution_query = m_material_collection->getMaterials().find("ScalarDistributionProbeGlyph"); - auto vector_query = m_material_collection->getMaterials().find("VectorProbeGlyph"); - auto clusterID_query = m_material_collection->getMaterials().find("ClusterIDProbeGlyph"); - - if (textured_query != m_material_collection->getMaterials().end()) { - textured_shader = textured_query->second.shader_program; - } - if (scalar_query != m_material_collection->getMaterials().end()) { - scalar_shader = scalar_query->second.shader_program; - } - if (scalar_distribution_query != m_material_collection->getMaterials().end()) { - scalar_distribution_shader = scalar_distribution_query->second.shader_program; - } - if (vector_query != m_material_collection->getMaterials().end()) { - vector_shader = vector_query->second.shader_program; - } - if (clusterID_query != m_material_collection->getMaterials().end()) { - clusterID_shader = clusterID_query->second.shader_program; - } - - - if (textured_shader == nullptr) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Could not get TexturedProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, - __FUNCTION__, __LINE__); - } - if (scalar_shader == nullptr) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Could not get ScalarProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, - __FUNCTION__, __LINE__); - } - if (scalar_distribution_shader == nullptr) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Could not get ScalarDistributionProbeGlyphe material, identifier not found. [%s, %s, line %d]\n", __FILE__, - __FUNCTION__, __LINE__); - } - if (vector_shader == nullptr) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Could not get VectorProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, - __FUNCTION__, __LINE__); - } - if (clusterID_shader == nullptr) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "Could not get ClusterIDProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, - __FUNCTION__, __LINE__); - } - - if (!m_textured_gylph_draw_commands.empty()) { - m_rendertask_collection.first->addRenderTasks(m_textured_glyph_identifiers, textured_shader, - m_billboard_dummy_mesh, m_textured_gylph_draw_commands, m_textured_glyph_data); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_textured_glyph_identifiers.begin(), m_textured_glyph_identifiers.end()); - } - - if (!m_scalar_probe_glyph_data.empty()) { - m_rendertask_collection.first->addRenderTasks(m_scalar_probe_glyph_identifiers, scalar_shader, - m_billboard_dummy_mesh, m_scalar_probe_gylph_draw_commands, m_scalar_probe_glyph_data); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_scalar_probe_glyph_identifiers.begin(), m_scalar_probe_glyph_identifiers.end()); - } - - if (!m_scalar_distribution_probe_glyph_data.empty()) { - m_rendertask_collection.first->addRenderTasks(m_scalar_distribution_probe_glyph_identifiers, - scalar_distribution_shader, m_billboard_dummy_mesh, m_scalar_distribution_probe_gylph_draw_commands, - m_scalar_distribution_probe_glyph_data); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_scalar_distribution_probe_glyph_identifiers.begin(), m_scalar_distribution_probe_glyph_identifiers.end()); - } - - if (!m_vector_probe_glyph_data.empty()) { - m_rendertask_collection.first->addRenderTasks(m_vector_probe_glyph_identifiers, vector_shader, - m_billboard_dummy_mesh, m_vector_probe_gylph_draw_commands, m_vector_probe_glyph_data); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_vector_probe_glyph_identifiers.begin(), m_vector_probe_glyph_identifiers.end()); - } - - if (!m_clusterID_gylph_draw_commands.empty()) { - m_rendertask_collection.first->addRenderTasks(m_clusterID_glyph_identifiers, clusterID_shader, - m_billboard_dummy_mesh, m_clusterID_gylph_draw_commands, m_clusterID_glyph_data); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_clusterID_glyph_identifiers.begin(), m_clusterID_glyph_identifiers.end()); - } - return true; -} - -void megamol::probe_gl::ProbeBillboardGlyphRenderTasks::updateAllRenderTasks() { - for (int i = 0; i < m_type_index_map.size(); ++i) { - auto probe_type = m_type_index_map[i].first; - auto probe_idx = m_type_index_map[i].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } -} - -void megamol::probe_gl::ProbeBillboardGlyphRenderTasks::clearAllRenderTasks() { - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); -} - -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::GlyphScalarProbeData -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::createScalarProbeGlyphData( - probe::FloatProbe const& probe, int probe_id, float scale) { - GlyphScalarProbeData glyph_data; - glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), - probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), - probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); - - glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); - - glyph_data.scale = scale; - - if (probe.getSamplingResult()->samples.size() > 32) { - // TODO print warning/error message - } - - glyph_data.sample_cnt = std::min(static_cast(32), probe.getSamplingResult()->samples.size()); - - for (int i = 0; i < glyph_data.sample_cnt; ++i) { - glyph_data.samples[i] = probe.getSamplingResult()->samples[i]; - } - - glyph_data.probe_id = probe_id; - - return glyph_data; -} - -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::GlyphScalarDistributionProbeData -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::createScalarDistributionProbeGlyphData( - probe::FloatDistributionProbe const& probe, int probe_id, float scale) { - - GlyphScalarDistributionProbeData glyph_data; - glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), - probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), - probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); - - glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); - - glyph_data.scale = scale; - - if (probe.getSamplingResult()->samples.size() > 32) { - // TODO print warning/error message - } - - glyph_data.sample_cnt = std::min(static_cast(32), probe.getSamplingResult()->samples.size()); - - for (int i = 0; i < glyph_data.sample_cnt; ++i) { - glyph_data.samples[i][0] = probe.getSamplingResult()->samples[i].mean; - glyph_data.samples[i][1] = probe.getSamplingResult()->samples[i].lower_bound; - glyph_data.samples[i][2] = probe.getSamplingResult()->samples[i].upper_bound; - } - - glyph_data.probe_id = probe_id; - - return glyph_data; -} - -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::GlyphVectorProbeData -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::createVectorProbeGlyphData( - probe::Vec4Probe const& probe, int probe_id, float scale) { - - GlyphVectorProbeData glyph_data; - glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), - probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), - probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); - - glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); - - glyph_data.scale = scale; - - if (probe.getSamplingResult()->samples.size() > 32) { - // TODO print warning/error message - } - - glyph_data.sample_cnt = std::min(static_cast(32), probe.getSamplingResult()->samples.size()); - - for (int i = 0; i < glyph_data.sample_cnt; ++i) { - glyph_data.samples[i] = probe.getSamplingResult()->samples[i]; - } - - glyph_data.probe_id = probe_id; - - return glyph_data; -} - -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::GlyphClusterIDData -megamol::probe_gl::ProbeBillboardGlyphRenderTasks::createClusterIDGlyphData( - probe::BaseProbe const& probe, int probe_id, float scale) { - - GlyphClusterIDData glyph_data; - glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), - probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), - probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); - - glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); - - glyph_data.scale = scale; - - glyph_data.probe_id = probe_id; - - glyph_data.cluster_id = probe.m_cluster_id; - - return glyph_data; -} diff --git a/plugins/probe_gl/src/ProbeDetailViewRenderTasks.cpp b/plugins/probe_gl/src/ProbeDetailViewRenderer.cpp similarity index 76% rename from plugins/probe_gl/src/ProbeDetailViewRenderTasks.cpp rename to plugins/probe_gl/src/ProbeDetailViewRenderer.cpp index 34e06b4d7b..d841184df3 100644 --- a/plugins/probe_gl/src/ProbeDetailViewRenderTasks.cpp +++ b/plugins/probe_gl/src/ProbeDetailViewRenderer.cpp @@ -1,4 +1,4 @@ -#include "ProbeDetailViewRenderTasks.h" +#include "ProbeDetailViewRenderer.h" #include "mmstd/event/EventCall.h" @@ -8,13 +8,10 @@ #include "mmstd_gl/renderer/CallGetTransferFunctionGL.h" #include "probe/ProbeCalls.h" -megamol::probe_gl::ProbeDetailViewRenderTasks::ProbeDetailViewRenderTasks() - : AbstractGPURenderTaskDataSource() - , m_version(0) - , m_transfer_function_Slot("GetTransferFunction", "Slot for accessing a transfer function") +megamol::probe_gl::ProbeDetailViewRenderer::ProbeDetailViewRenderer() + : m_transfer_function_Slot("GetTransferFunction", "Slot for accessing a transfer function") , m_probes_slot("GetProbes", "Slot for accessing a probe collection") , m_event_slot("GetProbeManipulation", "") - , m_material_collection(nullptr) , m_ui_mesh(nullptr) , m_probes_mesh(nullptr) , m_tf_min(0.0f) @@ -29,12 +26,9 @@ megamol::probe_gl::ProbeDetailViewRenderTasks::ProbeDetailViewRenderTasks() this->MakeSlotAvailable(&this->m_event_slot); } -megamol::probe_gl::ProbeDetailViewRenderTasks::~ProbeDetailViewRenderTasks() {} - -bool megamol::probe_gl::ProbeDetailViewRenderTasks::create() { - - auto retval = AbstractGPURenderTaskDataSource::create(); +megamol::probe_gl::ProbeDetailViewRenderer::~ProbeDetailViewRenderer() {} +void megamol::probe_gl::ProbeDetailViewRenderer::createMaterialCollection() { // Create local copy of transfer function texture (for compatibility with material pipeline) glowl::TextureLayout tex_layout; tex_layout.width = 1; @@ -56,19 +50,17 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::create() { megamol::core::utility::log::Log::DefaultLog.WriteError( "Error on transfer texture view pre-creation: %s. [%s, %s, line %d]\n", exc.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; } - m_material_collection = std::make_shared(); + material_collection_ = std::make_shared(); try { std::vector shaderfiles = {"probes/dfr_probeDetailView.vert.glsl", "probes/dfr_probeDetailView.frag.glsl", "probes/dfr_probeDetailView.tesc.glsl", "probes/dfr_probeDetailView.tese.glsl"}; - m_material_collection->addMaterial(this->instance(), "ProbeDetailView", shaderfiles); + material_collection_->addMaterial(this->instance(), "ProbeDetailView", shaderfiles); } catch (const std::exception& ex) { megamol::core::utility::log::Log::DefaultLog.WriteError( "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; } // TODO ui mesh @@ -103,7 +95,6 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::create() { __LINE__); } } - // create an empty dummy mesh, probe mesh std::vector data_ptrs = {}; @@ -114,62 +105,34 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::create() { //TODO try catch m_probes_mesh = std::make_shared( data_ptrs, byte_sizes, vertex_layout, indices.data(), 6 * 4, GL_UNSIGNED_INT, GL_TRIANGLES, GL_STATIC_DRAW); - - return retval; } -void megamol::probe_gl::ProbeDetailViewRenderTasks::release() {} - -bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& caller) { - - mesh_gl::CallGPURenderTaskData* lhs_rtc = dynamic_cast(&caller); - if (lhs_rtc == nullptr){ - return false; - } - - // if there is a render task connection to the right, pass on the render task collection - mesh_gl::CallGPURenderTaskData* rhs_rtc = this->m_renderTask_rhs_slot.CallAs(); - - auto gpu_render_tasks = std::make_shared>>(); - if (rhs_rtc != nullptr) { - if (!(*rhs_rtc)(0)) { - return false; - } - if (rhs_rtc->hasUpdate()) { - ++m_version; - } - gpu_render_tasks = rhs_rtc->getData(); - } - gpu_render_tasks->push_back(m_rendertask_collection.first); - - // check/get mesh data - mesh_gl::CallGPUMeshData* mc = this->m_mesh_slot.CallAs(); - if (mc != NULL){ - if (!(*mc)(0)) return false; - } +void megamol::probe_gl::ProbeDetailViewRenderer::updateRenderTaskCollection( + mmstd_gl::CallRender3DGL& call, bool force_update) { // check/get probe data probe::CallProbes* pc = this->m_probes_slot.CallAs(); - if (pc == NULL) return false; - if (!(*pc)(0)) return false; - + if (pc != nullptr){ + + if (!(*pc)(0)){ + // TODO throw error + return; + } // check/get transfer function auto* tfc = this->m_transfer_function_Slot.CallAs(); - if (tfc != NULL) { - if (!(*tfc)(0)) return false; + if (tfc != nullptr) { + if (!(*tfc)(0)){ + // TODO throw error + return; + } } bool something_has_changed = pc->hasUpdate() || ((tfc != NULL) ? tfc->IsDirty() : false); if (something_has_changed) { - ++m_version; - - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); + render_task_collection_->clear(); - auto const& ui_shader = m_material_collection->getMaterial("ProbeDetailViewUI").shader_program; + auto const& ui_shader = material_collection_->getMaterial("ProbeDetailViewUI").shader_program; std::vector draw_commands = {glowl::DrawElementsCommand()}; draw_commands[0].cnt = 12; draw_commands[0].instance_cnt = 1; @@ -179,8 +142,7 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& struct UIPerDrawData {}; std::vector per_draw_data = {UIPerDrawData()}; std::vector identifiers = {std::string(FullName()) + "UI"}; - m_rendertask_collection.first->addRenderTasks(identifiers, ui_shader, m_ui_mesh, draw_commands, per_draw_data ); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(),identifiers.begin(),identifiers.end()); + render_task_collection_->addRenderTasks(identifiers, ui_shader, m_ui_mesh, draw_commands, per_draw_data ); auto probes = pc->getData(); auto probe_cnt = probes->getProbeCount(); @@ -374,10 +336,8 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& } if (!m_vector_probe_draw_commands.empty()) { - auto const& probe_shader = m_material_collection->getMaterial("ProbeDetailView").shader_program; - m_rendertask_collection.first->addRenderTasks(m_vector_probe_identifiers,probe_shader, m_probes_mesh, m_vector_probe_draw_commands, m_vector_probe_data); - m_rendertask_collection.second.insert( - m_rendertask_collection.second.end(), m_vector_probe_identifiers.begin(), m_vector_probe_identifiers.end()); + auto const& probe_shader = material_collection_->getMaterial("ProbeDetailView").shader_program; + render_task_collection_->addRenderTasks(m_vector_probe_identifiers,probe_shader, m_probes_mesh, m_vector_probe_draw_commands, m_vector_probe_data); } } @@ -392,17 +352,17 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& bbox[4] = -0.5f; bbox[5] = 3.0f; - auto meta_data = lhs_rtc->getMetaData(); - meta_data.m_bboxs.SetBoundingBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]); - meta_data.m_bboxs.SetClipBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]); - lhs_rtc->setMetaData(meta_data); - + call.AccessBoundingBoxes().SetBoundingBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]); + call.AccessBoundingBoxes().SetClipBox(bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]); // check for pending probe manipulations // check for pending events auto call_event_storage = this->m_event_slot.CallAs(); if (call_event_storage != NULL) { - if ((!(*call_event_storage)(0))) return false; + if ((!(*call_event_storage)(0))){ + // TODO throw + return; + } auto event_collection = call_event_storage->getData(); @@ -452,26 +412,22 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& if (!pending_events.empty()) { auto probe_idx = pending_events.back().obj_id; - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); + render_task_collection_->clear(); for (int i=0; i< m_vector_probe_selected.size(); ++i) { m_vector_probe_selected[i] = false; } if (!m_vector_probe_draw_commands.empty()) { - auto const& probe_shader = m_material_collection->getMaterial("ProbeDetailView").shader_program; + auto const& probe_shader = material_collection_->getMaterial("ProbeDetailView").shader_program; std::string identifier = std::string(FullName()) + std::to_string(probe_idx); - m_rendertask_collection.first->addRenderTask(identifier, + render_task_collection_->addRenderTask(identifier, probe_shader, m_probes_mesh, m_vector_probe_draw_commands[probe_idx], m_vector_probe_data[probe_idx]); - m_rendertask_collection.second.push_back(identifier); m_vector_probe_selected[probe_idx] = true; } - auto const& ui_shader = m_material_collection->getMaterial("ProbeDetailViewUI").shader_program; + auto const& ui_shader = material_collection_->getMaterial("ProbeDetailViewUI").shader_program; std::vector draw_commands = {glowl::DrawElementsCommand()}; draw_commands[0].cnt = 12; draw_commands[0].instance_cnt = 1; @@ -481,8 +437,7 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& struct UIPerDrawData {}; std::vector per_draw_data = {UIPerDrawData()}; std::vector identifiers = {std::string(FullName()) + "UI"}; - m_rendertask_collection.first->addRenderTasks(identifiers, ui_shader, m_ui_mesh, draw_commands, per_draw_data ); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(),identifiers.begin(),identifiers.end()); + render_task_collection_->addRenderTasks(identifiers, ui_shader, m_ui_mesh, draw_commands, per_draw_data ); } } @@ -495,16 +450,15 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& if (!m_vector_probe_draw_commands.empty()) { std::string identifier = std::string(FullName()) + std::to_string(probe_idx); if (!m_vector_probe_selected[probe_idx]) { - auto const& probe_shader = m_material_collection->getMaterial("ProbeDetailView").shader_program; + auto const& probe_shader = material_collection_->getMaterial("ProbeDetailView").shader_program; - m_rendertask_collection.first->addRenderTask(identifier, + render_task_collection_->addRenderTask(identifier, probe_shader, m_probes_mesh, m_vector_probe_draw_commands[probe_idx], m_vector_probe_data[probe_idx]); - m_rendertask_collection.second.push_back(identifier); m_vector_probe_selected[probe_idx] = true; } else { - m_rendertask_collection.first->deleteRenderTask(identifier); + render_task_collection_->deleteRenderTask(identifier); m_vector_probe_selected[probe_idx] = false; } } @@ -512,40 +466,33 @@ bool megamol::probe_gl::ProbeDetailViewRenderTasks::getDataCallback(core::Call& } } - - lhs_rtc->setData(gpu_render_tasks, m_version); - - return true; + } } -bool megamol::probe_gl::ProbeDetailViewRenderTasks::getMetaDataCallback(core::Call& caller) { - if (!AbstractGPURenderTaskDataSource::getMetaDataCallback(caller)) return false; - - mesh_gl::CallGPURenderTaskData* lhs_rt_call = dynamic_cast(&caller); +bool megamol::probe_gl::ProbeDetailViewRenderer::GetExtents(mmstd_gl::CallRender3DGL& call) { + bool retval = false; auto probe_call = m_probes_slot.CallAs(); - if (probe_call == NULL) return false; - - auto lhs_meta_data = lhs_rt_call->getMetaData(); + if (probe_call != nullptr) { + auto probe_meta_data = probe_call->getMetaData(); + probe_meta_data.m_frame_ID = static_cast(call.Time()); + probe_call->setMetaData(probe_meta_data); + if ((*probe_call)(1)) { + probe_meta_data = probe_call->getMetaData(); - auto probe_meta_data = probe_call->getMetaData(); - probe_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; - probe_call->setMetaData(probe_meta_data); - if (!(*probe_call)(1)) return false; - probe_meta_data = probe_call->getMetaData(); + call.SetTimeFramesCount(std::min(call.TimeFramesCount(), probe_meta_data.m_frame_cnt)); - lhs_meta_data.m_frame_cnt = std::min(lhs_meta_data.m_frame_cnt, probe_meta_data.m_frame_cnt); + auto bbox = call.AccessBoundingBoxes().BoundingBox(); + bbox.Union(probe_meta_data.m_bboxs.BoundingBox()); + call.AccessBoundingBoxes().SetBoundingBox(bbox); - //auto bbox = lhs_meta_data.m_bboxs.BoundingBox(); - //bbox.Union(probe_meta_data.m_bboxs.BoundingBox()); - //lhs_meta_data.m_bboxs.SetBoundingBox(bbox); - // - //auto cbbox = lhs_meta_data.m_bboxs.ClipBox(); - //cbbox.Union(probe_meta_data.m_bboxs.ClipBox()); - //lhs_meta_data.m_bboxs.SetClipBox(cbbox); + auto cbbox = call.AccessBoundingBoxes().ClipBox(); + cbbox.Union(probe_meta_data.m_bboxs.ClipBox()); + call.AccessBoundingBoxes().SetClipBox(cbbox); - lhs_rt_call->setMetaData(lhs_meta_data); - - return true; + retval = true; + } + } + return retval; } diff --git a/plugins/probe_gl/src/ProbeDetailViewRenderTasks.h b/plugins/probe_gl/src/ProbeDetailViewRenderer.h similarity index 72% rename from plugins/probe_gl/src/ProbeDetailViewRenderTasks.h rename to plugins/probe_gl/src/ProbeDetailViewRenderer.h index 6b37d88785..932eb56fa7 100644 --- a/plugins/probe_gl/src/ProbeDetailViewRenderTasks.h +++ b/plugins/probe_gl/src/ProbeDetailViewRenderer.h @@ -8,14 +8,14 @@ #ifndef PROBE_DETAIL_VIEW_RENDER_TASK_H_INCLUDED #define PROBE_DETAIL_VIEW_RENDER_TASK_H_INCLUDED -#include "mesh_gl/AbstractGPURenderTaskDataSource.h" +#include "mesh_gl/BaseRenderTaskRenderer.h" #include "probe/ProbeCollection.h" namespace megamol { namespace probe_gl { -class ProbeDetailViewRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSource { +class ProbeDetailViewRenderer : public mesh_gl::BaseRenderTaskRenderer { public: /** * Answer the name of this module. @@ -23,7 +23,7 @@ class ProbeDetailViewRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSour * @return The name of this module. */ static const char* ClassName(void) { - return "ProbeDetailViewRenderTasks"; + return "ProbeDetailViewRenderer"; } /** @@ -35,26 +35,23 @@ class ProbeDetailViewRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSour return "..."; } + ProbeDetailViewRenderer(); + ~ProbeDetailViewRenderer(); + +protected: /** - * Answers whether this module is available on the current system. + * The get extents callback. The module should set the members of + * 'call' to tell the caller the extents of its data (bounding boxes + * and times). + * + * @param call The calling call. * - * @return 'true' if the module is available, 'false' otherwise. + * @return The return value of the function. */ - static bool IsAvailable(void) { - return true; - } - - bool create(); + bool GetExtents(mmstd_gl::CallRender3DGL& call) override; - void release(); - - ProbeDetailViewRenderTasks(); - ~ProbeDetailViewRenderTasks(); - -protected: - bool getDataCallback(core::Call& caller); - - bool getMetaDataCallback(core::Call& caller); + void createMaterialCollection() override; + void updateRenderTaskCollection(mmstd_gl::CallRender3DGL& call, bool force_update) override; private: uint32_t m_version; @@ -65,9 +62,6 @@ class ProbeDetailViewRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSour core::CallerSlot m_event_slot; - /** In-place material collection (initialized with probe detail view btf) */ - std::shared_ptr m_material_collection; - std::shared_ptr m_ui_mesh; // for depth scale (parallel to probe, offset by cam right vector) std::shared_ptr m_probes_mesh; diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp new file mode 100644 index 0000000000..4e27cda14c --- /dev/null +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp @@ -0,0 +1,903 @@ +#include "ProbeGlyphRenderer.h" + +#include "ProbeEvents.h" +#include "ProbeGlCalls.h" +#include "mmstd/event/EventCall.h" +#include "mmstd_gl/renderer/CallGetTransferFunctionGL.h" +#include "probe/ProbeCalls.h" + +#include "glm/glm.hpp" +#include "glm/gtc/type_ptr.hpp" +#include "glm/gtx/transform.hpp" +#include "mmcore/param/BoolParam.h" +#include "mmcore/param/ColorParam.h" +#include "mmcore/param/EnumParam.h" +#include "mmcore/param/FloatParam.h" + +#define IMGUI_DEFINE_MATH_OPERATORS +#include "imgui_impl_opengl3.h" +#include "imgui_stdlib.h" +#include + +megamol::probe_gl::ProbeGlyphRenderer::ProbeGlyphRenderer() + : m_imgui_context(nullptr) + , m_transfer_function_Slot("GetTransferFunction", "Slot for accessing a transfer function") + , m_probes_slot("GetProbes", "Slot for accessing a probe collection") + , m_event_slot("GetProbeEvents", "") + , m_billboard_dummy_mesh(nullptr) + , m_billboard_size_slot("BillBoardSize", "Sets the scaling factor of the texture billboards") + , m_rendering_mode_slot("RenderingMode", "Glyph rendering mode") + , m_use_interpolation_slot("UseInterpolation", "Interpolate between samples") + , m_show_canvas_slot("ShowGlyphCanvas", "Render glyphs with opaque background") + , m_canvas_color_slot("GlyphCanvasColor", "Color used for the background of individual glyphs") + , m_tf_range({0.0f, 0.0f}) + , m_show_glyphs(true) { + + this->m_transfer_function_Slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->m_transfer_function_Slot); + + this->m_probes_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->m_probes_slot); + + this->m_event_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->m_event_slot); + + this->m_billboard_size_slot << new core::param::FloatParam(1.0f); + this->MakeSlotAvailable(&this->m_billboard_size_slot); + + this->m_rendering_mode_slot << new megamol::core::param::EnumParam(0); + this->m_rendering_mode_slot.Param()->SetTypePair(0, "Precomputed"); + this->m_rendering_mode_slot.Param()->SetTypePair(1, "Realtime"); + this->m_rendering_mode_slot.Param()->SetTypePair(2, "ClusterID"); + this->MakeSlotAvailable(&this->m_rendering_mode_slot); + + this->m_use_interpolation_slot << new core::param::BoolParam(true); + this->MakeSlotAvailable(&this->m_use_interpolation_slot); + + this->m_show_canvas_slot << new core::param::BoolParam(true); + this->MakeSlotAvailable(&this->m_show_canvas_slot); + + this->m_canvas_color_slot << new core::param::ColorParam(1.0, 1.0, 1.0, 1.0); + this->MakeSlotAvailable(&this->m_canvas_color_slot); +} + +megamol::probe_gl::ProbeGlyphRenderer::~ProbeGlyphRenderer() {} + +void megamol::probe_gl::ProbeGlyphRenderer::createMaterialCollection() { + // Create local copy of transfer function texture (for compatibility with material pipeline) + glowl::TextureLayout tex_layout; + tex_layout.width = 1; + tex_layout.height = 1; + tex_layout.depth = 1; + tex_layout.levels = 1; + // TODO + tex_layout.format = GL_RGBA; + tex_layout.type = GL_FLOAT; + // TODO + tex_layout.internal_format = GL_RGBA32F; + tex_layout.int_parameters = { + {GL_TEXTURE_MIN_FILTER, GL_NEAREST}, {GL_TEXTURE_MAG_FILTER, GL_LINEAR}, {GL_TEXTURE_WRAP_S, GL_CLAMP}}; + try { + this->m_transfer_function = std::make_shared("ProbeTransferFunction", tex_layout, nullptr); + } catch (glowl::TextureException const& exc) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Error on transfer texture view pre-creation: %s. [%s, %s, line %d]\n", exc.what(), __FILE__, __FUNCTION__, + __LINE__); + } + // TODO intialize with value indicating that no transfer function is connected + this->m_transfer_function->makeResident(); + + + material_collection_ = std::make_shared(); + // textured glyph shader program + + material_collection_->addMaterial(this->instance(), "TexturedProbeGlyph", + {"glyphs/textured_probe_glyph.vert.glsl", "glyphs/textured_probe_glyph.frag.glsl"}); + + // scalar glyph shader program + material_collection_->addMaterial(this->instance(), "ScalarProbeGlyph", + {"glyphs/scalar_probe_glyph_v2.vert.glsl", "glyphs/scalar_probe_glyph_v2.frag.glsl"}); + + // scalar distribution glyph shader program + material_collection_->addMaterial(this->instance(), "ScalarDistributionProbeGlyph", + {"glyphs/scalar_distribution_probe_glyph_v2.vert.glsl", "glyphs/scalar_distribution_probe_glyph.frag.glsl"}); + + // vector glyph shader program + material_collection_->addMaterial(this->instance(), "VectorProbeGlyph", + {"glyphs/vector_probe_glyph.vert.glsl", "glyphs/vector_probe_glyph.frag.glsl"}); + + // cluster ID glyph shader program + material_collection_->addMaterial(this->instance(), "ClusterIDProbeGlyph", + {"glyphs/clusterID_probe_glyph.vert.glsl", "glyphs/clusterID_probe_glyph.frag.glsl"}); +} + +void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( + mmstd_gl::CallRender3DGL& call, bool force_update) { + auto err = glGetError(); + if (err != GL_NO_ERROR) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Unexpeced OpenGL error: %i. [%s, %s, line %d]\n", err, __FILE__, __FUNCTION__, __LINE__); + } + + // create an empty dummy mesh, actual billboard geometry will be build in vertex shader + if (m_billboard_dummy_mesh == nullptr) { + std::vector data_ptrs = {}; + std::vector byte_sizes = {}; + std::vector indices = {0, 1, 2, 3, 4, 5}; + std::vector vertex_layout = {}; + + m_billboard_dummy_mesh = std::make_shared( + data_ptrs, byte_sizes, vertex_layout, indices.data(), 6 * 4, GL_UNSIGNED_INT, GL_TRIANGLES, GL_STATIC_DRAW); + } + + probe::CallProbes* pc = this->m_probes_slot.CallAs(); + if (pc != NULL) { + if (!(*pc)(0)) { + // TODO throw error + return; + } + + auto* tfc = this->m_transfer_function_Slot.CallAs(); + if (tfc != NULL) { + ((*tfc)(0)); + } + + bool something_has_changed = force_update || pc->hasUpdate() || this->m_billboard_size_slot.IsDirty() || + this->m_rendering_mode_slot.IsDirty(); + + if (something_has_changed) { + this->m_billboard_size_slot.ResetDirty(); + this->m_rendering_mode_slot.ResetDirty(); + auto probes = pc->getData(); + + auto visitor = [this](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + // TODO wtf + } else if constexpr (std::is_same_v>) { + m_tf_range = arg; + } else if constexpr (std::is_same_v>) { + // TODO + } else { + // unknown probe type, throw error? do nothing? + } + }; + + std::visit(visitor, probes->getGenericGlobalMinMax()); + + render_task_collection_->clear(); + + auto probe_cnt = probes->getProbeCount(); + + m_type_index_map.clear(); + m_type_index_map.reserve(probe_cnt); + + m_textured_glyph_identifiers.clear(); + m_vector_probe_glyph_identifiers.clear(); + m_scalar_probe_glyph_identifiers.clear(); + m_scalar_distribution_probe_glyph_identifiers.clear(); + m_clusterID_glyph_identifiers.clear(); + + m_textured_glyph_data.clear(); + m_vector_probe_glyph_data.clear(); + m_scalar_probe_glyph_data.clear(); + m_scalar_distribution_probe_glyph_data.clear(); + m_clusterID_glyph_data.clear(); + + m_textured_gylph_draw_commands.clear(); + m_vector_probe_gylph_draw_commands.clear(); + m_scalar_probe_gylph_draw_commands.clear(); + m_scalar_distribution_probe_gylph_draw_commands.clear(); + m_clusterID_gylph_draw_commands.clear(); + + m_textured_gylph_draw_commands.reserve(probe_cnt); + m_textured_glyph_data.reserve(probe_cnt); + + m_vector_probe_gylph_draw_commands.reserve(probe_cnt); + m_vector_probe_glyph_data.reserve(probe_cnt); + + m_scalar_probe_gylph_draw_commands.reserve(probe_cnt); + m_scalar_probe_glyph_data.reserve(probe_cnt); + + m_scalar_distribution_probe_gylph_draw_commands.reserve(probe_cnt); + m_scalar_distribution_probe_glyph_data.reserve(probe_cnt); + + m_clusterID_gylph_draw_commands.reserve(probe_cnt); + m_clusterID_glyph_data.reserve(probe_cnt); + + // draw command looks the same for all billboards because geometry is reused + glowl::DrawElementsCommand draw_command; + draw_command.base_instance = 0; + draw_command.base_vertex = 0; + draw_command.cnt = 6; + draw_command.first_idx = 0; + draw_command.instance_cnt = 1; + + // scale in constant over all billboards + float scale = this->m_billboard_size_slot.Param()->Value(); + + if (m_rendering_mode_slot.Param()->Value() == 0) { + // use precomputed textures if available + auto mat = material_collection_->getMaterial("TexturedProbeGlyph"); + if (mat.shader_program != nullptr && mat.textures.size() > 0) { + for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { + + assert(probe_cnt <= (mat.textures.size() * 2048)); + + auto generic_probe = probes->getGenericProbe(probe_idx); + + GLuint64 texture_handle = mat.textures[probe_idx / 2048]->getTextureHandle(); + float slice_idx = probe_idx % 2048; + mat.textures[probe_idx / 2048]->makeResident(); + + auto visitor = [draw_command, scale, texture_handle, slice_idx, probe_idx, this](auto&& arg) { + using T = std::decay_t; + + auto glyph_data = createTexturedGlyphData(arg, probe_idx, texture_handle, slice_idx, scale); + m_textured_gylph_draw_commands.push_back(draw_command); + this->m_textured_glyph_data.push_back(glyph_data); + + m_textured_glyph_identifiers.emplace_back( + std::string(FullName()) + "_tg_" + std::to_string(probe_idx)); + + this->m_type_index_map.push_back({std::type_index(typeid(TexturedGlyphData)), probe_idx}); + }; + + std::visit(visitor, generic_probe); + } + } + + } else if (m_rendering_mode_slot.Param()->Value() == 1) { + + for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { + + auto generic_probe = probes->getGenericProbe(probe_idx); + + auto visitor = [draw_command, scale, probe_idx, this](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + + auto sp_idx = m_scalar_probe_glyph_data.size(); + + auto glyph_data = createScalarProbeGlyphData(arg, probe_idx, scale); + m_scalar_probe_gylph_draw_commands.push_back(draw_command); + this->m_scalar_probe_glyph_data.push_back(glyph_data); + + m_scalar_probe_glyph_identifiers.emplace_back( + std::string(FullName()) + "_sg_" + std::to_string(probe_idx)); + + this->m_type_index_map.push_back({std::type_index(typeid(GlyphScalarProbeData)), sp_idx}); + + } else if constexpr (std::is_same_v) { + auto sp_idx = m_scalar_distribution_probe_glyph_data.size(); + + auto glyph_data = createScalarDistributionProbeGlyphData(arg, probe_idx, scale); + m_scalar_distribution_probe_gylph_draw_commands.push_back(draw_command); + this->m_scalar_distribution_probe_glyph_data.push_back(glyph_data); + + m_scalar_distribution_probe_glyph_identifiers.emplace_back( + std::string(FullName()) + "_sdg_" + std::to_string(probe_idx)); + + this->m_type_index_map.push_back( + {std::type_index(typeid(GlyphScalarDistributionProbeData)), sp_idx}); + } else if constexpr (std::is_same_v) { + // TODO + } else if constexpr (std::is_same_v) { + + auto vp_idx = m_vector_probe_glyph_data.size(); + + auto glyph_data = createVectorProbeGlyphData(arg, probe_idx, scale); + m_vector_probe_gylph_draw_commands.push_back(draw_command); + this->m_vector_probe_glyph_data.push_back(glyph_data); + + m_vector_probe_glyph_identifiers.emplace_back( + std::string(FullName()) + "_vg_" + std::to_string(probe_idx)); + + this->m_type_index_map.push_back({std::type_index(typeid(GlyphVectorProbeData)), vp_idx}); + + } else { + // unknown probe type, throw error? do nothing? + } + }; + + std::visit(visitor, generic_probe); + } + + } else { + int total_cluster_cnt = 0; + for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { + + auto generic_probe = probes->getGenericProbe(probe_idx); + + auto visitor = [draw_command, scale, probe_idx, &total_cluster_cnt, this](auto&& arg) { + using T = std::decay_t; + + auto glyph_data = createClusterIDGlyphData(arg, probe_idx, scale); + m_clusterID_gylph_draw_commands.push_back(draw_command); + this->m_clusterID_glyph_data.push_back(glyph_data); + + total_cluster_cnt = std::max(total_cluster_cnt, glyph_data.cluster_id); + + m_clusterID_glyph_identifiers.push_back( + std::string(FullName()) + "_cg_" + std::to_string(probe_idx)); + + this->m_type_index_map.push_back({std::type_index(typeid(GlyphClusterIDData)), probe_idx}); + }; + + std::visit(visitor, generic_probe); + } + + for (auto& glyph_data : m_clusterID_glyph_data) { + glyph_data.total_cluster_cnt = total_cluster_cnt; + } + } + + addAllRenderTasks(); + } + + bool per_frame_data_has_changed = this->m_use_interpolation_slot.IsDirty() || + this->m_show_canvas_slot.IsDirty() || this->m_canvas_color_slot.IsDirty() || + ((tfc != NULL) ? tfc->IsDirty() : false) || + render_task_collection_->getPerFrameBuffers().empty(); + + if (per_frame_data_has_changed) { + this->m_use_interpolation_slot.ResetDirty(); + this->m_show_canvas_slot.ResetDirty(); + this->m_canvas_color_slot.ResetDirty(); + + if (tfc != nullptr) { + tfc->SetRange(m_tf_range); + ((*tfc)()); + m_tf_range = tfc->Range(); + } + + // Update transfer texture only if it available and has changed + if (tfc != nullptr) { + + if (tfc->IsDirty()) { + //++m_version; + tfc->ResetDirty(); + + this->m_transfer_function->makeNonResident(); + this->m_transfer_function.reset(); + + { + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + // "Do something cop!" + std::cerr << "GL error during transfer function update" << err << std::endl; + } + } + + glowl::TextureLayout tex_layout; + tex_layout.width = tfc->TextureSize(); + tex_layout.height = 1; + tex_layout.depth = 1; + tex_layout.levels = 1; + // TODO + tex_layout.format = GL_RGBA; + tex_layout.type = GL_FLOAT; + // TODO + tex_layout.internal_format = GL_RGBA32F; + tex_layout.int_parameters = {{GL_TEXTURE_MIN_FILTER, GL_NEAREST}, + {GL_TEXTURE_MAG_FILTER, GL_LINEAR}, {GL_TEXTURE_WRAP_S, GL_CLAMP}}; + try { + this->m_transfer_function = std::make_shared( + "ProbeTransferFunction", tex_layout, (GLvoid*)tfc->GetTextureData()); + } catch (glowl::TextureException const& exc) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Error on transfer texture view creation: %s. [%s, %s, line %d]\n", exc.what(), __FILE__, + __FUNCTION__, __LINE__); + } + + this->m_transfer_function->makeResident(); + { + auto err = glGetError(); + if (err != GL_NO_ERROR) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Error on making transfer texture view resident: %i. [%s, %s, line %d]\n", err, + __FILE__, __FUNCTION__, __LINE__); + } + } + + m_tf_range = tfc->Range(); + } + } + + GLuint64 texture_handle = this->m_transfer_function->getTextureHandle(); + + std::array data; + data[0].use_interpolation = m_use_interpolation_slot.Param()->Value(); + data[0].show_canvas = m_show_canvas_slot.Param()->Value(); + data[0].canvas_color = m_canvas_color_slot.Param()->Value(); + data[0].tf_texture_handle = texture_handle; + data[0].tf_min = std::get<0>(m_tf_range); + data[0].tf_max = std::get<1>(m_tf_range); + + std::string identifier = std::string(FullName()) + "_perFrameData"; + if (render_task_collection_->getPerFrameBuffers().empty()) { + render_task_collection_->addPerFrameDataBuffer(identifier, data, 1); + } else { + render_task_collection_->updatePerFrameDataBuffer(identifier, data, 1); + } + } + + // check for pending events + auto call_event_storage = this->m_event_slot.CallAs(); + if (call_event_storage != NULL) { + if ((!(*call_event_storage)(0))) { + // TODO throw error + return; + } + + auto event_collection = call_event_storage->getData(); + + // process pobe clear selection events + { + auto pending_events = event_collection->get(); + if (!pending_events.empty()) { + for (auto& draw_data : m_scalar_probe_glyph_data) { + draw_data.state = 0; + } + for (auto& draw_data : m_vector_probe_glyph_data) { + draw_data.state = 0; + } + for (auto& draw_data : m_clusterID_glyph_data) { + draw_data.state = 0; + } + + updateAllRenderTasks(); + } + } + + // process probe highlight events + { + auto pending_highlight_events = event_collection->get(); + for (auto& evt : pending_highlight_events) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + per_probe_data[0].state = 1; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + per_probe_data[0].state = 1; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + per_probe_data[0].state = 1; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + + // bool my_tool_active = true; + // float my_color[4] = {0.0, 0.0, 0.0, 0.0}; + // + // // ImGui::NewFrame(); + // // Create a window called "My First Tool", with a menu bar. + // auto ctx = reinterpret_cast(this->GetCoreInstance()->GetCurrentImGuiContext()); + // if (ctx != nullptr) { + // ImGui::SetCurrentContext(ctx); + // ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar); + // if (ImGui::BeginMenuBar()) { + // if (ImGui::BeginMenu("File")) { + // if (ImGui::MenuItem("Open..", "Ctrl+O")) { /* Do stuff */ + // } + // if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Do stuff */ + // } + // if (ImGui::MenuItem("Close", "Ctrl+W")) { + // my_tool_active = false; + // } + // ImGui::EndMenu(); + // } + // ImGui::EndMenuBar(); + // } + // + // // Edit a color (stored as ~4 floats) + // ImGui::ColorEdit4("Color", my_color); + // + // // Plot some values + // const float my_values[] = {0.2f, 0.1f, 1.0f, 0.5f, 0.9f, 2.2f}; + // ImGui::PlotLines("Frame Times", my_values, IM_ARRAYSIZE(my_values)); + // + // // Display contents in a scrolling region + // ImGui::TextColored(ImVec4(1, 1, 0, 1), "Important Stuff"); + // ImGui::BeginChild("Scrolling"); + // for (int n = 0; n < 50; n++) ImGui::Text("%04d: Some text", n); + // ImGui::EndChild(); + // ImGui::End(); + // } + } + } + + // process probe dehighlight events + { + auto pending_dehighlight_events = event_collection->get(); + for (auto& evt : pending_dehighlight_events) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process probe selection events + { + auto pending_select_events = event_collection->get(); + for (auto& evt : pending_select_events) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = 2; + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_ProbeBillboard_Scalar"; + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = 2; + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_ProbeBillboard_Vector"; + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = 2; + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_ProbeBillboard_ClusterID"; + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process probe deselection events + { + auto pending_deselect_events = event_collection->get(); + for (auto& evt : pending_deselect_events) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = 0; + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = 0; + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = 0; + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process probe exclusive selection events + { + auto pending_events = event_collection->get(); + if (!pending_events.empty()) { + + for (auto& draw_data : m_scalar_probe_glyph_data) { + draw_data.state = 0; + } + for (auto& draw_data : m_vector_probe_glyph_data) { + draw_data.state = 0; + } + for (auto& draw_data : m_clusterID_glyph_data) { + draw_data.state = 0; + } + + auto probe_type = m_type_index_map[pending_events.back().obj_id].first; + auto probe_idx = m_type_index_map[pending_events.back().obj_id].second; + + // multiple exclusive selections make no sense, just apply the last one + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = 2; + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = 2; + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = 2; + } + + updateAllRenderTasks(); + } + } + + // process probe selection toggle events + { + auto pending_select_events = event_collection->get(); + for (auto& evt : pending_select_events) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = + m_scalar_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = + m_vector_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = m_clusterID_glyph_data[probe_idx].state == 2 ? 0 : 2; + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process toggle show glyph events + { + auto pending_deselect_events = event_collection->get(); + for (auto& evt : pending_deselect_events) { + m_show_glyphs = !m_show_glyphs; + + if (m_show_glyphs) { + addAllRenderTasks(); + } else { + render_task_collection_->clear(); + } + } + } + } + } +} + +bool megamol::probe_gl::ProbeGlyphRenderer::GetExtents(mmstd_gl::CallRender3DGL& call) { + bool retval = false; + auto probe_call = m_probes_slot.CallAs(); + if (probe_call != nullptr) { + auto probe_meta_data = probe_call->getMetaData(); + probe_meta_data.m_frame_ID = static_cast(call.Time()); + probe_call->setMetaData(probe_meta_data); + if ((*probe_call)(1)) { + probe_meta_data = probe_call->getMetaData(); + + call.SetTimeFramesCount(std::min(call.TimeFramesCount(), probe_meta_data.m_frame_cnt)); + + auto bbox = call.AccessBoundingBoxes().BoundingBox(); + bbox.Union(probe_meta_data.m_bboxs.BoundingBox()); + call.AccessBoundingBoxes().SetBoundingBox(bbox); + + auto cbbox = call.AccessBoundingBoxes().ClipBox(); + cbbox.Union(probe_meta_data.m_bboxs.ClipBox()); + call.AccessBoundingBoxes().SetClipBox(cbbox); + + retval = true; + } + } + return retval; +} + +bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { + + std::shared_ptr textured_shader(nullptr); + std::shared_ptr scalar_shader(nullptr); + std::shared_ptr scalar_distribution_shader(nullptr); + std::shared_ptr vector_shader(nullptr); + std::shared_ptr clusterID_shader(nullptr); + + auto textured_query = material_collection_->getMaterials().find("TexturedProbeGlyph"); + auto scalar_query = material_collection_->getMaterials().find("ScalarProbeGlyph"); + auto scalar_distribution_query = material_collection_->getMaterials().find("ScalarDistributionProbeGlyph"); + auto vector_query = material_collection_->getMaterials().find("VectorProbeGlyph"); + auto clusterID_query = material_collection_->getMaterials().find("ClusterIDProbeGlyph"); + + if (textured_query != material_collection_->getMaterials().end()) { + textured_shader = textured_query->second.shader_program; + } + if (scalar_query != material_collection_->getMaterials().end()) { + scalar_shader = scalar_query->second.shader_program; + } + if (scalar_distribution_query != material_collection_->getMaterials().end()) { + scalar_distribution_shader = scalar_distribution_query->second.shader_program; + } + if (vector_query != material_collection_->getMaterials().end()) { + vector_shader = vector_query->second.shader_program; + } + if (clusterID_query != material_collection_->getMaterials().end()) { + clusterID_shader = clusterID_query->second.shader_program; + } + + + if (textured_shader == nullptr) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Could not get TexturedProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, + __FUNCTION__, __LINE__); + } + if (scalar_shader == nullptr) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Could not get ScalarProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, + __FUNCTION__, __LINE__); + } + if (scalar_distribution_shader == nullptr) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Could not get ScalarDistributionProbeGlyphe material, identifier not found. [%s, %s, line %d]\n", __FILE__, + __FUNCTION__, __LINE__); + } + if (vector_shader == nullptr) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Could not get VectorProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, + __FUNCTION__, __LINE__); + } + if (clusterID_shader == nullptr) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Could not get ClusterIDProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, + __FUNCTION__, __LINE__); + } + + if (!m_textured_gylph_draw_commands.empty()) { + render_task_collection_->addRenderTasks(m_textured_glyph_identifiers, textured_shader, + m_billboard_dummy_mesh, m_textured_gylph_draw_commands, m_textured_glyph_data); + } + + if (!m_scalar_probe_glyph_data.empty()) { + render_task_collection_->addRenderTasks(m_scalar_probe_glyph_identifiers, scalar_shader, + m_billboard_dummy_mesh, m_scalar_probe_gylph_draw_commands, m_scalar_probe_glyph_data); + } + + if (!m_scalar_distribution_probe_glyph_data.empty()) { + render_task_collection_->addRenderTasks(m_scalar_distribution_probe_glyph_identifiers, + scalar_distribution_shader, m_billboard_dummy_mesh, m_scalar_distribution_probe_gylph_draw_commands, + m_scalar_distribution_probe_glyph_data); + } + + if (!m_vector_probe_glyph_data.empty()) { + render_task_collection_->addRenderTasks(m_vector_probe_glyph_identifiers, vector_shader, + m_billboard_dummy_mesh, m_vector_probe_gylph_draw_commands, m_vector_probe_glyph_data); + } + + if (!m_clusterID_gylph_draw_commands.empty()) { + render_task_collection_->addRenderTasks(m_clusterID_glyph_identifiers, clusterID_shader, + m_billboard_dummy_mesh, m_clusterID_gylph_draw_commands, m_clusterID_glyph_data); + } + return true; +} + +void megamol::probe_gl::ProbeGlyphRenderer::updateAllRenderTasks() { + for (int i = 0; i < m_type_index_map.size(); ++i) { + auto probe_type = m_type_index_map[i].first; + auto probe_idx = m_type_index_map[i].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } +} + +megamol::probe_gl::ProbeGlyphRenderer::GlyphScalarProbeData +megamol::probe_gl::ProbeGlyphRenderer::createScalarProbeGlyphData( + probe::FloatProbe const& probe, int probe_id, float scale) { + GlyphScalarProbeData glyph_data; + glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), + probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), + probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); + + glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); + + glyph_data.scale = scale; + + if (probe.getSamplingResult()->samples.size() > 32) { + // TODO print warning/error message + } + + glyph_data.sample_cnt = std::min(static_cast(32), probe.getSamplingResult()->samples.size()); + + for (int i = 0; i < glyph_data.sample_cnt; ++i) { + glyph_data.samples[i] = probe.getSamplingResult()->samples[i]; + } + + glyph_data.probe_id = probe_id; + + return glyph_data; +} + +megamol::probe_gl::ProbeGlyphRenderer::GlyphScalarDistributionProbeData +megamol::probe_gl::ProbeGlyphRenderer::createScalarDistributionProbeGlyphData( + probe::FloatDistributionProbe const& probe, int probe_id, float scale) { + + GlyphScalarDistributionProbeData glyph_data; + glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), + probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), + probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); + + glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); + + glyph_data.scale = scale; + + if (probe.getSamplingResult()->samples.size() > 32) { + // TODO print warning/error message + } + + glyph_data.sample_cnt = std::min(static_cast(32), probe.getSamplingResult()->samples.size()); + + for (int i = 0; i < glyph_data.sample_cnt; ++i) { + glyph_data.samples[i][0] = probe.getSamplingResult()->samples[i].mean; + glyph_data.samples[i][1] = probe.getSamplingResult()->samples[i].lower_bound; + glyph_data.samples[i][2] = probe.getSamplingResult()->samples[i].upper_bound; + } + + glyph_data.probe_id = probe_id; + + return glyph_data; +} + +megamol::probe_gl::ProbeGlyphRenderer::GlyphVectorProbeData +megamol::probe_gl::ProbeGlyphRenderer::createVectorProbeGlyphData( + probe::Vec4Probe const& probe, int probe_id, float scale) { + + GlyphVectorProbeData glyph_data; + glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), + probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), + probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); + + glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); + + glyph_data.scale = scale; + + if (probe.getSamplingResult()->samples.size() > 32) { + // TODO print warning/error message + } + + glyph_data.sample_cnt = std::min(static_cast(32), probe.getSamplingResult()->samples.size()); + + for (int i = 0; i < glyph_data.sample_cnt; ++i) { + glyph_data.samples[i] = probe.getSamplingResult()->samples[i]; + } + + glyph_data.probe_id = probe_id; + + return glyph_data; +} + +megamol::probe_gl::ProbeGlyphRenderer::GlyphClusterIDData +megamol::probe_gl::ProbeGlyphRenderer::createClusterIDGlyphData( + probe::BaseProbe const& probe, int probe_id, float scale) { + + GlyphClusterIDData glyph_data; + glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), + probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), + probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); + + glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); + + glyph_data.scale = scale; + + glyph_data.probe_id = probe_id; + + glyph_data.cluster_id = probe.m_cluster_id; + + return glyph_data; +} diff --git a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.h b/plugins/probe_gl/src/ProbeGlyphRenderer.h similarity index 86% rename from plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.h rename to plugins/probe_gl/src/ProbeGlyphRenderer.h index bb49cdd63e..d5b6bd3771 100644 --- a/plugins/probe_gl/src/ProbeBillboardGlyphRenderTasks.h +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.h @@ -10,7 +10,7 @@ #include -#include "mesh_gl/AbstractGPURenderTaskDataSource.h" +#include "mesh_gl/BaseRenderTaskRenderer.h" #include "probe/ProbeCollection.h" @@ -19,7 +19,7 @@ namespace megamol { namespace probe_gl { -class ProbeBillboardGlyphRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSource { +class ProbeGlyphRenderer : public mesh_gl::BaseRenderTaskRenderer { public: /** * Answer the name of this module. @@ -27,7 +27,7 @@ class ProbeBillboardGlyphRenderTasks : public mesh_gl::AbstractGPURenderTaskData * @return The name of this module. */ static const char* ClassName(void) { - return "ProbeBillboardGlyphRenderTasks"; + return "ProbeGlyphRenderer"; } /** @@ -39,30 +39,25 @@ class ProbeBillboardGlyphRenderTasks : public mesh_gl::AbstractGPURenderTaskData return "..."; } + ProbeGlyphRenderer(); + ~ProbeGlyphRenderer(); + +protected: /** - * Answers whether this module is available on the current system. + * The get extents callback. The module should set the members of + * 'call' to tell the caller the extents of its data (bounding boxes + * and times). + * + * @param call The calling call. * - * @return 'true' if the module is available, 'false' otherwise. + * @return The return value of the function. */ - static bool IsAvailable(void) { - return true; - } - - bool create(); - - void release(); + bool GetExtents(mmstd_gl::CallRender3DGL& call) override; - ProbeBillboardGlyphRenderTasks(); - ~ProbeBillboardGlyphRenderTasks(); - -protected: - bool getDataCallback(core::Call& caller); - - bool getMetaDataCallback(core::Call& caller); + void createMaterialCollection() override; + void updateRenderTaskCollection(mmstd_gl::CallRender3DGL& call, bool force_update) override; private: - uint32_t m_version; - core::CallerSlot m_transfer_function_Slot; core::CallerSlot m_probes_slot; @@ -79,8 +74,6 @@ class ProbeBillboardGlyphRenderTasks : public mesh_gl::AbstractGPURenderTaskData core::param::ParamSlot m_canvas_color_slot; - std::shared_ptr m_material_collection; - std::shared_ptr m_billboard_dummy_mesh; std::shared_ptr m_transfer_function; @@ -193,8 +186,6 @@ class ProbeBillboardGlyphRenderTasks : public mesh_gl::AbstractGPURenderTaskData void updateAllRenderTasks(); - void clearAllRenderTasks(); - template TexturedGlyphData createTexturedGlyphData( ProbeType const& probe, int probe_id, GLuint64 texture_handle, float slice_idx, float scale); @@ -210,7 +201,7 @@ class ProbeBillboardGlyphRenderTasks : public mesh_gl::AbstractGPURenderTaskData }; template -inline ProbeBillboardGlyphRenderTasks::TexturedGlyphData ProbeBillboardGlyphRenderTasks::createTexturedGlyphData( +inline ProbeGlyphRenderer::TexturedGlyphData ProbeGlyphRenderer::createTexturedGlyphData( ProbeType const& probe, int probe_id, GLuint64 texture_handle, float slice_idx, float scale) { TexturedGlyphData glyph_data; glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.1f), diff --git a/plugins/probe_gl/src/ProbeHullRenderTasks.cpp b/plugins/probe_gl/src/ProbeHullRenderTasks.cpp deleted file mode 100644 index a9ea79297b..0000000000 --- a/plugins/probe_gl/src/ProbeHullRenderTasks.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * ProbeHullRenderTasks.cpp - * - * Copyright (C) 2020 by Universitaet Stuttgart (VISUS). - * All rights reserved. - */ - - -#include "mmcore/param/ColorParam.h" -#include "mmcore/param/EnumParam.h" -#include "mmstd/event/EventCall.h" - -#include "ProbeEvents.h" -#include "ProbeGlCalls.h" -#include "ProbeHUllRenderTasks.h" -#include "probe/ProbeCalls.h" - -#include "mesh/MeshCalls.h" - -bool megamol::probe_gl::ProbeHullRenderTasks::create() { - auto retval = AbstractGPURenderTaskDataSource::create(); - - struct PerFrameData { - int shading_mode; - }; - std::array per_frame_data; - per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); - m_rendertask_collection.first->addPerFrameDataBuffer("", per_frame_data, 1); - - m_material_collection = std::make_shared(); - try { - std::vector shaderfiles = {"hull/dfr_hull_patch.vert.glsl", "hull/dfr_hull.frag.glsl", - "hull/dfr_hull.tesc.glsl", "hull/dfr_hull.tese.glsl"}; - m_material_collection->addMaterial(this->instance(), "ProbeHull", shaderfiles); - } catch (const std::exception& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - try { - std::vector shaderfiles = {"hull/dfr_hull_tri.vert.glsl", "hull/dfr_hull.frag.glsl"}; - m_material_collection->addMaterial(this->instance(), "ProbeTriangleHull", shaderfiles); - } catch (const std::exception& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - - return retval; -} - -megamol::probe_gl::ProbeHullRenderTasks::ProbeHullRenderTasks() - : m_version(0) - , m_show_hull(true) - //, m_probes_slot("probes","") - , m_event_slot("GetEvents", "") - , m_shading_mode_slot("ShadingMode", "") - , m_hull_color_slot("HullColor", "") { - //this->m_probes_slot.SetCompatibleCall(); - //this->MakeSlotAvailable(&this->m_probes_slot); - - this->m_event_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_event_slot); - - this->m_shading_mode_slot << new megamol::core::param::EnumParam(0); - this->m_shading_mode_slot.Param()->SetTypePair(0, "Grey"); - this->m_shading_mode_slot.Param()->SetTypePair(1, "ClusterID"); - this->MakeSlotAvailable(&this->m_shading_mode_slot); - - this->m_hull_color_slot << new megamol::core::param::ColorParam( - this->m_hull_color[0], this->m_hull_color[1], this->m_hull_color[2], 1.0f); - this->MakeSlotAvailable(&this->m_hull_color_slot); -} - -megamol::probe_gl::ProbeHullRenderTasks::~ProbeHullRenderTasks() {} - -bool megamol::probe_gl::ProbeHullRenderTasks::getDataCallback(core::Call& caller) { - mesh_gl::CallGPURenderTaskData* lhs_rtc = dynamic_cast(&caller); - if (lhs_rtc == NULL) - return false; - - mesh_gl::CallGPURenderTaskData* rhs_rtc = this->m_renderTask_rhs_slot.CallAs(); - - auto gpu_render_tasks = std::make_shared>>(); - if (rhs_rtc != nullptr) { - if (!(*rhs_rtc)(0)) { - return false; - } - if (rhs_rtc->hasUpdate()) { - ++m_version; - } - gpu_render_tasks = rhs_rtc->getData(); - } - gpu_render_tasks->push_back(m_rendertask_collection.first); - - mesh_gl::CallGPUMeshData* mc = this->m_mesh_slot.CallAs(); - - - if (mc != nullptr) { - if (!(*mc)(0)) - return false; - - if (m_shading_mode_slot.IsDirty()) { - m_shading_mode_slot.ResetDirty(); - - struct PerFrameData { - int shading_mode; - }; - - std::array per_frame_data; - per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); - - m_rendertask_collection.first->updatePerFrameDataBuffer("", per_frame_data, 1); - } - - if (m_hull_color_slot.IsDirty()) { - m_hull_color_slot.ResetDirty(); - - std::array obj_color = this->m_hull_color_slot.Param()->Value(); - - for (auto& batch : m_per_object_data) { - for (auto& data : batch) { - data.color = obj_color; - } - } - - for (int i = 0; i < m_batch_meshes.size(); ++i) { - for (int j = 0; j < m_identifiers[i].size(); ++j) { - m_rendertask_collection.first->updatePerDrawData( - m_identifiers[i][j], std::vector{m_per_object_data[i][j]}); - } - } - } - - bool something_has_changed = mc->hasUpdate(); - - if (something_has_changed) { - ++m_version; - - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); - - m_identifiers.clear(); - m_draw_commands.clear(); - m_per_object_data.clear(); - m_batch_meshes.clear(); - - auto gpu_mesh_storage = mc->getData(); - - for (auto& mesh_collection : *gpu_mesh_storage) { - - std::shared_ptr prev_mesh(nullptr); - - int counter = 0; - for (auto& sub_mesh : mesh_collection->getSubMeshData()) { - auto const& gpu_batch_mesh = sub_mesh.second.mesh->mesh; - - //counter++; - //if (counter == 4) { - // continue; - //} - - if (gpu_batch_mesh != prev_mesh) { - m_identifiers.emplace_back(std::vector()); - m_draw_commands.emplace_back(std::vector()); - m_per_object_data.emplace_back(std::vector()); - m_batch_meshes.push_back(gpu_batch_mesh); - - prev_mesh = gpu_batch_mesh; - } - - float scale = 1.0f; - std::array obj_xform = {scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, - scale, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - std::array obj_color = this->m_hull_color_slot.Param()->Value(); - - m_identifiers.back().emplace_back(std::string(FullName()) + "_" + sub_mesh.first); - m_draw_commands.back().push_back(sub_mesh.second.sub_mesh_draw_command); - m_per_object_data.back().push_back(PerObjectData{obj_xform, obj_color}); - } - } - - if (m_show_hull) { - auto patch_shader = m_material_collection->getMaterial("ProbeHull").shader_program; - auto tri_shader = m_material_collection->getMaterial("ProbeTriangleHull").shader_program; - - for (int i = 0; i < m_batch_meshes.size(); ++i) { - - if (m_batch_meshes[i]->getPrimitiveType() == GL_TRIANGLES) { - m_rendertask_collection.first->addRenderTasks( - m_identifiers[i], tri_shader, m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); - m_rendertask_collection.second.insert( - m_rendertask_collection.second.end(), m_identifiers[i].begin(), m_identifiers[i].end()); - } else if (m_batch_meshes[i]->getPrimitiveType() == GL_PATCHES) { - m_rendertask_collection.first->addRenderTasks(m_identifiers[i], patch_shader, m_batch_meshes[i], - m_draw_commands[i], m_per_object_data[i]); - m_rendertask_collection.second.insert( - m_rendertask_collection.second.end(), m_identifiers[i].begin(), m_identifiers[i].end()); - } else { - //TODO print warning - } - } - } - } - - // check for pending events - auto call_event_storage = this->m_event_slot.CallAs(); - if (call_event_storage != NULL) { - if ((!(*call_event_storage)(0))) - return false; - - auto event_collection = call_event_storage->getData(); - - // process toggle show glyph events - { - auto pending_deselect_events = event_collection->get(); - for (auto& evt : pending_deselect_events) { - m_show_hull = !m_show_hull; - - if (m_show_hull) { - //TODO get rid of code copy-pasting... - auto patch_shader = m_material_collection->getMaterial("ProbeHull").shader_program; - auto tri_shader = m_material_collection->getMaterial("ProbeTriangleHull").shader_program; - - for (int i = 0; i < m_batch_meshes.size(); ++i) { - - if (m_batch_meshes[i]->getPrimitiveType() == GL_TRIANGLES) { - m_rendertask_collection.first->addRenderTasks(m_identifiers[i], tri_shader, - m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_identifiers[i].begin(), m_identifiers[i].end()); - } else if (m_batch_meshes[i]->getPrimitiveType() == GL_PATCHES) { - m_rendertask_collection.first->addRenderTasks(m_identifiers[i], patch_shader, - m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_identifiers[i].begin(), m_identifiers[i].end()); - } else { - // TODO print warning - } - } - } else { - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); - } - } - } - } - - // TODO merge meta data stuff, i.e. bounding box - auto mesh_meta_data = mc->getMetaData(); - } - - // set data if necessary - lhs_rtc->setData(gpu_render_tasks, m_version); - - return true; -} - -bool megamol::probe_gl::ProbeHullRenderTasks::getMetaDataCallback(core::Call& caller) { - - if (!AbstractGPURenderTaskDataSource::getMetaDataCallback(caller)) - return false; - - mesh_gl::CallGPURenderTaskData* lhs_rt_call = dynamic_cast(&caller); - mesh_gl::CallGPUMeshData* mesh_call = this->m_mesh_slot.CallAs(); - - auto lhs_meta_data = lhs_rt_call->getMetaData(); - - if (mesh_call != NULL) { - auto mesh_meta_data = mesh_call->getMetaData(); - mesh_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; - mesh_call->setMetaData(mesh_meta_data); - if (!(*mesh_call)(1)) - return false; - mesh_meta_data = mesh_call->getMetaData(); - - auto bbox = lhs_meta_data.m_bboxs.BoundingBox(); - auto cbbox = lhs_meta_data.m_bboxs.ClipBox(); - - auto mesh_bbox = mesh_meta_data.m_bboxs.BoundingBox(); - auto mesh_cbbox = mesh_meta_data.m_bboxs.ClipBox(); - - // mesh_bbox.SetSize(vislib::math::Dimension( - // 2.1f * mesh_bbox.GetSize()[0], 2.1f * mesh_bbox.GetSize()[1], 2.1f * mesh_bbox.GetSize()[2])); - - mesh_cbbox.SetSize(vislib::math::Dimension( - 2.1f * mesh_cbbox.GetSize()[0], 2.1f * mesh_cbbox.GetSize()[1], 2.1f * mesh_cbbox.GetSize()[2])); - - bbox.Union(mesh_bbox); - cbbox.Union(mesh_cbbox); - - lhs_meta_data.m_bboxs.SetBoundingBox(bbox); - lhs_meta_data.m_bboxs.SetClipBox(cbbox); - } - - lhs_rt_call->setMetaData(lhs_meta_data); - - return true; -} diff --git a/plugins/probe_gl/src/ProbeHullRenderer.cpp b/plugins/probe_gl/src/ProbeHullRenderer.cpp new file mode 100644 index 0000000000..4057cdedc1 --- /dev/null +++ b/plugins/probe_gl/src/ProbeHullRenderer.cpp @@ -0,0 +1,201 @@ +/* + * ProbeHullRenderTasks.cpp + * + * Copyright (C) 2020 by Universitaet Stuttgart (VISUS). + * All rights reserved. + */ + + +#include "mmcore/param/ColorParam.h" +#include "mmcore/param/EnumParam.h" +#include "mmstd/event/EventCall.h" + +#include "ProbeEvents.h" +#include "ProbeGlCalls.h" +#include "ProbeHUllRenderer.h" +#include "probe/ProbeCalls.h" + +#include "mesh/MeshCalls.h" + +megamol::probe_gl::ProbeHullRenderer::ProbeHullRenderer() + : m_show_hull(true) + //, m_probes_slot("probes","") + , m_event_slot("GetEvents", "") + , m_shading_mode_slot("ShadingMode", "") + , m_hull_color_slot("HullColor", "") { + //this->m_probes_slot.SetCompatibleCall(); + //this->MakeSlotAvailable(&this->m_probes_slot); + + this->m_event_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->m_event_slot); + + this->m_shading_mode_slot << new megamol::core::param::EnumParam(0); + this->m_shading_mode_slot.Param()->SetTypePair(0, "Grey"); + this->m_shading_mode_slot.Param()->SetTypePair(1, "ClusterID"); + this->MakeSlotAvailable(&this->m_shading_mode_slot); + + this->m_hull_color_slot << new megamol::core::param::ColorParam( + this->m_hull_color[0], this->m_hull_color[1], this->m_hull_color[2], 1.0f); + this->MakeSlotAvailable(&this->m_hull_color_slot); +} + +megamol::probe_gl::ProbeHullRenderer::~ProbeHullRenderer() {} + + +void megamol::probe_gl::ProbeHullRenderer::createMaterialCollection() { + material_collection_ = std::make_shared(); + material_collection_->addMaterial(this->instance(), "ProbeHull", + {"hull/dfr_hull_patch.vert.glsl", "hull/dfr_hull.frag.glsl", "hull/dfr_hull.tesc.glsl", + "hull/dfr_hull.tese.glsl"}); + material_collection_->addMaterial( + this->instance(), "ProbeTriangleHull", {"hull/dfr_hull_tri.vert.glsl", "hull/dfr_hull.frag.glsl"}); +} + +void megamol::probe_gl::ProbeHullRenderer::createRenderTaskCollection() { + render_task_collection_ = std::make_shared(); + struct PerFrameData { + int shading_mode; + }; + std::array per_frame_data; + per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); + render_task_collection_->addPerFrameDataBuffer("", per_frame_data, 1); +} + +void megamol::probe_gl::ProbeHullRenderer::updateRenderTaskCollection( + mmstd_gl::CallRender3DGL& call, bool force_update) { + + + if (m_shading_mode_slot.IsDirty()) { + m_shading_mode_slot.ResetDirty(); + + struct PerFrameData { + int shading_mode; + }; + + std::array per_frame_data; + per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); + + render_task_collection_->updatePerFrameDataBuffer("", per_frame_data, 1); + } + + if (m_hull_color_slot.IsDirty()) { + m_hull_color_slot.ResetDirty(); + + std::array obj_color = this->m_hull_color_slot.Param()->Value(); + + for (auto& batch : m_per_object_data) { + for (auto& data : batch) { + data.color = obj_color; + } + } + + for (int i = 0; i < m_batch_meshes.size(); ++i) { + for (int j = 0; j < m_identifiers[i].size(); ++j) { + render_task_collection_->updatePerDrawData( + m_identifiers[i][j], std::vector{m_per_object_data[i][j]}); + } + } + } + + bool something_has_changed = force_update; + + if (something_has_changed) { + render_task_collection_->clear(); + + m_identifiers.clear(); + m_draw_commands.clear(); + m_per_object_data.clear(); + m_batch_meshes.clear(); + + std::shared_ptr prev_mesh(nullptr); + + int counter = 0; + for (auto& sub_mesh : mesh_collection_->getSubMeshData()) { + auto const& gpu_batch_mesh = sub_mesh.second.mesh->mesh; + + //counter++; + //if (counter == 4) { + // continue; + //} + + if (gpu_batch_mesh != prev_mesh) { + m_identifiers.emplace_back(std::vector()); + m_draw_commands.emplace_back(std::vector()); + m_per_object_data.emplace_back(std::vector()); + m_batch_meshes.push_back(gpu_batch_mesh); + + prev_mesh = gpu_batch_mesh; + } + + float scale = 1.0f; + std::array obj_xform = { + scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + std::array obj_color = this->m_hull_color_slot.Param()->Value(); + + m_identifiers.back().emplace_back(std::string(FullName()) + "_" + sub_mesh.first); + m_draw_commands.back().push_back(sub_mesh.second.sub_mesh_draw_command); + m_per_object_data.back().push_back(PerObjectData{obj_xform, obj_color}); + } + + + if (m_show_hull) { + auto patch_shader = material_collection_->getMaterial("ProbeHull").shader_program; + auto tri_shader = material_collection_->getMaterial("ProbeTriangleHull").shader_program; + + for (int i = 0; i < m_batch_meshes.size(); ++i) { + + if (m_batch_meshes[i]->getPrimitiveType() == GL_TRIANGLES) { + render_task_collection_->addRenderTasks( + m_identifiers[i], tri_shader, m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); + } else if (m_batch_meshes[i]->getPrimitiveType() == GL_PATCHES) { + render_task_collection_->addRenderTasks( + m_identifiers[i], patch_shader, m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); + } else { + //TODO print warning + } + } + } + } + + // check for pending events + auto call_event_storage = this->m_event_slot.CallAs(); + if (call_event_storage != NULL) { + if ((!(*call_event_storage)(0))) { + // TODO throw error + return; + } + + auto event_collection = call_event_storage->getData(); + + // process toggle show glyph events + { + auto pending_deselect_events = event_collection->get(); + for (auto& evt : pending_deselect_events) { + m_show_hull = !m_show_hull; + + if (m_show_hull) { + //TODO get rid of code copy-pasting... + auto patch_shader = material_collection_->getMaterial("ProbeHull").shader_program; + auto tri_shader = material_collection_->getMaterial("ProbeTriangleHull").shader_program; + + for (int i = 0; i < m_batch_meshes.size(); ++i) { + + if (m_batch_meshes[i]->getPrimitiveType() == GL_TRIANGLES) { + render_task_collection_->addRenderTasks(m_identifiers[i], tri_shader, m_batch_meshes[i], + m_draw_commands[i], m_per_object_data[i]); + } else if (m_batch_meshes[i]->getPrimitiveType() == GL_PATCHES) { + render_task_collection_->addRenderTasks(m_identifiers[i], patch_shader, m_batch_meshes[i], + m_draw_commands[i], m_per_object_data[i]); + } else { + // TODO print warning + } + } + } else { + render_task_collection_->clear(); + } + } + } + } + + // TODO merge meta data stuff, i.e. bounding box +} diff --git a/plugins/probe_gl/src/ProbeHullRenderTasks.h b/plugins/probe_gl/src/ProbeHullRenderer.h similarity index 66% rename from plugins/probe_gl/src/ProbeHullRenderTasks.h rename to plugins/probe_gl/src/ProbeHullRenderer.h index 9b2154c4e1..7a7540fae2 100644 --- a/plugins/probe_gl/src/ProbeHullRenderTasks.h +++ b/plugins/probe_gl/src/ProbeHullRenderer.h @@ -8,12 +8,12 @@ #ifndef PROBE_HULL_RENDER_TASK_H_INCLUDED #define PROBE_HULL_RENDER_TASK_H_INCLUDED -#include "mesh_gl/AbstractGPURenderTaskDataSource.h" +#include "mesh_gl/BaseMeshRenderer.h" namespace megamol { namespace probe_gl { -class ProbeHullRenderTasks : public megamol::mesh_gl::AbstractGPURenderTaskDataSource { +class ProbeHullRenderer : public mesh_gl::BaseMeshRenderer { public: /** * Answer the name of this module. @@ -21,7 +21,7 @@ class ProbeHullRenderTasks : public megamol::mesh_gl::AbstractGPURenderTaskDataS * @return The name of this module. */ static const char* ClassName(void) { - return "ProbeHullRenderTasks"; + return "ProbeHullRenderer"; } /** @@ -33,28 +33,15 @@ class ProbeHullRenderTasks : public megamol::mesh_gl::AbstractGPURenderTaskDataS return "Simple mesh viewer for the enclosing hull for probe placement."; } - /** - * Answers whether this module is available on the current system. - * - * @return 'true' if the module is available, 'false' otherwise. - */ - static bool IsAvailable(void) { - return true; - } - - bool create(); - - ProbeHullRenderTasks(); - ~ProbeHullRenderTasks(); + ProbeHullRenderer(); + ~ProbeHullRenderer(); protected: - virtual bool getDataCallback(core::Call& caller); - - virtual bool getMetaDataCallback(core::Call& caller); + void createMaterialCollection() override; + void createRenderTaskCollection() override; + void updateRenderTaskCollection(mmstd_gl::CallRender3DGL& call, bool force_update) override; private: - uint32_t m_version; - bool m_show_hull; std::vector> m_identifiers; @@ -73,9 +60,6 @@ class ProbeHullRenderTasks : public megamol::mesh_gl::AbstractGPURenderTaskDataS core::CallerSlot m_event_slot; - /** In-place material collection (initialized with probe hull btf) */ - std::shared_ptr m_material_collection; - /** Slot for setting different rendering mode in hull shader */ core::param::ParamSlot m_shading_mode_slot; diff --git a/plugins/probe_gl/src/ProbeRenderTasks.cpp b/plugins/probe_gl/src/ProbeRenderTasks.cpp deleted file mode 100644 index 3d0cc0a966..0000000000 --- a/plugins/probe_gl/src/ProbeRenderTasks.cpp +++ /dev/null @@ -1,340 +0,0 @@ -#include "ProbeRenderTasks.h" - -#include "mmstd/event/EventCall.h" - -#include "ProbeEvents.h" -#include "ProbeGlCalls.h" -#include "mesh/MeshCalls.h" -#include "probe/ProbeCalls.h" - -#include "glm/glm.hpp" -#include "glm/gtc/type_ptr.hpp" -#include "glm/gtx/transform.hpp" - -megamol::probe_gl::ProbeRenderTasks::ProbeRenderTasks() - : m_version(0) - , m_material_collection(nullptr) - , m_show_probes(true) - , m_probes_slot("GetProbes", "Slot for accessing a probe collection") - , m_event_slot("GetEvents", "") { - this->m_probes_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_probes_slot); - - this->m_event_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_event_slot); -} - -megamol::probe_gl::ProbeRenderTasks::~ProbeRenderTasks() {} - -bool megamol::probe_gl::ProbeRenderTasks::create() { - auto retval = AbstractGPURenderTaskDataSource::create(); - - m_material_collection = std::make_shared(); - try { - std::vector shaderfiles = { - "probes/dfr_interaction_probe.vert.glsl", "probes/dfr_interaction_probe.frag.glsl"}; - m_material_collection->addMaterial(this->instance(), "ProbeInteraction", shaderfiles); - } catch (std::runtime_error const& ex) { - megamol::core::utility::log::Log::DefaultLog.WriteError( - "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); - retval = false; - } - - return retval; -} - -bool megamol::probe_gl::ProbeRenderTasks::getDataCallback(core::Call& caller) { - { - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - megamol::core::utility::log::Log::DefaultLog.WriteError("GL error during rendering" + err); - } - } - - mesh_gl::CallGPURenderTaskData* lhs_rtc = dynamic_cast(&caller); - if (lhs_rtc == NULL) - return false; - - mesh_gl::CallGPURenderTaskData* rhs_rtc = this->m_renderTask_rhs_slot.CallAs(); - - auto gpu_render_tasks = std::make_shared>>(); - if (rhs_rtc != nullptr) { - if (!(*rhs_rtc)(0)) { - return false; - } - if (rhs_rtc->hasUpdate()) { - ++m_version; - } - gpu_render_tasks = rhs_rtc->getData(); - } - gpu_render_tasks->push_back(m_rendertask_collection.first); - - - mesh_gl::CallGPUMeshData* mc = this->m_mesh_slot.CallAs(); - if (mc == NULL) - return false; - if (!(*mc)(0)) - return false; // TODO only call callback when hash is outdated? - - probe::CallProbes* pc = this->m_probes_slot.CallAs(); - if (pc == NULL) - return false; - if (!(*pc)(0)) - return false; - - // something has changed in the neath - bool something_has_changed = mc->hasUpdate() || pc->hasUpdate(); - - auto gpu_mesh_storage = mc->getData(); - auto probes = pc->getData(); - - struct PerObjData { - glm::mat4x4 object_transform; - int highlighted; - float pad0; - float pad1; - float pad2; - }; - - if (something_has_changed) { - ++m_version; - - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); - - auto probe_cnt = probes->getProbeCount(); - - m_identifiers.clear(); - m_identifiers.resize(probe_cnt); - - m_probe_draw_data.clear(); - m_probe_draw_data.resize(probe_cnt); - - m_draw_commands.clear(); - m_draw_commands.resize(probe_cnt); - - for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { - try { - // auto probe = probes->getProbe(probe_idx); - - auto generic_probe = probes->getGenericProbe(probe_idx); - - std::array direction; - std::array position; - float begin; - float end; - - auto visitor = [&direction, &position, &begin, &end](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - direction = arg.m_direction; - position = arg.m_position; - begin = arg.m_begin; - end = arg.m_end; - } else if constexpr (std::is_same_v) { - direction = arg.m_direction; - position = arg.m_position; - begin = arg.m_begin; - end = arg.m_end; - } else if constexpr (std::is_same_v) { - direction = arg.m_direction; - position = arg.m_position; - begin = arg.m_begin; - end = arg.m_end; - } else { - // unknown probe type, throw error? do nothing? - } - }; - - std::visit(visitor, generic_probe); - - // TODO create and add new render task for probe - - assert(gpu_mesh_storage->front()->getSubMeshData().size() > 0); - - m_identifiers[probe_idx] = (std::string(FullName()) + "_probe_" + std::to_string(probe_idx)); - - auto const& gpu_sub_mesh = gpu_mesh_storage->front()->getSubMeshData().begin()->second; - - m_draw_commands[probe_idx] = gpu_sub_mesh.sub_mesh_draw_command; - - const glm::vec3 from(0.0f, 0.0f, 1.0f); - const glm::vec3 to(direction[0], direction[1], direction[2]); - glm::vec3 v = glm::cross(to, from); - float angle = -acos(glm::dot(to, from) / (glm::length(to) * glm::length(from))); - m_probe_draw_data[probe_idx].object_transform = glm::rotate(angle, v); - - auto scaling = glm::scale(glm::vec3(end - begin)); - - auto probe_start_point = glm::vec3(position[0] + direction[0] * begin, - position[1] + direction[1] * begin, position[2] + direction[2] * begin); - auto translation = glm::translate(glm::mat4(), probe_start_point); - m_probe_draw_data[probe_idx].object_transform = - translation * m_probe_draw_data[probe_idx].object_transform * scaling; - - } catch (std::bad_variant_access&) { - // TODO log error, dont add new render task - } - } - - auto const& gpu_sub_mesh = gpu_mesh_storage->front()->getSubMeshData().begin()->second; - auto const& shader = m_material_collection->getMaterials().begin()->second.shader_program; - - if (m_show_probes) { - m_rendertask_collection.first->addRenderTasks( - m_identifiers, shader, gpu_sub_mesh.mesh->mesh, m_draw_commands, m_probe_draw_data); - m_rendertask_collection.second.insert( - m_rendertask_collection.second.end(), m_identifiers.begin(), m_identifiers.end()); - } - } - - { - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - megamol::core::utility::log::Log::DefaultLog.WriteError("GL error during rendering" + err); - } - } - - // check for pending events - auto call_event_storage = this->m_event_slot.CallAs(); - if (call_event_storage != NULL) { - if ((!(*call_event_storage)(0))) - return false; - - auto event_collection = call_event_storage->getData(); - - // process pobe clear selection events - { - auto pending_clearselection_events = event_collection->get(); - for (auto& evt : pending_clearselection_events) { - for (auto& draw_data : m_probe_draw_data) { - draw_data.highlighted = 0; - } - - if (m_show_probes) { - for (int i = 0; i < m_probe_draw_data.size(); ++i) { - std::array per_probe_data = {m_probe_draw_data[i]}; - m_rendertask_collection.first->updatePerDrawData(m_identifiers[i], per_probe_data); - } - } - } - } - - // process probe highlight events - { - auto pending_highlight_events = event_collection->get(); - for (auto& evt : pending_highlight_events) { - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - per_probe_data[0].highlighted = 1; - - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process probe dehighlight events - { - auto pending_dehighlight_events = event_collection->get(); - for (auto& evt : pending_dehighlight_events) { - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process probe selection events - { - auto pending_select_events = event_collection->get(); - for (auto& evt : pending_select_events) { - m_probe_draw_data[evt.obj_id].highlighted = 2; - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process probe deselection events - { - auto pending_deselect_events = event_collection->get(); - for (auto& evt : pending_deselect_events) { - m_probe_draw_data[evt.obj_id].highlighted = 0; - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - m_rendertask_collection.first->updatePerDrawData(identifier, per_probe_data); - } - } - } - - // process toggle show glyph events - { - auto pending_deselect_events = event_collection->get(); - for (auto& evt : pending_deselect_events) { - m_show_probes = !m_show_probes; - - if (m_show_probes) { - auto const& gpu_sub_mesh = gpu_mesh_storage->front()->getSubMeshData().begin()->second; - auto const& shader = m_material_collection->getMaterials().begin()->second.shader_program; - m_rendertask_collection.first->addRenderTasks( - m_identifiers, shader, gpu_sub_mesh.mesh->mesh, m_draw_commands, m_probe_draw_data); - m_rendertask_collection.second.insert( - m_rendertask_collection.second.end(), m_identifiers.begin(), m_identifiers.end()); - } else { - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); - } - } - } - } - - lhs_rtc->setData(gpu_render_tasks, m_version); - - return true; -} - -bool megamol::probe_gl::ProbeRenderTasks::getMetaDataCallback(core::Call& caller) { - - if (!AbstractGPURenderTaskDataSource::getMetaDataCallback(caller)) - return false; - - mesh_gl::CallGPURenderTaskData* lhs_rt_call = dynamic_cast(&caller); - auto probe_call = m_probes_slot.CallAs(); - if (probe_call == NULL) - return false; - - auto lhs_meta_data = lhs_rt_call->getMetaData(); - - auto probe_meta_data = probe_call->getMetaData(); - probe_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; - probe_call->setMetaData(probe_meta_data); - if (!(*probe_call)(1)) - return false; - probe_meta_data = probe_call->getMetaData(); - - lhs_meta_data.m_frame_cnt = std::min(lhs_meta_data.m_frame_cnt, probe_meta_data.m_frame_cnt); - - auto bbox = lhs_meta_data.m_bboxs.BoundingBox(); - bbox.Union(probe_meta_data.m_bboxs.BoundingBox()); - lhs_meta_data.m_bboxs.SetBoundingBox(bbox); - - auto cbbox = lhs_meta_data.m_bboxs.ClipBox(); - cbbox.Union(probe_meta_data.m_bboxs.ClipBox()); - lhs_meta_data.m_bboxs.SetClipBox(cbbox); - - lhs_rt_call->setMetaData(lhs_meta_data); - - return true; -} diff --git a/plugins/probe_gl/src/ProbeRenderer.cpp b/plugins/probe_gl/src/ProbeRenderer.cpp new file mode 100644 index 0000000000..b8eb53803e --- /dev/null +++ b/plugins/probe_gl/src/ProbeRenderer.cpp @@ -0,0 +1,287 @@ +#include "ProbeRenderer.h" + +#include "mmstd/event/EventCall.h" + +#include "ProbeEvents.h" +#include "ProbeGlCalls.h" +#include "mesh/MeshCalls.h" +#include "probe/ProbeCalls.h" + +#include "glm/glm.hpp" +#include "glm/gtc/type_ptr.hpp" +#include "glm/gtx/transform.hpp" + +megamol::probe_gl::ProbeRenderTasks::ProbeRenderTasks() + : m_show_probes(true) + , m_probes_slot("GetProbes", "Slot for accessing a probe collection") + , m_event_slot("GetEvents", "") { + this->m_probes_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->m_probes_slot); + + this->m_event_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->m_event_slot); +} + +megamol::probe_gl::ProbeRenderTasks::~ProbeRenderTasks() {} + +bool megamol::probe_gl::ProbeRenderTasks::GetExtents(mmstd_gl::CallRender3DGL& call) { + bool retval = false; + auto probe_call = m_probes_slot.CallAs(); + if (probe_call != nullptr) { + auto probe_meta_data = probe_call->getMetaData(); + probe_meta_data.m_frame_ID = static_cast(call.Time()); + probe_call->setMetaData(probe_meta_data); + if ((*probe_call)(1)) { + probe_meta_data = probe_call->getMetaData(); + + call.SetTimeFramesCount(std::min(call.TimeFramesCount(), probe_meta_data.m_frame_cnt)); + + auto bbox = call.AccessBoundingBoxes().BoundingBox(); + bbox.Union(probe_meta_data.m_bboxs.BoundingBox()); + call.AccessBoundingBoxes().SetBoundingBox(bbox); + + auto cbbox = call.AccessBoundingBoxes().ClipBox(); + cbbox.Union(probe_meta_data.m_bboxs.ClipBox()); + call.AccessBoundingBoxes().SetClipBox(cbbox); + + retval = true; + } + } + return retval; +} + +void megamol::probe_gl::ProbeRenderTasks::createMaterialCollection() { + material_collection_ = std::make_shared(); + try { + material_collection_->addMaterial(this->instance(), "ProbeInteraction", + {"probes/dfr_interaction_probe.vert.glsl", "probes/dfr_interaction_probe.frag.glsl"}); + } catch (std::runtime_error const& ex) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); + } +} + +void megamol::probe_gl::ProbeRenderTasks::updateRenderTaskCollection( + mmstd_gl::CallRender3DGL& call, bool force_update) { + { + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + megamol::core::utility::log::Log::DefaultLog.WriteError("GL error during rendering" + err); + } + } + + probe::CallProbes* pc = this->m_probes_slot.CallAs(); + if (pc != NULL) { + if (!(*pc)(0)) { + // TODO throw error + return; + } + + // something has changed in the neath + bool something_has_changed = force_update || pc->hasUpdate(); + + auto probes = pc->getData(); + + struct PerObjData { + glm::mat4x4 object_transform; + int highlighted; + float pad0; + float pad1; + float pad2; + }; + + if (something_has_changed) { + render_task_collection_->clear(); + + auto probe_cnt = probes->getProbeCount(); + + m_identifiers.clear(); + m_identifiers.resize(probe_cnt); + + m_probe_draw_data.clear(); + m_probe_draw_data.resize(probe_cnt); + + m_draw_commands.clear(); + m_draw_commands.resize(probe_cnt); + + for (int probe_idx = 0; probe_idx < probe_cnt; ++probe_idx) { + try { + // auto probe = probes->getProbe(probe_idx); + + auto generic_probe = probes->getGenericProbe(probe_idx); + + std::array direction; + std::array position; + float begin; + float end; + + auto visitor = [&direction, &position, &begin, &end](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + direction = arg.m_direction; + position = arg.m_position; + begin = arg.m_begin; + end = arg.m_end; + } else if constexpr (std::is_same_v) { + direction = arg.m_direction; + position = arg.m_position; + begin = arg.m_begin; + end = arg.m_end; + } else if constexpr (std::is_same_v) { + direction = arg.m_direction; + position = arg.m_position; + begin = arg.m_begin; + end = arg.m_end; + } else { + // unknown probe type, throw error? do nothing? + } + }; + + std::visit(visitor, generic_probe); + + // TODO create and add new render task for probe + + assert(mesh_collection_->getSubMeshData().size() > 0); + + m_identifiers[probe_idx] = (std::string(FullName()) + "_probe_" + std::to_string(probe_idx)); + + auto const& gpu_sub_mesh = mesh_collection_->getSubMeshData().begin()->second; + + m_draw_commands[probe_idx] = gpu_sub_mesh.sub_mesh_draw_command; + + const glm::vec3 from(0.0f, 0.0f, 1.0f); + const glm::vec3 to(direction[0], direction[1], direction[2]); + glm::vec3 v = glm::cross(to, from); + float angle = -acos(glm::dot(to, from) / (glm::length(to) * glm::length(from))); + m_probe_draw_data[probe_idx].object_transform = glm::rotate(angle, v); + + auto scaling = glm::scale(glm::vec3(end - begin)); + + auto probe_start_point = glm::vec3(position[0] + direction[0] * begin, + position[1] + direction[1] * begin, position[2] + direction[2] * begin); + auto translation = glm::translate(glm::mat4(), probe_start_point); + m_probe_draw_data[probe_idx].object_transform = + translation * m_probe_draw_data[probe_idx].object_transform * scaling; + + } catch (std::bad_variant_access&) { + // TODO log error, dont add new render task + } + } + + auto const& gpu_sub_mesh = mesh_collection_->getSubMeshData().begin()->second; + auto const& shader = material_collection_->getMaterial("ProbeInteraction").shader_program; + + if (m_show_probes) { + render_task_collection_->addRenderTasks( + m_identifiers, shader, gpu_sub_mesh.mesh->mesh, m_draw_commands, m_probe_draw_data); + } + } + + { + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + megamol::core::utility::log::Log::DefaultLog.WriteError("GL error during rendering" + err); + } + } + + // check for pending events + auto call_event_storage = this->m_event_slot.CallAs(); + if (call_event_storage != NULL) { + if ((!(*call_event_storage)(0))) { + // TODO throw error + return; + } + + auto event_collection = call_event_storage->getData(); + + // process pobe clear selection events + { + auto pending_clearselection_events = event_collection->get(); + for (auto& evt : pending_clearselection_events) { + for (auto& draw_data : m_probe_draw_data) { + draw_data.highlighted = 0; + } + + if (m_show_probes) { + for (int i = 0; i < m_probe_draw_data.size(); ++i) { + std::array per_probe_data = {m_probe_draw_data[i]}; + render_task_collection_->updatePerDrawData(m_identifiers[i], per_probe_data); + } + } + } + } + + // process probe highlight events + { + auto pending_highlight_events = event_collection->get(); + for (auto& evt : pending_highlight_events) { + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + per_probe_data[0].highlighted = 1; + + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process probe dehighlight events + { + auto pending_dehighlight_events = event_collection->get(); + for (auto& evt : pending_dehighlight_events) { + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process probe selection events + { + auto pending_select_events = event_collection->get(); + for (auto& evt : pending_select_events) { + m_probe_draw_data[evt.obj_id].highlighted = 2; + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process probe deselection events + { + auto pending_deselect_events = event_collection->get(); + for (auto& evt : pending_deselect_events) { + m_probe_draw_data[evt.obj_id].highlighted = 0; + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } + } + + // process toggle show glyph events + { + auto pending_deselect_events = event_collection->get(); + for (auto& evt : pending_deselect_events) { + m_show_probes = !m_show_probes; + + if (m_show_probes) { + auto const& gpu_sub_mesh = mesh_collection_->getSubMeshData().begin()->second; + auto const& shader = material_collection_->getMaterial("ProbeInteraction").shader_program; + render_task_collection_->addRenderTasks( + m_identifiers, shader, gpu_sub_mesh.mesh->mesh, m_draw_commands, m_probe_draw_data); + } else { + render_task_collection_->clear(); + } + } + } + } + } +} diff --git a/plugins/probe_gl/src/ProbeRenderTasks.h b/plugins/probe_gl/src/ProbeRenderer.h similarity index 60% rename from plugins/probe_gl/src/ProbeRenderTasks.h rename to plugins/probe_gl/src/ProbeRenderer.h index 3313c8df93..b6092a17ba 100644 --- a/plugins/probe_gl/src/ProbeRenderTasks.h +++ b/plugins/probe_gl/src/ProbeRenderer.h @@ -8,20 +8,23 @@ #ifndef PROBE_RENDER_TASK_H_INCLUDED #define PROBE_RENDER_TASK_H_INCLUDED -#include "mesh_gl/AbstractGPURenderTaskDataSource.h" +#include "mesh_gl/BaseMeshRenderer.h" namespace megamol { namespace probe_gl { -class ProbeRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSource { +class ProbeRenderTasks : public mesh_gl::BaseMeshRenderer { public: + ProbeRenderTasks(); + ~ProbeRenderTasks(); + /** * Answer the name of this module. * * @return The name of this module. */ static const char* ClassName(void) { - return "ProbeRenderTasks"; + return "ProbeRenderer"; } /** @@ -33,29 +36,20 @@ class ProbeRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSource { return "..."; } - /** - * Answers whether this module is available on the current system. - * - * @return 'true' if the module is available, 'false' otherwise. - */ - static bool IsAvailable(void) { - return true; - } - - ProbeRenderTasks(); - ~ProbeRenderTasks(); - protected: /** - * Implementation of 'Create'. + * The get extents callback. The module should set the members of + * 'call' to tell the caller the extents of its data (bounding boxes + * and times). + * + * @param call The calling call. * - * @return 'true' on success, 'false' otherwise. + * @return The return value of the function. */ - virtual bool create(); + bool GetExtents(mmstd_gl::CallRender3DGL& call) override; - virtual bool getDataCallback(core::Call& caller); - - virtual bool getMetaDataCallback(core::Call& caller); + void createMaterialCollection() override; + void updateRenderTaskCollection(mmstd_gl::CallRender3DGL& call, bool force_update) override; private: struct PerProbeDrawData { @@ -66,11 +60,6 @@ class ProbeRenderTasks : public mesh_gl::AbstractGPURenderTaskDataSource { float pad2; }; - uint32_t m_version; - - /** In-place material collection (initialized with probe btf) */ - std::shared_ptr m_material_collection; - std::vector m_identifiers; std::vector m_draw_commands; diff --git a/plugins/probe_gl/src/ProbeShellElementsRenderTasks.cpp b/plugins/probe_gl/src/ProbeShellElementsRenderTasks.cpp deleted file mode 100644 index d83de5e098..0000000000 --- a/plugins/probe_gl/src/ProbeShellElementsRenderTasks.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * ProbeShellElementsRenderTasks.cpp - * - * Copyright (C) 2021 by Universitaet Stuttgart (VISUS). - * All rights reserved. - */ - - -#include "mmcore/param/ColorParam.h" -#include "mmcore/param/EnumParam.h" -#include "mmstd/event/EventCall.h" - -#include "ProbeEvents.h" -#include "ProbeGlCalls.h" -#include "ProbeShellElementsRenderTasks.h" -#include "probe/ProbeCalls.h" - -bool megamol::probe_gl::ProbeShellElementsRenderTasks::create() { - - m_rendertask_collection.first = std::make_shared(); - - struct PerFrameData { - int shading_mode; - }; - - std::array per_frame_data; - per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); - - m_rendertask_collection.first->addPerFrameDataBuffer("", per_frame_data, 1); - - m_material_collection = std::make_shared(); - std::vector shaderfiles = { - "hull/dfr_shell_elements_vertex.glsl", "hull/dfr_shell_elements_fragment.glsl"}; - m_material_collection->addMaterial(this->instance(), "ProbeShellElements", shaderfiles); - - return true; -} - -megamol::probe_gl::ProbeShellElementsRenderTasks::ProbeShellElementsRenderTasks() - : m_version(0) - , m_show_elements(true) - , m_probes_slot("Probes", "") - , m_event_slot("Events", "") - , m_shading_mode_slot("ShadingMode", "") - , m_hull_color_slot("ElementsColor", "") { - // this->m_probes_slot.SetCompatibleCall(); - // this->MakeSlotAvailable(&this->m_probes_slot); - - this->m_event_slot.SetCompatibleCall(); - this->MakeSlotAvailable(&this->m_event_slot); - - this->m_shading_mode_slot << new megamol::core::param::EnumParam(0); - this->m_shading_mode_slot.Param()->SetTypePair(0, "Color"); - this->m_shading_mode_slot.Param()->SetTypePair(1, "ClusterID"); - this->MakeSlotAvailable(&this->m_shading_mode_slot); - - this->m_hull_color_slot << new megamol::core::param::ColorParam( - this->m_hull_color[0], this->m_hull_color[1], this->m_hull_color[2], 1.0f); - this->MakeSlotAvailable(&this->m_hull_color_slot); -} - -megamol::probe_gl::ProbeShellElementsRenderTasks::~ProbeShellElementsRenderTasks() {} - -bool megamol::probe_gl::ProbeShellElementsRenderTasks::getDataCallback(core::Call& caller) { - mesh_gl::CallGPURenderTaskData* lhs_rtc = dynamic_cast(&caller); - if (lhs_rtc == NULL) { - return false; - } - - mesh_gl::CallGPURenderTaskData* rhs_rtc = this->m_renderTask_rhs_slot.CallAs(); - - auto gpu_render_tasks = std::make_shared>>(); - if (rhs_rtc != nullptr) { - if (!(*rhs_rtc)(0)) { - return false; - } - if (rhs_rtc->hasUpdate()) { - ++m_version; - } - gpu_render_tasks = rhs_rtc->getData(); - } - gpu_render_tasks->push_back(m_rendertask_collection.first); - - mesh_gl::CallGPUMeshData* mc = this->m_mesh_slot.CallAs(); - - - if (mc != nullptr) { - if (!(*mc)(0)) { - return false; - } - - if (m_shading_mode_slot.IsDirty()) { - m_shading_mode_slot.ResetDirty(); - - struct PerFrameData { - int shading_mode; - }; - - std::array per_frame_data; - per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); - - m_rendertask_collection.first->updatePerFrameDataBuffer("", per_frame_data, 1); - } - - if (m_hull_color_slot.IsDirty()) { - m_hull_color_slot.ResetDirty(); - - std::array obj_color = this->m_hull_color_slot.Param()->Value(); - - for (auto& batch : m_per_object_data) { - for (auto& data : batch) { - data.color = obj_color; - } - } - - for (int i = 0; i < m_batch_meshes.size(); ++i) { - for (int j = 0; j < m_rt_identifiers[i].size(); ++j) { - m_rendertask_collection.first->updatePerDrawData( - m_rt_identifiers[i][j], std::vector{m_per_object_data[i][j]}); - } - } - } - - bool something_has_changed = mc->hasUpdate(); - - if (something_has_changed) { - ++m_version; - - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); - - m_rt_identifiers.clear(); - m_draw_commands.clear(); - m_per_object_data.clear(); - m_batch_meshes.clear(); - - auto gpu_mesh_storage = mc->getData(); - - for (auto& mesh_collection : *gpu_mesh_storage) { - - std::shared_ptr prev_mesh(nullptr); - - int counter = 0; - for (auto& sub_mesh : mesh_collection->getSubMeshData()) { - auto const& gpu_batch_mesh = sub_mesh.second.mesh->mesh; - - if (gpu_batch_mesh != prev_mesh) { - m_rt_identifiers.emplace_back(std::vector()); - m_draw_commands.emplace_back(std::vector()); - m_per_object_data.emplace_back(std::vector()); - m_batch_meshes.push_back(gpu_batch_mesh); - - prev_mesh = gpu_batch_mesh; - } - - float scale = 1.0f; - std::array obj_xform = {scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, - scale, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - std::array obj_color = this->m_hull_color_slot.Param()->Value(); - - m_rt_identifiers.back().emplace_back(std::string(FullName()) + "_" + sub_mesh.first); - m_draw_commands.back().push_back(sub_mesh.second.sub_mesh_draw_command); - m_per_object_data.back().push_back(PerObjectData{obj_xform, obj_color, -1, 0, 0, 0}); - } - } - - if (m_show_elements) { - auto shader = m_material_collection->getMaterial("ProbeShellElements").shader_program; - for (int i = 0; i < m_batch_meshes.size(); ++i) { - m_rendertask_collection.first->addRenderTasks( - m_rt_identifiers[i], shader, m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); - m_rendertask_collection.second.insert( - m_rendertask_collection.second.end(), m_rt_identifiers[i].begin(), m_rt_identifiers[i].end()); - } - } - } - - // check for pending events - auto call_event_storage = this->m_event_slot.CallAs(); - if (call_event_storage != NULL) { - if ((!(*call_event_storage)(0))) - return false; - - auto event_collection = call_event_storage->getData(); - - // process toggle show glyph events - { - auto pending_deselect_events = event_collection->get(); - for (auto& evt : pending_deselect_events) { - m_show_elements = !m_show_elements; - - if (m_show_elements) { - // TODO get rid of code copy-pasting... - auto shader = m_material_collection->getMaterial("ProbeShellElements").shader_program; - - for (int i = 0; i < m_batch_meshes.size(); ++i) { - m_rendertask_collection.first->addRenderTasks(m_rt_identifiers[i], shader, - m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); - m_rendertask_collection.second.insert(m_rendertask_collection.second.end(), - m_rt_identifiers[i].begin(), m_rt_identifiers[i].end()); - } - } else { - for (auto& identifier : m_rendertask_collection.second) { - m_rendertask_collection.first->deleteRenderTask(identifier); - } - m_rendertask_collection.second.clear(); - } - } - } - } - - // TODO merge meta data stuff, i.e. bounding box - auto mesh_meta_data = mc->getMetaData(); - } - - // set data if necessary - lhs_rtc->setData(gpu_render_tasks, m_version); - - return true; -} - -bool megamol::probe_gl::ProbeShellElementsRenderTasks::getMetaDataCallback(core::Call& caller) { - - if (!AbstractGPURenderTaskDataSource::getMetaDataCallback(caller)) - return false; - - mesh_gl::CallGPURenderTaskData* lhs_rt_call = dynamic_cast(&caller); - mesh_gl::CallGPUMeshData* mesh_call = this->m_mesh_slot.CallAs(); - - auto lhs_meta_data = lhs_rt_call->getMetaData(); - - if (mesh_call != NULL) { - auto mesh_meta_data = mesh_call->getMetaData(); - mesh_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; - mesh_call->setMetaData(mesh_meta_data); - if (!(*mesh_call)(1)) - return false; - mesh_meta_data = mesh_call->getMetaData(); - - auto bbox = lhs_meta_data.m_bboxs.BoundingBox(); - auto cbbox = lhs_meta_data.m_bboxs.ClipBox(); - - auto mesh_bbox = mesh_meta_data.m_bboxs.BoundingBox(); - auto mesh_cbbox = mesh_meta_data.m_bboxs.ClipBox(); - - // mesh_bbox.SetSize(vislib::math::Dimension( - // 2.1f * mesh_bbox.GetSize()[0], 2.1f * mesh_bbox.GetSize()[1], 2.1f * mesh_bbox.GetSize()[2])); - - mesh_cbbox.SetSize(vislib::math::Dimension( - 2.1f * mesh_cbbox.GetSize()[0], 2.1f * mesh_cbbox.GetSize()[1], 2.1f * mesh_cbbox.GetSize()[2])); - - bbox.Union(mesh_bbox); - cbbox.Union(mesh_cbbox); - - lhs_meta_data.m_bboxs.SetBoundingBox(bbox); - lhs_meta_data.m_bboxs.SetClipBox(cbbox); - } - - lhs_rt_call->setMetaData(lhs_meta_data); - - return true; -} diff --git a/plugins/probe_gl/src/ProbeShellElementsRenderer.cpp b/plugins/probe_gl/src/ProbeShellElementsRenderer.cpp new file mode 100644 index 0000000000..1dfe81b769 --- /dev/null +++ b/plugins/probe_gl/src/ProbeShellElementsRenderer.cpp @@ -0,0 +1,174 @@ +/* + * ProbeShellElementsRenderTasks.cpp + * + * Copyright (C) 2021 by Universitaet Stuttgart (VISUS). + * All rights reserved. + */ + + +#include "mmcore/param/ColorParam.h" +#include "mmcore/param/EnumParam.h" +#include "mmstd/event/EventCall.h" + +#include "ProbeEvents.h" +#include "ProbeGlCalls.h" +#include "ProbeShellElementsRenderer.h" +#include "probe/ProbeCalls.h" + + +megamol::probe_gl::ProbeShellElementsRenderTasks::ProbeShellElementsRenderTasks() + : m_show_elements(true) + , m_probes_slot("Probes", "") + , m_event_slot("Events", "") + , m_shading_mode_slot("ShadingMode", "") + , m_hull_color_slot("ElementsColor", "") { + // this->m_probes_slot.SetCompatibleCall(); + // this->MakeSlotAvailable(&this->m_probes_slot); + + this->m_event_slot.SetCompatibleCall(); + this->MakeSlotAvailable(&this->m_event_slot); + + this->m_shading_mode_slot << new megamol::core::param::EnumParam(0); + this->m_shading_mode_slot.Param()->SetTypePair(0, "Color"); + this->m_shading_mode_slot.Param()->SetTypePair(1, "ClusterID"); + this->MakeSlotAvailable(&this->m_shading_mode_slot); + + this->m_hull_color_slot << new megamol::core::param::ColorParam( + this->m_hull_color[0], this->m_hull_color[1], this->m_hull_color[2], 1.0f); + this->MakeSlotAvailable(&this->m_hull_color_slot); +} + +megamol::probe_gl::ProbeShellElementsRenderTasks::~ProbeShellElementsRenderTasks() {} + +void megamol::probe_gl::ProbeShellElementsRenderTasks::createMaterialCollection() { + material_collection_ = std::make_shared(); + std::vector shaderfiles = { + "hull/dfr_shell_elements_vertex.glsl", "hull/dfr_shell_elements_fragment.glsl"}; + material_collection_->addMaterial(this->instance(), "ProbeShellElements", shaderfiles); +} + +void megamol::probe_gl::ProbeShellElementsRenderTasks::createRenderTaskCollection() { + render_task_collection_ = std::make_shared(); + + struct PerFrameData { + int shading_mode; + }; + + std::array per_frame_data; + per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); + + render_task_collection_->addPerFrameDataBuffer("", per_frame_data, 1); +} + +void megamol::probe_gl::ProbeShellElementsRenderTasks::updateRenderTaskCollection( + mmstd_gl::CallRender3DGL& call, bool force_update) { + + if (m_shading_mode_slot.IsDirty()) { + m_shading_mode_slot.ResetDirty(); + + struct PerFrameData { + int shading_mode; + }; + + std::array per_frame_data; + per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); + + render_task_collection_->updatePerFrameDataBuffer("", per_frame_data, 1); + } + + if (m_hull_color_slot.IsDirty()) { + m_hull_color_slot.ResetDirty(); + + std::array obj_color = this->m_hull_color_slot.Param()->Value(); + + for (auto& batch : m_per_object_data) { + for (auto& data : batch) { + data.color = obj_color; + } + } + + for (int i = 0; i < m_batch_meshes.size(); ++i) { + for (int j = 0; j < m_rt_identifiers[i].size(); ++j) { + render_task_collection_->updatePerDrawData( + m_rt_identifiers[i][j], std::vector{m_per_object_data[i][j]}); + } + } + } + + bool something_has_changed = force_update; + + if (something_has_changed) { + render_task_collection_->clear(); + + m_rt_identifiers.clear(); + m_draw_commands.clear(); + m_per_object_data.clear(); + m_batch_meshes.clear(); + + std::shared_ptr prev_mesh(nullptr); + + int counter = 0; + for (auto& sub_mesh : mesh_collection_->getSubMeshData()) { + auto const& gpu_batch_mesh = sub_mesh.second.mesh->mesh; + + if (gpu_batch_mesh != prev_mesh) { + m_rt_identifiers.emplace_back(std::vector()); + m_draw_commands.emplace_back(std::vector()); + m_per_object_data.emplace_back(std::vector()); + m_batch_meshes.push_back(gpu_batch_mesh); + + prev_mesh = gpu_batch_mesh; + } + + float scale = 1.0f; + std::array obj_xform = { + scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + std::array obj_color = this->m_hull_color_slot.Param()->Value(); + + m_rt_identifiers.back().emplace_back(std::string(FullName()) + "_" + sub_mesh.first); + m_draw_commands.back().push_back(sub_mesh.second.sub_mesh_draw_command); + m_per_object_data.back().push_back(PerObjectData{obj_xform, obj_color, -1, 0, 0, 0}); + } + + if (m_show_elements) { + auto shader = material_collection_->getMaterial("ProbeShellElements").shader_program; + for (int i = 0; i < m_batch_meshes.size(); ++i) { + render_task_collection_->addRenderTasks( + m_rt_identifiers[i], shader, m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); + } + } + } + + // check for pending events + auto call_event_storage = this->m_event_slot.CallAs(); + if (call_event_storage != NULL) { + if ((!(*call_event_storage)(0))) { + // TODO throw error + return; + } + + auto event_collection = call_event_storage->getData(); + + // process toggle show glyph events + { + auto pending_deselect_events = event_collection->get(); + for (auto& evt : pending_deselect_events) { + m_show_elements = !m_show_elements; + + if (m_show_elements) { + // TODO get rid of code copy-pasting... + auto shader = material_collection_->getMaterial("ProbeShellElements").shader_program; + + for (int i = 0; i < m_batch_meshes.size(); ++i) { + render_task_collection_->addRenderTasks( + m_rt_identifiers[i], shader, m_batch_meshes[i], m_draw_commands[i], m_per_object_data[i]); + } + } else { + render_task_collection_->clear(); + } + } + } + } + + // TODO merge meta data stuff, i.e. bounding box +} diff --git a/plugins/probe_gl/src/ProbeShellElementsRenderTasks.h b/plugins/probe_gl/src/ProbeShellElementsRenderer.h similarity index 70% rename from plugins/probe_gl/src/ProbeShellElementsRenderTasks.h rename to plugins/probe_gl/src/ProbeShellElementsRenderer.h index 5c2b4f1109..046c2f2d76 100644 --- a/plugins/probe_gl/src/ProbeShellElementsRenderTasks.h +++ b/plugins/probe_gl/src/ProbeShellElementsRenderer.h @@ -8,12 +8,12 @@ #ifndef PROBE_SHELL_ELEMENTS_RENDER_TASK_H_INCLUDED #define PROBE_SHELL_ELEMENTS_RENDER_TASK_H_INCLUDED -#include "mesh_gl/AbstractGPURenderTaskDataSource.h" +#include "mesh_gl/BaseMeshRenderer.h" namespace megamol { namespace probe_gl { -class ProbeShellElementsRenderTasks : public megamol::mesh_gl::AbstractGPURenderTaskDataSource { +class ProbeShellElementsRenderTasks : public mesh_gl::BaseMeshRenderer { public: /** * Answer the name of this module. @@ -21,7 +21,7 @@ class ProbeShellElementsRenderTasks : public megamol::mesh_gl::AbstractGPURender * @return The name of this module. */ static const char* ClassName(void) { - return "ProbeShellElementsRenderTasks"; + return "ProbeShellElementsRenderer"; } /** @@ -33,28 +33,15 @@ class ProbeShellElementsRenderTasks : public megamol::mesh_gl::AbstractGPURender return "Mesh viewer for the elements of shells used for probing."; } - /** - * Answers whether this module is available on the current system. - * - * @return 'true' if the module is available, 'false' otherwise. - */ - static bool IsAvailable(void) { - return true; - } - - bool create(); - ProbeShellElementsRenderTasks(); ~ProbeShellElementsRenderTasks(); protected: - virtual bool getDataCallback(core::Call& caller); - - virtual bool getMetaDataCallback(core::Call& caller); + void createMaterialCollection() override; + void createRenderTaskCollection() override; + void updateRenderTaskCollection(mmstd_gl::CallRender3DGL& call, bool force_update) override; private: - uint32_t m_version; - bool m_show_elements; std::vector> m_rt_identifiers; @@ -77,9 +64,6 @@ class ProbeShellElementsRenderTasks : public megamol::mesh_gl::AbstractGPURender core::CallerSlot m_event_slot; - /** In-place material collection (initialized with probe hull btf) */ - std::shared_ptr m_material_collection; - /** Slot for setting different rendering mode in hull shader */ core::param::ParamSlot m_shading_mode_slot; diff --git a/plugins/probe_gl/src/probe_gl.cpp b/plugins/probe_gl/src/probe_gl.cpp index 9ed6b55333..28c74b9283 100644 --- a/plugins/probe_gl/src/probe_gl.cpp +++ b/plugins/probe_gl/src/probe_gl.cpp @@ -10,14 +10,13 @@ #include "ComputeDistance.h" #include "FilterByProbe.h" #include "PrecomputeGlyphTextures.h" -#include "ProbeBillboardGlyphMaterial.h" -#include "ProbeBillboardGlyphRenderTasks.h" -#include "ProbeDetailViewRenderTasks.h" +#include "ProbeGlyphRenderer.h" +#include "ProbeDetailViewRenderer.h" #include "ProbeGlCalls.h" -#include "ProbeHullRenderTasks.h" +#include "ProbeHullRenderer.h" #include "ProbeInteraction.h" -#include "ProbeRenderTasks.h" -#include "ProbeShellElementsRenderTasks.h" +#include "ProbeRenderer.h" +#include "ProbeShellElementsRenderer.h" namespace megamol::probe_gl { class ProbeGlPluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { @@ -32,13 +31,12 @@ class ProbeGlPluginInstance : public megamol::core::utility::plugins::AbstractPl void registerClasses() override { // register modules - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); - this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); From bec052d983f2d77da7b92618b950af37f892f6e2 Mon Sep 17 00:00:00 2001 From: invor Date: Tue, 9 Aug 2022 14:59:43 +0200 Subject: [PATCH 24/47] Fix probe hull rendering, fix probe_gl shader namespace --- .../glyphs/clusterID_probe_glyph.frag.glsl | 6 +++--- .../glyphs/clusterID_probe_glyph.vert.glsl | 4 ++-- .../scalar_distribution_probe_glyph.frag.glsl | 4 ++-- ...alar_distribution_probe_glyph_v2.vert.glsl | 4 ++-- .../glyphs/scalar_probe_glyph.frag.glsl | 4 ++-- .../glyphs/scalar_probe_glyph.vert.glsl | 4 ++-- .../glyphs/scalar_probe_glyph_v2.frag.glsl | 4 ++-- .../glyphs/scalar_probe_glyph_v2.vert.glsl | 4 ++-- .../glyphs/vector_probe_glyph.frag.glsl | 4 ++-- .../glyphs/vector_probe_glyph.vert.glsl | 4 ++-- .../shaders/probe_gl/hull/dfr_hull.frag.glsl | 2 +- .../probe_gl/src/ProbeDetailViewRenderer.cpp | 6 +++--- plugins/probe_gl/src/ProbeGlyphRenderer.cpp | 10 +++++----- plugins/probe_gl/src/ProbeHullRenderer.cpp | 19 ++++++++++++++----- plugins/probe_gl/src/ProbeRenderer.cpp | 2 +- .../src/ProbeShellElementsRenderer.cpp | 2 +- 16 files changed, 46 insertions(+), 37 deletions(-) diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.frag.glsl index 7ae4fa6c69..fe7d4caaea 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.frag.glsl @@ -1,8 +1,8 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/clusterID_probe_struct.inc.glsl" -#include "utility/hsv-spiral_colors.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/clusterID_probe_struct.inc.glsl" +#include "probe_gl/utility/hsv-spiral_colors.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.vert.glsl index 5e1e0d3a96..56ff484285 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/clusterID_probe_glyph.vert.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/clusterID_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/clusterID_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl index 529526957d..152c088c0a 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/scalar_distribution_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl index ba9e3f311a..4235c25ab3 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/scalar_distribution_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl index 68db1f1994..12799ed065 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl index 800d28227a..4240f701b1 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl index 99ad310331..ad4ee8e035 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl index 758def04a4..463898bda2 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl index 0e8f044963..878446e414 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/vector_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/vector_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl index 88f1154ad4..f7268c4b39 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl @@ -1,7 +1,7 @@ #version 450 -#include "glyphs/extensions.inc.glsl" -#include "glyphs/vector_probe_struct.inc.glsl" +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/vector_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.frag.glsl b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.frag.glsl index 4a09755577..7f7768a532 100644 --- a/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/hull/dfr_hull.frag.glsl @@ -1,6 +1,6 @@ #version 450 -#include "utility/random_colors_lut.inc.glsl" +#include "probe_gl/utility/random_colors_lut.inc.glsl" struct PerFrameData { diff --git a/plugins/probe_gl/src/ProbeDetailViewRenderer.cpp b/plugins/probe_gl/src/ProbeDetailViewRenderer.cpp index d841184df3..946dc0b49e 100644 --- a/plugins/probe_gl/src/ProbeDetailViewRenderer.cpp +++ b/plugins/probe_gl/src/ProbeDetailViewRenderer.cpp @@ -54,9 +54,9 @@ void megamol::probe_gl::ProbeDetailViewRenderer::createMaterialCollection() { material_collection_ = std::make_shared(); try { - std::vector shaderfiles = {"probes/dfr_probeDetailView.vert.glsl", - "probes/dfr_probeDetailView.frag.glsl", "probes/dfr_probeDetailView.tesc.glsl", - "probes/dfr_probeDetailView.tese.glsl"}; + std::vector shaderfiles = {"probe_gl/probes/dfr_probeDetailView.vert.glsl", + "probe_gl/probes/dfr_probeDetailView.frag.glsl", "probe_gl/probes/dfr_probeDetailView.tesc.glsl", + "probe_gl/probes/dfr_probeDetailView.tese.glsl"}; material_collection_->addMaterial(this->instance(), "ProbeDetailView", shaderfiles); } catch (const std::exception& ex) { megamol::core::utility::log::Log::DefaultLog.WriteError( diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp index 4e27cda14c..900ced5601 100644 --- a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp @@ -92,23 +92,23 @@ void megamol::probe_gl::ProbeGlyphRenderer::createMaterialCollection() { // textured glyph shader program material_collection_->addMaterial(this->instance(), "TexturedProbeGlyph", - {"glyphs/textured_probe_glyph.vert.glsl", "glyphs/textured_probe_glyph.frag.glsl"}); + {"probe_gl/glyphs/textured_probe_glyph.vert.glsl", "probe_gl/glyphs/textured_probe_glyph.frag.glsl"}); // scalar glyph shader program material_collection_->addMaterial(this->instance(), "ScalarProbeGlyph", - {"glyphs/scalar_probe_glyph_v2.vert.glsl", "glyphs/scalar_probe_glyph_v2.frag.glsl"}); + {"probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl"}); // scalar distribution glyph shader program material_collection_->addMaterial(this->instance(), "ScalarDistributionProbeGlyph", - {"glyphs/scalar_distribution_probe_glyph_v2.vert.glsl", "glyphs/scalar_distribution_probe_glyph.frag.glsl"}); + {"probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl", "probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl"}); // vector glyph shader program material_collection_->addMaterial(this->instance(), "VectorProbeGlyph", - {"glyphs/vector_probe_glyph.vert.glsl", "glyphs/vector_probe_glyph.frag.glsl"}); + {"probe_gl/glyphs/vector_probe_glyph.vert.glsl", "probe_gl/glyphs/vector_probe_glyph.frag.glsl"}); // cluster ID glyph shader program material_collection_->addMaterial(this->instance(), "ClusterIDProbeGlyph", - {"glyphs/clusterID_probe_glyph.vert.glsl", "glyphs/clusterID_probe_glyph.frag.glsl"}); + {"probe_gl/glyphs/clusterID_probe_glyph.vert.glsl", "probe_gl/glyphs/clusterID_probe_glyph.frag.glsl"}); } void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( diff --git a/plugins/probe_gl/src/ProbeHullRenderer.cpp b/plugins/probe_gl/src/ProbeHullRenderer.cpp index 4057cdedc1..fcb69d9047 100644 --- a/plugins/probe_gl/src/ProbeHullRenderer.cpp +++ b/plugins/probe_gl/src/ProbeHullRenderer.cpp @@ -45,10 +45,10 @@ megamol::probe_gl::ProbeHullRenderer::~ProbeHullRenderer() {} void megamol::probe_gl::ProbeHullRenderer::createMaterialCollection() { material_collection_ = std::make_shared(); material_collection_->addMaterial(this->instance(), "ProbeHull", - {"hull/dfr_hull_patch.vert.glsl", "hull/dfr_hull.frag.glsl", "hull/dfr_hull.tesc.glsl", - "hull/dfr_hull.tese.glsl"}); + {"probe_gl/hull/dfr_hull_patch.vert.glsl", "probe_gl/hull/dfr_hull.frag.glsl", "probe_gl/hull/dfr_hull.tesc.glsl", + "probe_gl/hull/dfr_hull.tese.glsl"}); material_collection_->addMaterial( - this->instance(), "ProbeTriangleHull", {"hull/dfr_hull_tri.vert.glsl", "hull/dfr_hull.frag.glsl"}); + this->instance(), "ProbeTriangleHull", {"probe_gl/hull/dfr_hull_tri.vert.glsl", "probe_gl/hull/dfr_hull.frag.glsl"}); } void megamol::probe_gl::ProbeHullRenderer::createRenderTaskCollection() { @@ -58,7 +58,7 @@ void megamol::probe_gl::ProbeHullRenderer::createRenderTaskCollection() { }; std::array per_frame_data; per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); - render_task_collection_->addPerFrameDataBuffer("", per_frame_data, 1); + render_task_collection_->addPerFrameDataBuffer("ProbeHullPerFrameData", per_frame_data, 1); } void megamol::probe_gl::ProbeHullRenderer::updateRenderTaskCollection( @@ -75,7 +75,7 @@ void megamol::probe_gl::ProbeHullRenderer::updateRenderTaskCollection( std::array per_frame_data; per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); - render_task_collection_->updatePerFrameDataBuffer("", per_frame_data, 1); + render_task_collection_->updatePerFrameDataBuffer("ProbeHullPerFrameData", per_frame_data, 1); } if (m_hull_color_slot.IsDirty()) { @@ -107,6 +107,15 @@ void megamol::probe_gl::ProbeHullRenderer::updateRenderTaskCollection( m_per_object_data.clear(); m_batch_meshes.clear(); + { + struct PerFrameData { + int shading_mode; + }; + std::array per_frame_data; + per_frame_data[0].shading_mode = m_shading_mode_slot.Param()->Value(); + render_task_collection_->addPerFrameDataBuffer("ProbeHullPerFrameData", per_frame_data, 1); + } + std::shared_ptr prev_mesh(nullptr); int counter = 0; diff --git a/plugins/probe_gl/src/ProbeRenderer.cpp b/plugins/probe_gl/src/ProbeRenderer.cpp index b8eb53803e..a9f498190a 100644 --- a/plugins/probe_gl/src/ProbeRenderer.cpp +++ b/plugins/probe_gl/src/ProbeRenderer.cpp @@ -54,7 +54,7 @@ void megamol::probe_gl::ProbeRenderTasks::createMaterialCollection() { material_collection_ = std::make_shared(); try { material_collection_->addMaterial(this->instance(), "ProbeInteraction", - {"probes/dfr_interaction_probe.vert.glsl", "probes/dfr_interaction_probe.frag.glsl"}); + {"probe_gl/probes/dfr_interaction_probe.vert.glsl", "probe_gl/probes/dfr_interaction_probe.frag.glsl"}); } catch (std::runtime_error const& ex) { megamol::core::utility::log::Log::DefaultLog.WriteError( "%s [%s, %s, line %d]\n", ex.what(), __FILE__, __FUNCTION__, __LINE__); diff --git a/plugins/probe_gl/src/ProbeShellElementsRenderer.cpp b/plugins/probe_gl/src/ProbeShellElementsRenderer.cpp index 1dfe81b769..95574175d2 100644 --- a/plugins/probe_gl/src/ProbeShellElementsRenderer.cpp +++ b/plugins/probe_gl/src/ProbeShellElementsRenderer.cpp @@ -43,7 +43,7 @@ megamol::probe_gl::ProbeShellElementsRenderTasks::~ProbeShellElementsRenderTasks void megamol::probe_gl::ProbeShellElementsRenderTasks::createMaterialCollection() { material_collection_ = std::make_shared(); std::vector shaderfiles = { - "hull/dfr_shell_elements_vertex.glsl", "hull/dfr_shell_elements_fragment.glsl"}; + "probe_gl/hull/dfr_shell_elements_vertex.glsl", "probe_gl/hull/dfr_shell_elements_fragment.glsl"}; material_collection_->addMaterial(this->instance(), "ProbeShellElements", shaderfiles); } From e817cd38f1d08c80f7da15fba26742ffdf723cc7 Mon Sep 17 00:00:00 2001 From: invor Date: Fri, 19 Aug 2022 23:41:39 +0200 Subject: [PATCH 25/47] Add save to texture feature for scalar probes --- .../probe_gl/glyphs/renderToTexture.frag.glsl | 14 ++ .../probe_gl/glyphs/renderToTexture.vert.glsl | 33 +++++ plugins/probe_gl/src/ProbeGlyphRenderer.cpp | 132 ++++++++++++++++++ plugins/probe_gl/src/ProbeGlyphRenderer.h | 4 + 4 files changed, 183 insertions(+) create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.frag.glsl create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.vert.glsl diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.frag.glsl new file mode 100644 index 0000000000..ddddf8e1e6 --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.frag.glsl @@ -0,0 +1,14 @@ +#version 450 + +#include "probe_gl/glyphs/extensions.inc.glsl" + +layout(location = 0) flat in int draw_id; +layout(location = 1) in vec2 uv_coords; +layout(location = 2) in vec3 pixel_vector; +layout(location = 3) in vec3 cam_vector; + +layout(location = 0) out vec4 albedo_out; + +void main() { + albedo_out = vec4(0.0,1.0,1.0,1.0); +} diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.vert.glsl new file mode 100644 index 0000000000..214340e43b --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/renderToTexture.vert.glsl @@ -0,0 +1,33 @@ +#version 450 + +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" + +layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; + +uniform mat4 view_mx; +uniform mat4 proj_mx; + +layout(location = 0) flat out int draw_id; +layout(location = 1) out vec2 uv_coords; +layout(location = 2) out vec3 pixel_vector; +layout(location = 3) out vec3 cam_vector; + + +void main() +{ + const vec4 vertices[6] = vec4[6]( vec4( -1.0,-1.0,0.0,0.0 ), + vec4( 1.0,1.0,1.0,1.0 ), + vec4( -1.0,1.0,0.0,1.0 ), + vec4( 1.0,1.0,1.0,1.0 ), + vec4( -1.0,-1.0,0.0,0.0 ), + vec4( 1.0,-1.0,1.0,0.0 ) ); + + vec4 vertex = vertices[gl_VertexID]; + gl_Position = vec4(vertex.xy, -1.0, 1.0); + + draw_id = 0; + uv_coords = vertex.zw; + cam_vector = mesh_shader_params[gl_DrawIDARB].probe_direction.xyz; + +} diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp index 900ced5601..0b9abd0059 100644 --- a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp @@ -1,5 +1,7 @@ #include "ProbeGlyphRenderer.h" +#include "Screenshots.h" + #include "ProbeEvents.h" #include "ProbeGlCalls.h" #include "mmstd/event/EventCall.h" @@ -10,6 +12,7 @@ #include "glm/gtc/type_ptr.hpp" #include "glm/gtx/transform.hpp" #include "mmcore/param/BoolParam.h" +#include "mmcore/param/ButtonParam.h" #include "mmcore/param/ColorParam.h" #include "mmcore/param/EnumParam.h" #include "mmcore/param/FloatParam.h" @@ -30,6 +33,7 @@ megamol::probe_gl::ProbeGlyphRenderer::ProbeGlyphRenderer() , m_use_interpolation_slot("UseInterpolation", "Interpolate between samples") , m_show_canvas_slot("ShowGlyphCanvas", "Render glyphs with opaque background") , m_canvas_color_slot("GlyphCanvasColor", "Color used for the background of individual glyphs") + , m_save_glyphs_to_textures_slot("SaveToImageSlot", "Render glyph to texture and save to image") , m_tf_range({0.0f, 0.0f}) , m_show_glyphs(true) { @@ -59,6 +63,10 @@ megamol::probe_gl::ProbeGlyphRenderer::ProbeGlyphRenderer() this->m_canvas_color_slot << new core::param::ColorParam(1.0, 1.0, 1.0, 1.0); this->MakeSlotAvailable(&this->m_canvas_color_slot); + + this->m_save_glyphs_to_textures_slot << new core::param::ButtonParam(); + this->m_save_glyphs_to_textures_slot.SetUpdateCallback(&ProbeGlyphRenderer::saveGlyphsToImages); + this->MakeSlotAvailable(&this->m_save_glyphs_to_textures_slot); } megamol::probe_gl::ProbeGlyphRenderer::~ProbeGlyphRenderer() {} @@ -109,6 +117,10 @@ void megamol::probe_gl::ProbeGlyphRenderer::createMaterialCollection() { // cluster ID glyph shader program material_collection_->addMaterial(this->instance(), "ClusterIDProbeGlyph", {"probe_gl/glyphs/clusterID_probe_glyph.vert.glsl", "probe_gl/glyphs/clusterID_probe_glyph.frag.glsl"}); + + // render to texture program + material_collection_->addMaterial(this->instance(), "RenderToTexture", + {"probe_gl/glyphs/renderToTexture.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl"}); } void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( @@ -665,6 +677,126 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( } } +bool megamol::probe_gl::ProbeGlyphRenderer::saveGlyphsToImages(core::param::ParamSlot& slot) { + + // process render tasks and render to texture + std::shared_ptr fbo = std::make_shared(256, 256); + fbo->createColorAttachment(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); + std::shared_ptr draw_data_buffer = + std::make_shared(GL_SHADER_STORAGE_BUFFER, nullptr, 0, GL_DYNAMIC_DRAW); + std::shared_ptr draw_command_buffer = + std::make_shared(GL_SHADER_STORAGE_BUFFER, nullptr, 0, GL_DYNAMIC_DRAW); + + GLint previous_read_fbo; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &previous_read_fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + { + // Perform actual rendering after updating mesh data and gltf data + for (auto const& buffer : render_task_collection_->getPerFrameBuffers()) { + uint32_t binding_point = std::get<1>(buffer); + if (binding_point != 0) { + std::get<0>(buffer)->bind(binding_point); + } else { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Binding point 0 reserved for render task data buffer. [%s, %s, line %d]\n", __FILE__, __FUNCTION__, + __LINE__); + } + } + + auto render_func = []( + std::shared_ptr shdr_prgm, + std::shared_ptr fbo, + std::shared_ptr draw_data_buffer, + std::shared_ptr draw_command_buffer) + { + glDisable(GL_DEPTH_TEST); + + fbo->bind(); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, fbo->getWidth(), fbo->getHeight()); + //TODO clear FBO + + shdr_prgm->use(); + + draw_data_buffer->bind(0); + + draw_command_buffer->bind(); + //m_billboard_dummy_mesh->bindVertexArray(); + + //if (m_billboard_dummy_mesh->getPrimitiveType() == GL_PATCHES) { + // glPatchParameteri(GL_PATCH_VERTICES, 4); + // //TODO add generic patch vertex count to render tasks.... + //} + + glDrawArrays(GL_TRIANGLES, 0, 6); + //glMultiDrawElementsIndirect(m_billboard_dummy_mesh->getPrimitiveType(), + // m_billboard_dummy_mesh->getIndexType(), + // (GLvoid*)0, 1, 0); + + glUseProgram(0); + glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); + }; + + auto save_to_disk_func = []( + std::string const& filename, + std::shared_ptr fbo) + { + megamol::frontend_resources::ScreenshotImageData result; + result.resize(static_cast(fbo->getWidth()), static_cast(fbo->getHeight())); + + fbo->bindToRead(0); + //glReadBuffer(m_read_buffer); + glReadPixels(0, 0, fbo->getWidth(), fbo->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, result.image.data()); + + megamol::frontend_resources::ScreenshotImageDataToPNGWriter writer; + writer.write_image(result, filename); + }; + + // loop through "registered" render batches + int draw_idx = 0; + for (auto const& draw_command : m_scalar_probe_gylph_draw_commands) { + + try { + auto const& draw_data = m_scalar_probe_glyph_data[draw_idx]; + draw_command_buffer->rebuffer(&draw_command, sizeof(glowl::DrawElementsCommand)); + draw_data_buffer->rebuffer(&draw_data, sizeof(GlyphScalarProbeData)); + + fbo = std::make_shared(256, 256); + fbo->createColorAttachment(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); + auto shdr_prgm = material_collection_->getMaterials().find("RenderToTexture")->second.shader_program; + + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + + render_func(shdr_prgm, fbo, draw_data_buffer, draw_command_buffer); + + // save texture to disk + auto filename = "probe_scalar_glyph" + std::to_string(draw_idx) + ".png"; + save_to_disk_func(filename, fbo); + } catch (const std::exception&) { + + } + + draw_idx++; + } + + //TODO add loop for other glpyh types + + glBindFramebuffer(GL_READ_FRAMEBUFFER, previous_read_fbo); + + // Clear the way for his ancient majesty, the mighty immediate mode... + glUseProgram(0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); + } + + return true; +} + bool megamol::probe_gl::ProbeGlyphRenderer::GetExtents(mmstd_gl::CallRender3DGL& call) { bool retval = false; auto probe_call = m_probes_slot.CallAs(); diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.h b/plugins/probe_gl/src/ProbeGlyphRenderer.h index d5b6bd3771..2cf4908dcd 100644 --- a/plugins/probe_gl/src/ProbeGlyphRenderer.h +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.h @@ -57,6 +57,8 @@ class ProbeGlyphRenderer : public mesh_gl::BaseRenderTaskRenderer { void createMaterialCollection() override; void updateRenderTaskCollection(mmstd_gl::CallRender3DGL& call, bool force_update) override; + bool saveGlyphsToImages(core::param::ParamSlot& slot); + private: core::CallerSlot m_transfer_function_Slot; @@ -74,6 +76,8 @@ class ProbeGlyphRenderer : public mesh_gl::BaseRenderTaskRenderer { core::param::ParamSlot m_canvas_color_slot; + core::param::ParamSlot m_save_glyphs_to_textures_slot; + std::shared_ptr m_billboard_dummy_mesh; std::shared_ptr m_transfer_function; From 210becaec9334dd4ac565dd3cd037d581e34ddc1 Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 24 Aug 2022 15:06:36 +0200 Subject: [PATCH 26/47] particle list selector now advances the datahash properly --- plugins/datatools/src/ParticleListSelector.cpp | 11 +++++++++++ plugins/datatools/src/ParticleListSelector.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/plugins/datatools/src/ParticleListSelector.cpp b/plugins/datatools/src/ParticleListSelector.cpp index 2ecf2f15ab..b4eb0855ff 100644 --- a/plugins/datatools/src/ParticleListSelector.cpp +++ b/plugins/datatools/src/ParticleListSelector.cpp @@ -17,6 +17,7 @@ datatools::ParticleListSelector::ParticleListSelector(void) : AbstractParticleManipulator("outData", "indata") , listIndexSlot("listIndex", "The thinning factor. Only each n-th particle will be kept.") { this->listIndexSlot.SetParameter(new core::param::IntParam(0, 0)); + listIndexSlot.SetUpdateCallback(&datatools::ParticleListSelector::paramChanged); this->MakeSlotAvailable(&this->listIndexSlot); } @@ -48,6 +49,16 @@ bool datatools::ParticleListSelector::manipulateData( outData.SetParticleListCount(1); outData.AccessParticles(0) = inData.AccessParticles(idx); } + if (_param_changed) { + auto current_hash = outData.DataHash(); + outData.SetDataHash(++current_hash); + _param_changed = false; + } + + return true; +} +bool datatools::ParticleListSelector::paramChanged(core::param::ParamSlot& p) { + _param_changed = true; return true; } diff --git a/plugins/datatools/src/ParticleListSelector.h b/plugins/datatools/src/ParticleListSelector.h index 4d30196d10..7c8534379c 100644 --- a/plugins/datatools/src/ParticleListSelector.h +++ b/plugins/datatools/src/ParticleListSelector.h @@ -58,10 +58,12 @@ class ParticleListSelector : public AbstractParticleManipulator { * @return True on success */ virtual bool manipulateData(geocalls::MultiParticleDataCall& outData, geocalls::MultiParticleDataCall& inData); + bool paramChanged(core::param::ParamSlot& p); private: /** The list selection index */ core::param::ParamSlot listIndexSlot; + bool _param_changed = false; }; } /* end namespace datatools */ From 959340e6b6f4d79666dc8d3c7e2bfa5a41737c7f Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 24 Aug 2022 15:07:51 +0200 Subject: [PATCH 27/47] mesh obj loader does not copy vertices anymore and keeps the original index array --- plugins/mesh/src/WavefrontObjLoader.cpp | 99 +++++++++++++------------ 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/plugins/mesh/src/WavefrontObjLoader.cpp b/plugins/mesh/src/WavefrontObjLoader.cpp index 53930c9760..1fc17be0e5 100644 --- a/plugins/mesh/src/WavefrontObjLoader.cpp +++ b/plugins/mesh/src/WavefrontObjLoader.cpp @@ -67,8 +67,8 @@ bool megamol::mesh::WavefrontObjLoader::getMeshDataCallback(core::Call& caller) return false; } - const bool has_normals = !m_obj_model->attrib.normals.empty(); - const bool has_texcoords = !m_obj_model->attrib.texcoords.empty(); + bool has_normals = !m_obj_model->attrib.normals.empty(); + bool has_texcoords = !(m_obj_model->attrib.texcoords.empty()); // size_t vertex_cnt = m_obj_model->shapes.size() * 3; this->m_positions.clear(); @@ -93,66 +93,71 @@ bool megamol::mesh::WavefrontObjLoader::getMeshDataCallback(core::Call& caller) } // Loop over shapes + int index_offset = 0; + int normal_offset = 0; for (size_t s = 0; s < m_obj_model->shapes.size(); s++) { auto& mesh = m_obj_model->shapes[s].mesh; auto& lines = m_obj_model->shapes[s].lines; + has_normals = has_normals && !(mesh.indices[0].normal_index == -1); + has_texcoords = has_texcoords && !(mesh.indices[0].texcoord_index == -1); + uint64_t vertex_cnt = 0; if (!mesh.indices.empty()) { // Loop over faces(polygon) - size_t index_offset = 0; - m_indices[s].resize(mesh.num_face_vertices.size() * 3); - m_positions[s].reserve(mesh.num_face_vertices.size() * 3 * 3); + std::vector index_vec; + index_vec.reserve(mesh.indices.size()); + std::vector normal_index_vec; + normal_index_vec.reserve(mesh.indices.size()); + for (auto& id : mesh.indices) { + index_vec.emplace_back(id.vertex_index); + normal_index_vec.emplace_back(id.normal_index); + } + m_indices[s] = index_vec; + std::sort(index_vec.begin(), index_vec.end()); + index_vec.erase(std::unique(index_vec.begin(), index_vec.end()), index_vec.end()); + std::sort(normal_index_vec.begin(), normal_index_vec.end()); + normal_index_vec.erase( + std::unique(normal_index_vec.begin(), normal_index_vec.end()), normal_index_vec.end()); + + auto position_begin = &(m_obj_model->attrib.vertices[3 * index_offset]); + m_positions[s].assign(position_begin, position_begin + 3*index_vec.size()); + if (has_normals) { - this->m_normals[s].reserve(mesh.num_face_vertices.size() * 3 * 3); + m_normals[s].resize(m_positions[s].size(), 0.0f); + for (auto& id: mesh.indices) { + m_normals[s][3 * (id.vertex_index - index_offset) + 0] += m_obj_model->attrib.normals[3 * id.normal_index + 0]; + m_normals[s][3 * (id.vertex_index - index_offset) + 1] += m_obj_model->attrib.normals[3 * id.normal_index + 1]; + m_normals[s][3 * (id.vertex_index - index_offset) + 2] += m_obj_model->attrib.normals[3 * id.normal_index + 2]; + } + // normalize + for (int j = 0; j < m_normals[s].size()/3; j++) { + float const length = std::sqrtf(m_normals[s][3 * j] * m_normals[s][3 * j] + + m_normals[s][3 * j + 1] * m_normals[s][3 * j + 1] + + m_normals[s][3 * j + 2] * m_normals[s][3 * j +2]); + m_normals[s][3 * j + 0] = m_normals[s][3 * j + 0] / length; + m_normals[s][3 * j + 1] = m_normals[s][3 * j + 1] / length; + m_normals[s][3 * j + 2] = m_normals[s][3 * j + 2] / length; + } } if (has_texcoords) { - this->m_texcoords[s].reserve(mesh.num_face_vertices.size() * 3 * 2); + auto texcoords_begin = &(m_obj_model->attrib.texcoords[2 * index_offset]); + m_texcoords[s].assign(texcoords_begin, texcoords_begin + 2 * index_vec.size()); } - for (size_t f = 0; f < mesh.num_face_vertices.size(); f++) { - int fv = mesh.num_face_vertices[f]; - - assert(fv == 3); // assume that triangulation was forced - - // Loop over vertices in the face. - for (size_t v = 0; v < fv; v++) { - // access to vertex - tinyobj::index_t idx = mesh.indices[index_offset + v]; - tinyobj::real_t vx = m_obj_model->attrib.vertices[3 * idx.vertex_index + 0]; - tinyobj::real_t vy = m_obj_model->attrib.vertices[3 * idx.vertex_index + 1]; - tinyobj::real_t vz = m_obj_model->attrib.vertices[3 * idx.vertex_index + 2]; - - bbox[0] = std::min(bbox[0], static_cast(vx)); - bbox[1] = std::min(bbox[1], static_cast(vy)); - bbox[2] = std::min(bbox[2], static_cast(vz)); - bbox[3] = std::max(bbox[3], static_cast(vx)); - bbox[4] = std::max(bbox[4], static_cast(vy)); - bbox[5] = std::max(bbox[5], static_cast(vz)); - - m_indices[s][index_offset + v] = index_offset + v; - - auto current_position_ptr = &(m_obj_model->attrib.vertices[3 * idx.vertex_index]); - m_positions[s].insert(m_positions[s].end(), current_position_ptr, current_position_ptr + 3); - - if (has_normals && idx.normal_index >= 0) { - auto current_normal_ptr = &(m_obj_model->attrib.normals[3 * idx.normal_index]); - m_normals[s].insert(m_normals[s].end(), current_normal_ptr, current_normal_ptr + 3); - } - - if (has_texcoords && idx.texcoord_index >= 0) { - auto current_texcoords_ptr = &(m_obj_model->attrib.texcoords[2 * idx.texcoord_index]); - m_texcoords[s].insert( - m_texcoords[s].end(), current_texcoords_ptr, current_texcoords_ptr + 2); - } - } - index_offset += fv; - // per-face material - // m_obj_model->shapes[s].mesh.material_ids[f]; + for (int j = 0; j < m_positions[s].size()/3; j++) { + bbox[0] = std::min(bbox[0], m_positions[s][3*j+0]); + bbox[1] = std::min(bbox[1], m_positions[s][3*j+1]); + bbox[2] = std::min(bbox[2], m_positions[s][3*j+2]); + bbox[3] = std::max(bbox[3], m_positions[s][3*j+0]); + bbox[4] = std::max(bbox[4], m_positions[s][3*j+1]); + bbox[5] = std::max(bbox[5], m_positions[s][3*j+2]); } + index_offset += index_vec.size(); + normal_offset += normal_index_vec.size(); - vertex_cnt = mesh.num_face_vertices.size() * 3; + vertex_cnt = m_positions[s].size() / 3; } else { // Loop over line From d4683f490a63e3f0faf54fac50f50bfdb4618c02 Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 24 Aug 2022 15:10:34 +0200 Subject: [PATCH 28/47] added slot required indicators --- plugins/mmospray/src/OSPRayRenderer.cpp | 1 + plugins/mmospray/src/OSPRaySphereGeometry.cpp | 1 + plugins/mmstd_gl/include/mmstd_gl/renderer/ContextToGL.h | 1 + 3 files changed, 3 insertions(+) diff --git a/plugins/mmospray/src/OSPRayRenderer.cpp b/plugins/mmospray/src/OSPRayRenderer.cpp index 50b8c92d0a..5cf52ce1e8 100644 --- a/plugins/mmospray/src/OSPRayRenderer.cpp +++ b/plugins/mmospray/src/OSPRayRenderer.cpp @@ -28,6 +28,7 @@ OSPRayRenderer::OSPRayRenderer(void) { this->_getStructureSlot.SetCompatibleCall(); this->MakeSlotAvailable(&this->_getStructureSlot); + _getStructureSlot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); _imgSize = {0, 0}; _time = 0; diff --git a/plugins/mmospray/src/OSPRaySphereGeometry.cpp b/plugins/mmospray/src/OSPRaySphereGeometry.cpp index df865a84f8..22832d3ac1 100644 --- a/plugins/mmospray/src/OSPRaySphereGeometry.cpp +++ b/plugins/mmospray/src/OSPRaySphereGeometry.cpp @@ -18,6 +18,7 @@ OSPRaySphereGeometry::OSPRaySphereGeometry(void) this->getDataSlot.SetCompatibleCall(); this->MakeSlotAvailable(&this->getDataSlot); + getDataSlot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); } diff --git a/plugins/mmstd_gl/include/mmstd_gl/renderer/ContextToGL.h b/plugins/mmstd_gl/include/mmstd_gl/renderer/ContextToGL.h index ea46153985..f25796879b 100644 --- a/plugins/mmstd_gl/include/mmstd_gl/renderer/ContextToGL.h +++ b/plugins/mmstd_gl/include/mmstd_gl/renderer/ContextToGL.h @@ -58,6 +58,7 @@ class ContextToGL : public mmstd_gl::Renderer3DModuleGL { this->_getContextSlot.template SetCompatibleCall>(); this->MakeSlotAvailable(&this->_getContextSlot); + _getContextSlot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); } /** Dtor. */ From 928bce874a359f12e6d3ed43bab72b8acd5693cb Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 24 Aug 2022 15:11:22 +0200 Subject: [PATCH 29/47] added dual mesh sampling module, minor fixes --- plugins/probe/include/probe/CallKDTree.h | 7 +- plugins/probe/include/probe/ProbeCollection.h | 13 +- plugins/probe/src/DualMeshProbeSampling.cpp | 605 ++++++++++++++++++ plugins/probe/src/DualMeshProbeSampling.h | 487 ++++++++++++++ plugins/probe/src/MeshSelector.cpp | 4 + plugins/probe/src/PlaceProbes.cpp | 33 +- plugins/probe/src/PlaceProbes.h | 2 +- plugins/probe/src/probe.cpp | 2 + 8 files changed, 1134 insertions(+), 19 deletions(-) create mode 100644 plugins/probe/src/DualMeshProbeSampling.cpp create mode 100644 plugins/probe/src/DualMeshProbeSampling.h diff --git a/plugins/probe/include/probe/CallKDTree.h b/plugins/probe/include/probe/CallKDTree.h index 8a5ac34cfb..8fc6070f3c 100644 --- a/plugins/probe/include/probe/CallKDTree.h +++ b/plugins/probe/include/probe/CallKDTree.h @@ -34,12 +34,7 @@ struct kd_adaptor { // Since this is inlined and the "dim" argument is typically an immediate value, the // "if/else's" are actually solved at compile time. inline coord_t kdtree_get_pt(const size_t idx, const size_t dim) const { - if (dim == 0) - return derived()[idx][0]; - else if (dim == 1) - return derived()[idx][1]; - else - return derived()[idx][2]; + return derived()[idx][dim]; } // Optional bounding-box computation: return false to default to a standard bbox computation loop. diff --git a/plugins/probe/include/probe/ProbeCollection.h b/plugins/probe/include/probe/ProbeCollection.h index e7357aff15..c0b80492bd 100644 --- a/plugins/probe/include/probe/ProbeCollection.h +++ b/plugins/probe/include/probe/ProbeCollection.h @@ -18,6 +18,7 @@ namespace megamol { namespace probe { struct BaseProbe { + enum PlacementMethod {CENTERLINE, CENTERPOINT, VERTEX_NORMAL, FACE_NORMAL, UNKNOWN}; /** time at which this probes samples the data */ size_t m_timestamp; /** semantic name of the values/field that this probe samples */ @@ -30,6 +31,8 @@ struct BaseProbe { float m_begin; /** "sample to" offset from position */ float m_end; + /** original end of probe in case the probe was shortened */ + float m_orig_end; // std::vectorm_sample_idxs; ///< indices of samples relevant to this /** sample radius used by this probe */ float m_sample_radius; @@ -39,8 +42,12 @@ struct BaseProbe { bool m_representant = false; /** string id of the meshes that the probe goes through */ std::vector m_geo_ids; - /** string id of the meshes that the probe goes through */ + /** vertex id on the rendered mesh the probe is placed */ std::vector m_vert_ids; + /** vertex id on the original mesh the probe is placed */ + std::vector m_face_vert_ids; + /** saves the placement method used to create probe */ + PlacementMethod m_placement_method; // virtual void probe() = 0; }; @@ -74,6 +81,8 @@ struct FloatDistributionProbe : public BaseProbe { float mean; float lower_bound; float upper_bound; + std::vector values; + std::vector value_depth; }; struct SamplingResult { @@ -123,7 +132,7 @@ struct Vec4Probe : public BaseProbe { }; using GenericProbe = std::variant; -using GenericMinMax = std::variant, std::array>; +using GenericMinMax = std::variant, std::array, std::array>; class ProbeCollection { public: diff --git a/plugins/probe/src/DualMeshProbeSampling.cpp b/plugins/probe/src/DualMeshProbeSampling.cpp new file mode 100644 index 0000000000..a1233e6558 --- /dev/null +++ b/plugins/probe/src/DualMeshProbeSampling.cpp @@ -0,0 +1,605 @@ +/* + * DualMeshProbeSampling.cpp + * Copyright (C) 2022 by MegaMol Team + * Alle Rechte vorbehalten. + */ + +#include "DualMeshProbeSampling.h" +#include "mmadios/CallADIOSData.h" +#include "geometry_calls/MultiParticleDataCall.h" +#include "mmcore/param/EnumParam.h" +#include "mmcore/param/FlexEnumParam.h" +#include "mmcore/param/FloatParam.h" +#include "probe/CallKDTree.h" +#include "probe/ProbeCalls.h" + + +namespace megamol::probe { + +DualMeshProbeSampling::DualMeshProbeSampling() + : Module() + , _version(0) + , _old_datahash(0) + , _probe_lhs_slot("deployProbe", "") + , _probe_rhs_slot("getProbe", "") + , _adios_rhs_slot("getData", "") + , _full_tree_rhs_slot("getTree", "") + , _parameter_to_sample_slot("ParameterToSample", "") + , _num_samples_per_probe_slot( + "NumSamplesPerProbe", "Note: Tighter sample placement leads to reduced sampling radius.") + , _vec_param_to_samplex_x("ParameterToSampleX", "") + , _vec_param_to_samplex_y("ParameterToSampleY", "") + , _vec_param_to_samplex_z("ParameterToSampleZ", "") + , _vec_param_to_samplex_w("ParameterToSampleW", "") + , _mesh_rhs_slot("getMesh", "Get the surface mesh") + , _debug_lhs_slot("getDMvertices", "") { + + _probe_lhs_slot.SetCallback(CallProbes::ClassName(), CallProbes::FunctionName(0), &DualMeshProbeSampling::getData); + _probe_lhs_slot.SetCallback( + CallProbes::ClassName(), CallProbes::FunctionName(1), &DualMeshProbeSampling::getMetaData); + MakeSlotAvailable(&_probe_lhs_slot); + + _debug_lhs_slot.SetCallback(geocalls::MultiParticleDataCall::ClassName(), + geocalls::MultiParticleDataCall::FunctionName(0), &DualMeshProbeSampling::getParticleData); + _debug_lhs_slot.SetCallback(geocalls::MultiParticleDataCall::ClassName(), + geocalls::MultiParticleDataCall::FunctionName(1), &DualMeshProbeSampling::getParticleMetaData); + MakeSlotAvailable(&_debug_lhs_slot); + + _probe_rhs_slot.SetCompatibleCall(); + MakeSlotAvailable(&_probe_rhs_slot); + _probe_rhs_slot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); + + _mesh_rhs_slot.SetCompatibleCall(); + MakeSlotAvailable(&_mesh_rhs_slot); + _mesh_rhs_slot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); + + _adios_rhs_slot.SetCompatibleCall(); + MakeSlotAvailable(&_adios_rhs_slot); + _adios_rhs_slot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); + + _full_tree_rhs_slot.SetCompatibleCall(); + MakeSlotAvailable(&_full_tree_rhs_slot); + _full_tree_rhs_slot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); + + core::param::FlexEnumParam* paramEnum = new core::param::FlexEnumParam("undef"); + _parameter_to_sample_slot << paramEnum; + _parameter_to_sample_slot.SetUpdateCallback(&DualMeshProbeSampling::paramChanged); + MakeSlotAvailable(&_parameter_to_sample_slot); + + _num_samples_per_probe_slot << new core::param::IntParam(10); + _num_samples_per_probe_slot.SetUpdateCallback(&DualMeshProbeSampling::paramChanged); + MakeSlotAvailable(&_num_samples_per_probe_slot); + + core::param::FlexEnumParam* paramEnum_1 = new core::param::FlexEnumParam("undef"); + _vec_param_to_samplex_x << paramEnum_1; + _vec_param_to_samplex_x.SetUpdateCallback(&DualMeshProbeSampling::paramChanged); + MakeSlotAvailable(&_vec_param_to_samplex_x); + + core::param::FlexEnumParam* paramEnum_2 = new core::param::FlexEnumParam("undef"); + _vec_param_to_samplex_y << paramEnum_2; + _vec_param_to_samplex_y.SetUpdateCallback(&DualMeshProbeSampling::paramChanged); + MakeSlotAvailable(&_vec_param_to_samplex_y); + + core::param::FlexEnumParam* paramEnum_3 = new core::param::FlexEnumParam("undef"); + _vec_param_to_samplex_z << paramEnum_3; + _vec_param_to_samplex_z.SetUpdateCallback(&DualMeshProbeSampling::paramChanged); + MakeSlotAvailable(&_vec_param_to_samplex_z); + + core::param::FlexEnumParam* paramEnum_4 = new core::param::FlexEnumParam("undef"); + _vec_param_to_samplex_w << paramEnum_4; + _vec_param_to_samplex_w.SetUpdateCallback(&DualMeshProbeSampling::paramChanged); + MakeSlotAvailable(&_vec_param_to_samplex_w); +} + +DualMeshProbeSampling::~DualMeshProbeSampling() { + Release(); +} + +bool DualMeshProbeSampling::create() { + return true; +} + +void DualMeshProbeSampling::release() {} + +bool DualMeshProbeSampling::getData(core::Call& call) { + + bool something_has_changed = false; + auto cp = dynamic_cast(&call); + if (cp == nullptr) + return false; + + // query adios data + auto cd = _adios_rhs_slot.CallAs(); + auto ct = _full_tree_rhs_slot.CallAs(); + auto cprobes = _probe_rhs_slot.CallAs(); + auto csm = _mesh_rhs_slot.CallAs(); + + + std::vector toInq; + std::string var_str = + std::string(_parameter_to_sample_slot.Param()->ValueString()); + + std::string x_var_str = + std::string(_vec_param_to_samplex_x.Param()->ValueString()); + std::string y_var_str = + std::string(_vec_param_to_samplex_y.Param()->ValueString()); + std::string z_var_str = + std::string(_vec_param_to_samplex_z.Param()->ValueString()); + std::string w_var_str = + std::string(_vec_param_to_samplex_w.Param()->ValueString()); + + core::Spatial3DMetaData meta_data = cp->getMetaData(); + core::Spatial3DMetaData tree_meta_data; + core::Spatial3DMetaData probes_meta_data; + + // only for particle data + if (cd != nullptr && ct != nullptr && csm != nullptr) { + + toInq.clear(); + if (var_str != "undef") { + toInq.emplace_back( + std::string(_parameter_to_sample_slot.Param()->ValueString())); + } else { + toInq.emplace_back( + std::string(_vec_param_to_samplex_x.Param()->ValueString())); + toInq.emplace_back( + std::string(_vec_param_to_samplex_y.Param()->ValueString())); + toInq.emplace_back( + std::string(_vec_param_to_samplex_z.Param()->ValueString())); + toInq.emplace_back( + std::string(_vec_param_to_samplex_w.Param()->ValueString())); + } + + // get data from adios + for (auto var : toInq) { + if (!cd->inquireVar(var)) + return false; + } + + if (cd->getDataHash() != _old_datahash || _trigger_recalc) { + if (!(*cd)(0)) + return false; + } + + // query kd tree data + if (!(*ct)(0)) + return false; + + // query dual mesh + if (!(*csm)(0)) + return false; + + + tree_meta_data = ct->getMetaData(); + + something_has_changed = something_has_changed || (cd->getDataHash() != _old_datahash) || ct->hasUpdate(); + } else { + return false; + } + + // query probe data + if (cprobes == nullptr) + return false; + if (!(*cprobes)(0)) + return false; + + something_has_changed = something_has_changed || cprobes->hasUpdate() || _trigger_recalc; + + probes_meta_data = cprobes->getMetaData(); + _probes = cprobes->getData(); + + if (something_has_changed) { + ++_version; + + auto surface_mesh = csm->getData(); + if (!calcDualMesh(surface_mesh)) { + log.WriteError("[DualMeshProbeSampling] Error during dual mesh calculation."); + return false; + } + + if (var_str != "undef") { + if (cd == nullptr || ct == nullptr) { + log.WriteError( + "[DualMeshProbeSampling] Scalar mode selected but no particle data connected."); + return false; + } + // scalar sampling + auto tree = ct->getData(); + if (cd->getData(var_str)->getType() == "double") { + std::vector data = cd->getData(var_str)->GetAsDouble(); + doScalarDistributionSampling(tree, data); + } else if (cd->getData(var_str)->getType() == "float") { + std::vector data = cd->getData(var_str)->GetAsFloat(); + doScalarDistributionSampling(tree, data); + } + } else { + if (cd == nullptr || ct == nullptr) { + log.WriteError( + "[DualMeshProbeSampling] Vector mode selected but no particle data connected."); + return false; + } + // vector sampling + auto tree = ct->getData(); + if (cd->getData(x_var_str)->getType() == "double" && cd->getData(y_var_str)->getType() == "double" && + cd->getData(z_var_str)->getType() == "double" && cd->getData(w_var_str)->getType() == "double") { + std::vector data_x = cd->getData(x_var_str)->GetAsDouble(); + std::vector data_y = cd->getData(y_var_str)->GetAsDouble(); + std::vector data_z = cd->getData(z_var_str)->GetAsDouble(); + std::vector data_w = cd->getData(w_var_str)->GetAsDouble(); + + doVectorSamling(tree, data_x, data_y, data_z, data_w); + + } else if (cd->getData(x_var_str)->getType() == "float" && cd->getData(y_var_str)->getType() == "float" && + cd->getData(z_var_str)->getType() == "float" && cd->getData(w_var_str)->getType() == "float") { + std::vector data_x = cd->getData(x_var_str)->GetAsFloat(); + std::vector data_y = cd->getData(y_var_str)->GetAsFloat(); + std::vector data_z = cd->getData(z_var_str)->GetAsFloat(); + std::vector data_w = cd->getData(w_var_str)->GetAsFloat(); + + doVectorSamling(tree, data_x, data_y, data_z, data_w); + + } + } + } + + // put data into probes + + if (cd != nullptr) { + _old_datahash = cd->getDataHash(); + meta_data.m_bboxs = tree_meta_data.m_bboxs; + } + + cp->setMetaData(meta_data); + cp->setData(_probes, _version); + _trigger_recalc = false; + + + return true; +} + +bool DualMeshProbeSampling::getMetaData(core::Call& call) { + + auto cp = dynamic_cast(&call); + if (cp == nullptr) + return false; + + auto cd = _adios_rhs_slot.CallAs(); + auto ct = _full_tree_rhs_slot.CallAs(); + auto cprobes = _probe_rhs_slot.CallAs(); + if (cprobes == nullptr) { + log.WriteError("[DualMeshProbeSampling] Connecting probes is required."); + return false; + } + + auto cdm = _mesh_rhs_slot.CallAs(); + if (cdm == nullptr) { + log.WriteError("[DualMeshProbeSampling] Connecting a dual mesh is required."); + return false; + } + + auto meta_data = cp->getMetaData(); + // if (cd->getDataHash() == _old_datahash && meta_data.m_frame_ID == cd->getFrameIDtoLoad() && !_trigger_recalc) + // return true; + + if (cd != nullptr && ct != nullptr && cdm != nullptr) { + cd->setFrameIDtoLoad(meta_data.m_frame_ID); + auto dm_meta_data = cdm->getMetaData(); + dm_meta_data.m_frame_ID = meta_data.m_frame_ID; + cdm->setMetaData(dm_meta_data); + if (!(*cd)(1)) + return false; + if (!(*ct)(1)) + return false; + if (!(*cdm)(1)) + return false; + meta_data.m_frame_cnt = cd->getFrameCount(); + + // get adios meta data + auto vars = cd->getAvailableVars(); + for (auto var : vars) { + _parameter_to_sample_slot.Param()->AddValue(var); + _vec_param_to_samplex_x.Param()->AddValue(var); + _vec_param_to_samplex_y.Param()->AddValue(var); + _vec_param_to_samplex_z.Param()->AddValue(var); + _vec_param_to_samplex_w.Param()->AddValue(var); + } + } else { + log.WriteError("[DualMeshProbeSampling] Connecting adios data and kd tree modules is required."); + return false; + } + + auto probes_meta_data = cprobes->getMetaData(); + probes_meta_data.m_frame_ID = meta_data.m_frame_ID; + cprobes->setMetaData(probes_meta_data); + if (!(*cprobes)(1)) + return false; + + // put metadata in mesh call + cp->setMetaData(meta_data); + + return true; +} + +bool DualMeshProbeSampling::getParticleMetaData(core::Call& call) { + + auto cp = dynamic_cast(&call); + if (cp == nullptr) + return false; + + auto cd = _adios_rhs_slot.CallAs(); + auto ct = _full_tree_rhs_slot.CallAs(); + auto cprobes = _probe_rhs_slot.CallAs(); + if (cprobes == nullptr) { + log.WriteError("[DualMeshProbeSampling] Connecting probes is required."); + return false; + } + + auto cdm = _mesh_rhs_slot.CallAs(); + if (cdm == nullptr) { + log.WriteError("[DualMeshProbeSampling] Connecting a dual mesh is required."); + return false; + } + + auto current_frame = cp->FrameID(); + // if (cd->getDataHash() == _old_datahash && meta_data.m_frame_ID == cd->getFrameIDtoLoad() && !_trigger_recalc) + // return true; + + if (cd != nullptr && ct != nullptr && cdm != nullptr) { + cd->setFrameIDtoLoad(current_frame); + auto dm_meta_data = cdm->getMetaData(); + dm_meta_data.m_frame_ID = current_frame; + cdm->setMetaData(dm_meta_data); + if (!(*cd)(1)) + return false; + if (!(*ct)(1)) + return false; + if (!(*cdm)(1)) + return false; + cp->SetFrameCount(cd->getFrameCount()); + + // get adios meta data + auto vars = cd->getAvailableVars(); + for (auto var : vars) { + _parameter_to_sample_slot.Param()->AddValue(var); + _vec_param_to_samplex_x.Param()->AddValue(var); + _vec_param_to_samplex_y.Param()->AddValue(var); + _vec_param_to_samplex_z.Param()->AddValue(var); + _vec_param_to_samplex_w.Param()->AddValue(var); + } + } else { + log.WriteError( + "[DualMeshProbeSampling] Connecting adios data and kd tree modules is required."); + return false; + } + + auto probes_meta_data = cprobes->getMetaData(); + probes_meta_data.m_frame_ID = current_frame; + cprobes->setMetaData(probes_meta_data); + if (!(*cprobes)(1)) + return false; + + return true; +} + +bool DualMeshProbeSampling::getParticleData(core::Call& call) { + + bool something_has_changed = false; + auto cp = dynamic_cast(&call); + if (cp == nullptr) + return false; + + // query adios data + auto cd = _adios_rhs_slot.CallAs(); + auto ct = _full_tree_rhs_slot.CallAs(); + auto cprobes = _probe_rhs_slot.CallAs(); + auto csm = _mesh_rhs_slot.CallAs(); + + + std::vector toInq; + std::string var_str = std::string(_parameter_to_sample_slot.Param()->ValueString()); + + std::string x_var_str = std::string(_vec_param_to_samplex_x.Param()->ValueString()); + std::string y_var_str = std::string(_vec_param_to_samplex_y.Param()->ValueString()); + std::string z_var_str = std::string(_vec_param_to_samplex_z.Param()->ValueString()); + std::string w_var_str = std::string(_vec_param_to_samplex_w.Param()->ValueString()); + + core::Spatial3DMetaData tree_meta_data; + core::Spatial3DMetaData probes_meta_data; + + // only for particle data + if (cd != nullptr && ct != nullptr && csm != nullptr) { + + toInq.clear(); + if (var_str != "undef") { + toInq.emplace_back( + std::string(_parameter_to_sample_slot.Param()->ValueString())); + } else { + toInq.emplace_back(std::string(_vec_param_to_samplex_x.Param()->ValueString())); + toInq.emplace_back(std::string(_vec_param_to_samplex_y.Param()->ValueString())); + toInq.emplace_back(std::string(_vec_param_to_samplex_z.Param()->ValueString())); + toInq.emplace_back(std::string(_vec_param_to_samplex_w.Param()->ValueString())); + } + + // get data from adios + for (auto var : toInq) { + if (!cd->inquireVar(var)) + return false; + } + + if (cd->getDataHash() != _old_datahash || _trigger_recalc) { + if (!(*cd)(0)) + return false; + } + + // query kd tree data + if (!(*ct)(0)) + return false; + + // query dual mesh + if (!(*csm)(0)) + return false; + + + tree_meta_data = ct->getMetaData(); + + something_has_changed = something_has_changed || (cd->getDataHash() != _old_datahash) || ct->hasUpdate(); + } else { + return false; + } + + // query probe data + if (cprobes == nullptr) + return false; + if (!(*cprobes)(0)) + return false; + + something_has_changed = something_has_changed || cprobes->hasUpdate() || _trigger_recalc; + + probes_meta_data = cprobes->getMetaData(); + _probes = cprobes->getData(); + + if (something_has_changed) { + ++_version; + + auto surface_mesh = csm->getData(); + calcDualMesh(surface_mesh); + } + + // put data into probes + + if (cd != nullptr) { + _old_datahash = cd->getDataHash(); + cp->AccessBoundingBoxes().SetObjectSpaceBBox(tree_meta_data.m_bboxs.BoundingBox()); + } + + cp->SetParticleListCount(_dual_mesh_vertices.size()); + cp->SetDataHash(_version); + for (int i = 0; i < _dual_mesh_vertices.size(); i++) { + cp->AccessParticles(i).SetCount(_dual_mesh_vertices[i].size()); + cp->AccessParticles(i).SetVertexData( + geocalls::SimpleSphericalParticles::VERTDATA_FLOAT_XYZ, _dual_mesh_vertices[i].data(), sizeof(std::array)); + } + + _trigger_recalc = false; + + + return true; +} + +bool DualMeshProbeSampling::paramChanged(core::param::ParamSlot& p) { + + _trigger_recalc = true; + return true; +} + +bool DualMeshProbeSampling::createMeshTree(std::shared_ptr mesh) { + + if (mesh->accessMeshes().size() > 1) { + log.WriteError( + "[DualMeshProbeSampling] Dual Mesh accessor too large. Please use a MeshSelector in front."); + return false; + } + + auto the_mesh = mesh->accessMeshes().begin(); + + _mesh_vertex_data.clear(); + for (auto& attr : the_mesh->second.attributes) { + if (attr.semantic == mesh::MeshDataAccessCollection::POSITION) { + int const count = attr.byte_size / attr.stride; + _mesh_vertex_data.resize(count); + auto data = reinterpret_cast(attr.data); + for (int i = 0; i < count; ++i) { + std::array const vertex = {data[3 * i + 0], data[3 * i + 1], data[3 * i + 2]}; + _mesh_vertex_data[i] = vertex; + } + } + } + + + _mesh_dataKD = std::make_shared(_mesh_vertex_data); + _mesh_tree = std::make_shared( + 3 /*dim*/, *_mesh_dataKD, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + _mesh_tree->buildIndex(); + return true; +} + +bool DualMeshProbeSampling::calcDualMesh(std::shared_ptr mesh) { + + auto cprobes = _probe_rhs_slot.CallAs(); + auto const num_probes = cprobes->getData()->getProbeCount(); + + + // should only have one mesh + if (mesh->accessMeshes().size() != 1) { + log.WriteError( + "[DualMeshProbeSampling] One mesh expected, got %d", mesh->accessMeshes().size()); + return false; + } + auto const current_mesh = mesh->accessMeshes().begin(); + + + mesh::MeshDataAccessCollection::VertexAttribute pos_attr; + for (auto& attr : current_mesh->second.attributes) { + if (attr.semantic == mesh::MeshDataAccessCollection::POSITION) { + pos_attr = attr; + } + } + + size_t float_count = float_count = (pos_attr.byte_size / pos_attr.stride); + size_t vertex_count = float_count / pos_attr.component_cnt; + auto vertex_accessor = reinterpret_cast(pos_attr.data); + + + size_t num_indices = current_mesh->second.indices.byte_size / + mesh::MeshDataAccessCollection::getByteSize(current_mesh->second.indices.type); + std::vector mesh_indices(reinterpret_cast(current_mesh->second.indices.data), + reinterpret_cast(current_mesh->second.indices.data) + num_indices); + assert(*std::max_element(mesh_indices.begin(),mesh_indices.end()) >= vertex_count); + + _dual_mesh_vertices.resize(num_probes); + for (int i = 0; i < num_probes; ++i) { + auto const current_probe = cprobes->getData()->getProbe(i); + // should only have one ID + if (current_probe.m_vert_ids.size() != 1) { + log.WriteError( + "[DualMeshProbeSampling] One vertex id expected, got %d", current_probe.m_vert_ids.size()); + return false; + } + + int const current_vert_id = current_probe.m_vert_ids[0]; + + std::vector triangles; + triangles.reserve(5); + auto b = mesh_indices.begin(), end = mesh_indices.end(); + while (b != end) { + b = std::find(b, end, current_vert_id); + if (b != end) { + unsigned int const diff = b++ - mesh_indices.begin(); + unsigned int const mod_result = diff % 3; + triangles.emplace_back(diff - mod_result); + } + } + // calc centers of triangles + _dual_mesh_vertices[i].reserve(5); + for (auto const& triangle : triangles) { + auto const t0 = 3 * mesh_indices[triangle]; + auto const t1 = 3 * mesh_indices[triangle+1]; + auto const t2 = 3 * mesh_indices[triangle+2]; + glm::vec3 const v0 = {vertex_accessor[t0 + 0], + vertex_accessor[t0 + 1], + vertex_accessor[t0 + 2]}; + glm::vec3 const v1 = {vertex_accessor[t1 + 0], + vertex_accessor[t1 + 1], + vertex_accessor[t1 + 2]}; + glm::vec3 const v2 = {vertex_accessor[t2 + 0], + vertex_accessor[t2 + 1], + vertex_accessor[t2 + 2]}; + glm::vec3 const center = (v0 + v1 + v2)/3.0f; + _dual_mesh_vertices[i].emplace_back(std::array{center.x, center.y, center.z}); + } + } + + return true; +} + +} // namespace megamol::probe diff --git a/plugins/probe/src/DualMeshProbeSampling.h b/plugins/probe/src/DualMeshProbeSampling.h new file mode 100644 index 0000000000..bfffe3df10 --- /dev/null +++ b/plugins/probe/src/DualMeshProbeSampling.h @@ -0,0 +1,487 @@ +/* + * DualMeshProbeSampling.h + * Copyright (C) 2022 by MegaMol Team + * Alle Rechte vorbehalten. + */ + + +#pragma once + +#include "mmcore/CalleeSlot.h" +#include "mmcore/CallerSlot.h" +#include "mmcore/Module.h" + +#include "geometry_calls/VolumetricDataCall.h" +#include "mmadios/CallADIOSData.h" +#include "mmcore/param/EnumParam.h" +#include "mmcore/param/FloatParam.h" +#include "mmcore/param/IntParam.h" +#include "mmcore/param/ParamSlot.h" +#include "probe/ProbeCollection.h" +#include "probe/CallKDTree.h" +#include "mesh/MeshCalls.h" + +#include "CGAL/Delaunay_triangulation_3.h" +#include "CGAL/Delaunay_triangulation_cell_base_3.h" +#include "CGAL/Exact_predicates_inexact_constructions_kernel.h" +#include "CGAL/Triangulation_vertex_base_3.h" +#include "CGAL/Triangulation_vertex_base_with_info_3.h" + +#include + +namespace megamol::probe { + +inline glm::vec3 to_vec3(std::array input) { + return glm::vec3(input[0], input[1], input[2]); +} + +inline auto log = core::utility::log::Log::DefaultLog; + +class DualMeshProbeSampling : public core::Module { +public: + /** + * Answer the name of this module. + * + * @return The name of this module. + */ + static const char* ClassName() { + return "DualMeshProbeSampling"; + } + + /** + * Answer a human readable description of this module. + * + * @return A human readable description of this module. + */ + static const char* Description() { + return "..."; + } + + /** + * Answers whether this module is available on the current system. + * + * @return 'true' if the module is available, 'false' otherwise. + */ + static bool IsAvailable(void) { + return true; + } + + DualMeshProbeSampling(); + virtual ~DualMeshProbeSampling(); + +protected: + virtual bool create(); + virtual void release(); + + uint32_t _version; + + core::CalleeSlot _probe_lhs_slot; + + core::CalleeSlot _debug_lhs_slot; + + core::CallerSlot _probe_rhs_slot; + size_t _probe_cached_hash; + + core::CallerSlot _adios_rhs_slot; + size_t _adios_cached_hash; + + core::CallerSlot _full_tree_rhs_slot; + size_t _full_tree_cached_hash; + + core::CallerSlot _mesh_rhs_slot; + + core::param::ParamSlot _parameter_to_sample_slot; + core::param::ParamSlot _num_samples_per_probe_slot; + + core::param::ParamSlot _vec_param_to_samplex_x; + core::param::ParamSlot _vec_param_to_samplex_y; + core::param::ParamSlot _vec_param_to_samplex_z; + core::param::ParamSlot _vec_param_to_samplex_w; + +private: + + template + void doScalarDistributionSampling( + const std::shared_ptr& tree, std::vector& data); + + template + void doVectorSamling(const std::shared_ptr& tree, const std::vector& data_x, + const std::vector& data_y, const std::vector& data_z, const std::vector& data_w); + + template + bool isInsideSamplingArea(float& min_radius, const std::array& _point, const std::vector>& _top, + const std::vector>& bottom, const std::array& _probe, const bool check_bottom = true, + const bool includes_probe = false); + + bool getData(core::Call& call); + + bool getMetaData(core::Call& call); + bool getParticleMetaData(core::Call& call); + bool getParticleData(core::Call& call); + + std::shared_ptr _probes; + + size_t _old_datahash; + size_t _old_volume_datahash; + bool _trigger_recalc; + bool paramChanged(core::param::ParamSlot& p); + bool createMeshTree(std::shared_ptr mesh); + bool calcDualMesh(std::shared_ptr mesh); + + std::shared_ptr _mesh_tree; + std::shared_ptr _mesh_dataKD; + std::vector> _mesh_vertex_data; + + std::vector>> _dual_mesh_vertices; + +}; + + +template +inline void DualMeshProbeSampling::doScalarDistributionSampling( + const std::shared_ptr& tree, std::vector& data) { + + const int samples_per_probe = this->_num_samples_per_probe_slot.Param()->Value(); + + T global_min = std::numeric_limits::max(); + T global_max = std::numeric_limits::lowest(); + //#pragma omp parallel for + for (int32_t i = 0; i < static_cast(_probes->getProbeCount()); i++) { + + FloatDistributionProbe probe; + + auto visitor = [&probe, i, samples_per_probe, this](auto&& arg) { + using PROBE_TYPE = std::decay_t; + if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v) { + + probe.m_timestamp = arg.m_timestamp; + probe.m_value_name = arg.m_value_name; + probe.m_position = arg.m_position; + probe.m_direction = arg.m_direction; + probe.m_begin = arg.m_begin; + probe.m_end = arg.m_end; + probe.m_orig_end = arg.m_orig_end; + probe.m_vert_ids = arg.m_vert_ids; + probe.m_geo_ids = arg.m_geo_ids; + probe.m_representant = arg.m_representant; + probe.m_cluster_id = arg.m_cluster_id; + probe.m_placement_method = arg.m_placement_method; + + _probes->setProbe(i, probe); + + } else if constexpr (std::is_same_v) { + probe = arg; + + } else { + // unknown/incompatible probe type, throw error? do nothing? + } + }; + + auto generic_probe = _probes->getGenericProbe(i); + std::visit(visitor, generic_probe); + + auto sample_step = probe.m_end / static_cast(samples_per_probe); + auto probe_end_point = glm::vec3(to_vec3(probe.m_direction) * probe.m_orig_end + to_vec3(probe.m_position)); + + std::shared_ptr samples = probe.getSamplingResult(); + + T probe_min = std::numeric_limits::max(); + T probe_max = std::numeric_limits::lowest(); + T probe_avg = 0.0; + samples->samples.resize(samples_per_probe); + auto dual_mesh_top_vertices = _dual_mesh_vertices[i]; + auto dual_mesh_bottom_vertices = _dual_mesh_vertices[i]; + for (int j = 0; j < samples_per_probe; j++) { + + std::array sample_center; + sample_center[0] = probe.m_position[0] + (j * sample_step + sample_step/2.0f) * probe.m_direction[0]; + sample_center[1] = probe.m_position[1] + (j * sample_step + sample_step/2.0f) * probe.m_direction[1]; + sample_center[2] = probe.m_position[2] + (j * sample_step + sample_step/2.0f) * probe.m_direction[2]; + + // DEBUG USE: auto sampledist_to_probe = glm::length(to_vec3(sample_center) - to_vec3(probe.m_position)); + float min_radius = std::numeric_limits::max(); + float blub = 0.0f; + float radius = sample_step/2.0f; + for (int d = 0; d < dual_mesh_top_vertices.size(); d++) { + // determine max radius of sampling geometry + auto const dist = glm::length(to_vec3(dual_mesh_top_vertices[d]) - + to_vec3(sample_center)); + radius = std::max(radius, dist); + // calculate bottom of the sampling geometry + glm::vec3 shift_dir; + if (probe.m_placement_method == BaseProbe::CENTERPOINT) { + shift_dir = probe_end_point - to_vec3(dual_mesh_top_vertices[d]); + } else if (probe.m_placement_method == BaseProbe::VERTEX_NORMAL) { + shift_dir = to_vec3(probe.m_direction); + } else { + log.WriteError("[DualMeshSampling] Probe placement method unknown or not implemented."); + return; + } + shift_dir = glm::normalize(shift_dir); + dual_mesh_bottom_vertices[d][0] += sample_step * shift_dir[0]; + dual_mesh_bottom_vertices[d][1] += sample_step * shift_dir[1]; + dual_mesh_bottom_vertices[d][2] += sample_step * shift_dir[2]; + } + + std::vector> res; + auto num_neighbors = + tree->radiusSearch(sample_center.data(), std::powf(radius,2), res, nanoflann::SearchParams()); + + if (num_neighbors == 0) { + log.WriteError("[DualMeshSampling] No samples in radius found!"); + return; + } + + bool check_bottom = true; + bool includes_probe = false; + if (j == 0 && (probe.m_placement_method == BaseProbe::CENTERPOINT || + probe.m_placement_method == BaseProbe::CENTERLINE)) { + includes_probe = true; + } + if ((j == samples_per_probe - 1) && (probe.m_placement_method == BaseProbe::CENTERPOINT || + probe.m_placement_method == BaseProbe::CENTERLINE)) { + check_bottom = false; + } + + // clac min radius + if (!isInsideSamplingArea(min_radius, sample_center, dual_mesh_top_vertices, dual_mesh_bottom_vertices, + probe.m_position, check_bottom, includes_probe)) { + log.WriteError("[DualMeshSampling] ERROR: Sample point found to be not in geometry. Check equations!"); + return; + } + + // only keep samplepoints that are within the boundaries of the dual mesh sampling geometry + std::vector> points_to_keep; + points_to_keep.reserve(res.size()); + std::vector kept_dists; + for (auto& id: res) { + std::array const point = tree->dataset.derived()[id.first]; + if (std::sqrtf(id.second) < min_radius) { + points_to_keep.emplace_back(id); + kept_dists.emplace_back(std::sqrtf(id.second)); + }else { + if (isInsideSamplingArea(blub, point, dual_mesh_top_vertices, dual_mesh_bottom_vertices, + probe.m_position, check_bottom, includes_probe)) { + points_to_keep.emplace_back(id); + kept_dists.emplace_back(std::sqrtf(id.second)); + } + } + } + points_to_keep.shrink_to_fit(); + + // accumulate values + T sample_avg = 0.0; + T sample_min = std::numeric_limits::max(); + T sample_max = std::numeric_limits::lowest(); + samples->samples[j].values.resize(points_to_keep.size()); + samples->samples[j].value_depth.resize(points_to_keep.size()); + for (int n = 0; n < points_to_keep.size(); n++) { + T const current_value = data[points_to_keep[n].first]; + sample_avg += current_value; + sample_min = std::min(sample_min, current_value); + sample_max = std::max(sample_max, current_value); + samples->samples[j].values[n] = current_value; + samples->samples[j].value_depth[n] = + glm::dot(to_vec3(probe.m_position) - to_vec3(tree->dataset.derived()[points_to_keep[n].first]), to_vec3(probe.m_direction)); + } // end points_to_keep.size() + sample_avg /= static_cast(points_to_keep.size()); + + if (!std::isfinite(sample_avg)) { + log.WriteError("[DualMeshSampling] Non-finite values detected."); + return; + } + + samples->samples[j].mean = sample_avg; + samples->samples[j].lower_bound = sample_min; + samples->samples[j].upper_bound = sample_max; + + probe_min = std::min(probe_min, sample_min); + probe_max = std::max(probe_max, sample_max); + probe_avg += sample_avg; + + dual_mesh_top_vertices = dual_mesh_bottom_vertices; + } // end num samples per probe + samples->max_value = probe_max; + samples->min_value = probe_min; + samples->average_value = probe_avg / static_cast(samples_per_probe); + + global_min = std::min(global_min, probe_min); + global_max = std::max(global_max, probe_max); + } // end for probes + _probes->setGlobalMinMax(global_min, global_max); +} + +template +inline void DualMeshProbeSampling::doVectorSamling(const std::shared_ptr& tree, + const std::vector& data_x, const std::vector& data_y, const std::vector& data_z, + const std::vector& data_w) { + + const int samples_per_probe = this->_num_samples_per_probe_slot.Param()->Value(); + + //#pragma omp parallel for + for (int32_t i = 0; i < static_cast(_probes->getProbeCount()); i++) { + + Vec4Probe probe; + + auto visitor = [&probe, i, samples_per_probe, this](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v || std::is_same_v || + std::is_same_v) { + + probe.m_timestamp = arg.m_timestamp; + probe.m_value_name = arg.m_value_name; + probe.m_position = arg.m_position; + probe.m_direction = arg.m_direction; + probe.m_begin = arg.m_begin; + probe.m_end = arg.m_end; + probe.m_cluster_id = arg.m_cluster_id; + + auto sample_step = probe.m_end / static_cast(samples_per_probe); + + _probes->setProbe(i, probe); + + } else if constexpr (std::is_same_v) { + probe = arg; + + auto sample_step = probe.m_end / static_cast(samples_per_probe); + + _probes->setProbe(i, probe); + + } else { + // unknown/incompatible probe type, throw error? do nothing? + } + }; + + auto generic_probe = _probes->getGenericProbe(i); + std::visit(visitor, generic_probe); + + auto sample_step = probe.m_end / static_cast(samples_per_probe); + auto radius = 1.0f; + + std::shared_ptr samples = probe.getSamplingResult(); + + float min_value = std::numeric_limits::max(); + float max_value = -std::numeric_limits::max(); + float avg_value = 0.0f; + samples->samples.resize(samples_per_probe); + + for (int j = 0; j < samples_per_probe; j++) { + + std::array sample_point; + sample_point[0] = probe.m_position[0] + j * sample_step * probe.m_direction[0]; + sample_point[1] = probe.m_position[1] + j * sample_step * probe.m_direction[1]; + sample_point[2] = probe.m_position[2] + j * sample_step * probe.m_direction[2]; + + std::vector> res; + + auto num_neighbors = + tree->radiusSearch(&sample_point[0], radius, res, nanoflann::SearchParams(10, 0.01f, true)); + if (num_neighbors == 0) { + std::vector ret_index(1); + std::vector out_dist_sqr(1); + nanoflann::KNNResultSet resultSet(1); + resultSet.init(ret_index.data(), out_dist_sqr.data()); + num_neighbors = tree->findNeighbors(resultSet, &sample_point[0], nanoflann::SearchParams(10)); + + res.resize(1); + res[0].first = ret_index[0]; + res[0].second = out_dist_sqr[0]; + } + + + // accumulate values + float value_x = 0, value_y = 0, value_z = 0, value_w = 0; + for (int n = 0; n < num_neighbors; n++) { + value_x += data_x[res[n].first]; + value_y += data_y[res[n].first]; + value_z += data_z[res[n].first]; + value_w += data_w[res[n].first]; + } // end num_neighbors + samples->samples[j][0] = value_x / num_neighbors; + ; + samples->samples[j][1] = value_y / num_neighbors; + ; + samples->samples[j][2] = value_z / num_neighbors; + ; + samples->samples[j][3] = value_w / num_neighbors; + ; + //min_value = std::min(min_value, value); + //max_value = std::max(max_value, value); + //avg_value += value; + } // end num samples per probe + //avg_value /= samples_per_probe; + //samples->average_value = avg_value; + //samples->max_value = max_value; + //samples->min_value = min_value; + } // end for probes +} + + +template +inline bool DualMeshProbeSampling::isInsideSamplingArea(float& min_radius, const std::array& _point, + const std::vector>& _top, + const std::vector>& bottom, const std::array& _probe, const bool check_bottom, const bool includes_probe) { + + assert(bottom.size() > 3); + assert(_top.size() > 3); + + glm::vec3 const point = to_vec3(_point); + glm::vec3 const probe = to_vec3(_probe); + std::vector> top = _top; + top.emplace_back(_top[0]); + // check bottom + if (check_bottom) { + // calculate normal + glm::vec3 const bottom_normal = glm::normalize( + glm::cross(to_vec3(bottom[2]) - to_vec3(bottom[0]), to_vec3(bottom[1]) - to_vec3(bottom[0]))); + // check direction of diff vec + auto dot = glm::dot(bottom_normal, to_vec3(bottom[0]) - point); + min_radius = std::min(min_radius, std::abs(dot)); + if (dot < 0) { + return false; + } + } + + // check sides + for (int i = 0; i < _top.size(); i++) { + glm::vec3 const side_normal = glm::normalize(glm::cross(to_vec3(bottom[i]) - to_vec3(top[i]), to_vec3(top[i + 1]) - to_vec3(top[i]))); + // check direction of diff vec + auto dot = glm::dot(to_vec3(top[i]) - point, side_normal); + min_radius = std::min(min_radius, std::abs(dot)); + if (dot < 0) { + return false; + } + } + + // check top + if (includes_probe) { + for (int i = 0; i < _top.size(); i++) { + glm::vec3 const top_normal = + glm::normalize(glm::cross(to_vec3(top[i+1]) - to_vec3(top[i]), probe - to_vec3(top[i]))); + // check direction of diff vec + auto dot = glm::dot(probe - point, top_normal); + min_radius = std::min(min_radius, std::abs(dot)); + if (dot < 0) { + return false; + } + } + } else { + // calculate normal + glm::vec3 const top_normal = glm::normalize( + glm::cross(to_vec3(top[1]) - to_vec3(top[0]), to_vec3(top[2]) - to_vec3(top[0]))); + // check direction of diff vec + auto dot = glm::dot(to_vec3(top[0]) - point, top_normal); + min_radius = std::min(min_radius, std::abs(dot)); + if (dot < 0) { + return false; + } + } + + + return true; +} + + +} // namespace megamol::probe diff --git a/plugins/probe/src/MeshSelector.cpp b/plugins/probe/src/MeshSelector.cpp index 15d6b6ed49..e483a8d567 100644 --- a/plugins/probe/src/MeshSelector.cpp +++ b/plugins/probe/src/MeshSelector.cpp @@ -234,6 +234,10 @@ bool MeshSelector::getData(core::Call& call) { } _selected_mesh = std::stoi(_meshNumberSlot.Param()->Value()); + if (_selected_mesh >= cd->getData()->accessMeshes().size()) { + core::utility::log::Log::DefaultLog.WriteError("[MeshSelector] Selected mesh out of bounds."); + return false; + } auto const selected_mesh = std::next(cd->getData()->accessMeshes().begin(), _selected_mesh); if (_splitMeshSlot.Param()->Value()) { diff --git a/plugins/probe/src/PlaceProbes.cpp b/plugins/probe/src/PlaceProbes.cpp index 54da7be669..35b3fee402 100644 --- a/plugins/probe/src/PlaceProbes.cpp +++ b/plugins/probe/src/PlaceProbes.cpp @@ -47,6 +47,7 @@ megamol::probe::PlaceProbes::PlaceProbes() this->_mesh_slot.SetCompatibleCall(); this->MakeSlotAvailable(&this->_mesh_slot); + _mesh_slot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); this->_centerline_slot.SetCompatibleCall(); this->MakeSlotAvailable(&this->_centerline_slot); @@ -166,8 +167,10 @@ bool megamol::probe::PlaceProbes::getMetaData(core::Call& call) { mesh::CallMesh* cm = this->_mesh_slot.CallAs(); mesh::CallMesh* ccl = this->_centerline_slot.CallAs(); - if (cm == nullptr) + if (cm == nullptr) { + core::utility::log::Log::DefaultLog.WriteError("[PlaceProbes] No surface mesh connected."); return false; + } // set frame id before callback auto mesh_meta_data = cm->getMetaData(); @@ -497,9 +500,14 @@ void megamol::probe::PlaceProbes::forceDirectedSampling(const mesh::MeshDataAcce } } +void megamol::probe::PlaceProbes::vertexSampling(const mesh::MeshDataAccessCollection::Mesh& mesh) { -void megamol::probe::PlaceProbes::vertexSampling(mesh::MeshDataAccessCollection::VertexAttribute& vertices) { - + mesh::MeshDataAccessCollection::VertexAttribute vertices; + for (auto& attr : mesh.attributes) { + if (attr.semantic == mesh::MeshDataAccessCollection::POSITION) { + vertices = attr; + } + } uint32_t probe_count = vertices.byte_size / vertices.stride; _probePositions.resize(probe_count); _probeVertices.resize(probe_count); @@ -507,6 +515,8 @@ void megamol::probe::PlaceProbes::vertexSampling(mesh::MeshDataAccessCollection: auto vertex_accessor = reinterpret_cast(vertices.data); auto vertex_step = vertices.stride / sizeof(float); + auto index_accessor = reinterpret_cast(mesh.indices.data); + #pragma omp parallel for for (int i = 0; i < probe_count; i++) { _probePositions[i][0] = vertex_accessor[vertex_step * i + 0]; @@ -542,7 +552,9 @@ void megamol::probe::PlaceProbes::vertexNormalSampling(mesh::MeshDataAccessColle -normal_accessor[normal_step * i + 2]}; probe.m_begin = -2.0 * _scale_probe_begin_slot.Param()->Value(); probe.m_end = 50.0; + probe.m_orig_end = probe.m_end; probe.m_cluster_id = -1; + probe.m_placement_method = BaseProbe::VERTEX_NORMAL; auto probe_idx = this->_probes->getProbeCount(); this->_probes->addProbe(std::move(probe)); @@ -603,7 +615,9 @@ void PlaceProbes::faceNormalSampling(mesh::MeshDataAccessCollection::VertexAttri probe.m_direction = {-n_c.x, -n_c.y, -n_c.z}; probe.m_begin = -2.0 * _scale_probe_begin_slot.Param()->Value(); probe.m_end = 50.0; + probe.m_orig_end = probe.m_end; probe.m_cluster_id = -1; + probe.m_placement_method = BaseProbe::FACE_NORMAL; auto probe_idx = this->_probes->getProbeCount(); this->_probes->addProbe(std::move(probe)); @@ -635,7 +649,7 @@ bool megamol::probe::PlaceProbes::placeProbes() { const float distanceIndicator = _whd[smallest_edge_index] / 20; if (this->_method_slot.Param()->Value() == 0) { - this->vertexSampling(vertices); + this->vertexSampling(_mesh->accessMeshes().begin()->second); processClipplane(); mesh::CallMesh* ccl = this->_centerline_slot.CallAs(); if (ccl == nullptr) { @@ -861,7 +875,9 @@ bool megamol::probe::PlaceProbes::placeByCenterline( auto begin = -0.1 * final_dist * _scale_probe_begin_slot.Param()->Value(); probe.m_begin = std::isfinite(begin) ? begin : 0.0f; probe.m_end = std::isfinite(final_dist) ? final_dist : 0.0f; + probe.m_orig_end = probe.m_end; probe.m_cluster_id = -1; + probe.m_placement_method = BaseProbe::CENTERLINE; if (!mesh_id.empty()) { probe.m_geo_ids.emplace_back(mesh_id); probe.m_vert_ids.emplace_back(_probeVertices[i]); @@ -888,12 +904,7 @@ bool megamol::probe::PlaceProbes::placeByCenterpoint() { auto probe_accessor = reinterpret_cast(_probePositions.data()->data()); auto probe_step = 4; - std::string mesh_id; - if (_mesh->accessMeshes().size() == 1) { - for (auto& m : _mesh->accessMeshes()) { - mesh_id = m.first; - } - } + std::string mesh_id = _mesh->accessMeshes().begin()->first; for (uint32_t i = 0; i < probe_count; i++) { BaseProbe probe; @@ -913,6 +924,7 @@ bool megamol::probe::PlaceProbes::placeByCenterpoint() { auto override_length = _override_probe_length_slot.Param() ->Value(); + probe.m_orig_end = normal_length; if (override_length > 0.0f){ normal_length = override_length; } @@ -923,6 +935,7 @@ bool megamol::probe::PlaceProbes::placeByCenterpoint() { probe.m_begin = -0.02 * normal_length * _scale_probe_begin_slot.Param()->Value(); probe.m_end = normal_length; probe.m_cluster_id = -1; + probe.m_placement_method = BaseProbe::CENTERPOINT; if (!mesh_id.empty()) { probe.m_geo_ids.emplace_back(mesh_id); probe.m_vert_ids.emplace_back(_probeVertices[i]); diff --git a/plugins/probe/src/PlaceProbes.h b/plugins/probe/src/PlaceProbes.h index 526389e7a0..2e453629fe 100644 --- a/plugins/probe/src/PlaceProbes.h +++ b/plugins/probe/src/PlaceProbes.h @@ -87,7 +87,7 @@ class PlaceProbes : public core::Module { void dartSampling(mesh::MeshDataAccessCollection::VertexAttribute& vertices, mesh::MeshDataAccessCollection::IndexData indexData, float distanceIndicator); void forceDirectedSampling(const mesh::MeshDataAccessCollection::Mesh& mesh); - void vertexSampling(mesh::MeshDataAccessCollection::VertexAttribute& vertices); + void vertexSampling(const mesh::MeshDataAccessCollection::Mesh& mesh); void vertexNormalSampling(mesh::MeshDataAccessCollection::VertexAttribute& vertices, mesh::MeshDataAccessCollection::VertexAttribute& normals, mesh::MeshDataAccessCollection::VertexAttribute& probe_ids); diff --git a/plugins/probe/src/probe.cpp b/plugins/probe/src/probe.cpp index aab4dfee38..17b09d212f 100644 --- a/plugins/probe/src/probe.cpp +++ b/plugins/probe/src/probe.cpp @@ -34,6 +34,7 @@ #include "TableToProbes.h" #include "TessellateBoundingBox.h" #include "FilterProbes.h" +#include "DualMeshProbeSampling.h" namespace megamol::probe { class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { @@ -75,6 +76,7 @@ class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPlug this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); // register calls From 3d2bef5229005c9ebccd84466c485c6a60e93694 Mon Sep 17 00:00:00 2001 From: rauts Date: Thu, 25 Aug 2022 15:48:24 +0200 Subject: [PATCH 30/47] dual mesh sampling now works for spherical data sets --- plugins/probe/src/DualMeshProbeSampling.cpp | 37 +++++++++++++++++++-- plugins/probe/src/DualMeshProbeSampling.h | 26 ++++++++++----- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/plugins/probe/src/DualMeshProbeSampling.cpp b/plugins/probe/src/DualMeshProbeSampling.cpp index a1233e6558..4f33eef3e6 100644 --- a/plugins/probe/src/DualMeshProbeSampling.cpp +++ b/plugins/probe/src/DualMeshProbeSampling.cpp @@ -580,7 +580,8 @@ bool DualMeshProbeSampling::calcDualMesh(std::shared_ptr> unsorted_dual_mesh_vertices; + std::vector dual_mesh_angles; for (auto const& triangle : triangles) { auto const t0 = 3 * mesh_indices[triangle]; auto const t1 = 3 * mesh_indices[triangle+1]; @@ -595,8 +596,40 @@ bool DualMeshProbeSampling::calcDualMesh(std::shared_ptr{center.x, center.y, center.z}); + unsorted_dual_mesh_vertices + .emplace_back(std::array{center.x, center.y, center.z}); + if (unsorted_dual_mesh_vertices.size() > 1) { + auto to_dm0 = to_vec3(unsorted_dual_mesh_vertices[0]) - to_vec3(current_probe.m_position); + auto to_dm1 = to_vec3(unsorted_dual_mesh_vertices[1]) - to_vec3(current_probe.m_position); + auto to_dmx = to_vec3(unsorted_dual_mesh_vertices.back()) - to_vec3(current_probe.m_position); + auto face_n = -1.0f*to_vec3(current_probe.m_direction); + auto n = glm::normalize(glm::cross(to_dm0, to_dmx)); + auto tangent = glm::normalize(glm::cross(face_n, to_dm0)); + + auto angle = std::atan2(glm::dot(n, glm::cross(to_dm0, to_dmx)), + glm::dot(to_dm0, to_dmx)); + if ( glm::dot(to_dmx, tangent) < 0.0f) { + angle = 2.0f*3.1415926535f - angle; + } + dual_mesh_angles.emplace_back(angle); + } + } + + std::vector index_permutation(dual_mesh_angles.size(),0); + for (int j = 0; j < index_permutation.size(); j++) { + index_permutation[j] = j; } + std::sort(index_permutation.begin(), index_permutation.end(), + [&](const int& a, const int& b) { return (dual_mesh_angles[a] < dual_mesh_angles[b]); }); + + _dual_mesh_vertices[i].resize(unsorted_dual_mesh_vertices.size()); + _dual_mesh_vertices[i][0] = unsorted_dual_mesh_vertices[0]; + for (int k = 0; k < index_permutation.size(); k++) { + _dual_mesh_vertices[i][k + 1] = unsorted_dual_mesh_vertices[index_permutation[k] + 1]; + } + + //_dual_mesh_vertices[i] = unsorted_dual_mesh_vertices; + } return true; diff --git a/plugins/probe/src/DualMeshProbeSampling.h b/plugins/probe/src/DualMeshProbeSampling.h index bfffe3df10..7d115abfa1 100644 --- a/plugins/probe/src/DualMeshProbeSampling.h +++ b/plugins/probe/src/DualMeshProbeSampling.h @@ -109,8 +109,8 @@ class DualMeshProbeSampling : public core::Module { const std::vector& data_y, const std::vector& data_z, const std::vector& data_w); template - bool isInsideSamplingArea(float& min_radius, const std::array& _point, const std::vector>& _top, - const std::vector>& bottom, const std::array& _probe, const bool check_bottom = true, + bool isInsideSamplingArea(float& min_radius, const std::array& _point, const std::vector>& _top, const std::vector>& bottom, + const std::array& _probe, const std::array& _probe_dir, const bool check_bottom = true, const bool includes_probe = false); bool getData(core::Call& call); @@ -247,7 +247,7 @@ inline void DualMeshProbeSampling::doScalarDistributionSampling( // clac min radius if (!isInsideSamplingArea(min_radius, sample_center, dual_mesh_top_vertices, dual_mesh_bottom_vertices, - probe.m_position, check_bottom, includes_probe)) { + probe.m_position, probe.m_direction, check_bottom, includes_probe)) { log.WriteError("[DualMeshSampling] ERROR: Sample point found to be not in geometry. Check equations!"); return; } @@ -263,7 +263,7 @@ inline void DualMeshProbeSampling::doScalarDistributionSampling( kept_dists.emplace_back(std::sqrtf(id.second)); }else { if (isInsideSamplingArea(blub, point, dual_mesh_top_vertices, dual_mesh_bottom_vertices, - probe.m_position, check_bottom, includes_probe)) { + probe.m_position, probe.m_direction, check_bottom, includes_probe)) { points_to_keep.emplace_back(id); kept_dists.emplace_back(std::sqrtf(id.second)); } @@ -422,7 +422,7 @@ inline void DualMeshProbeSampling::doVectorSamling(const std::shared_ptr inline bool DualMeshProbeSampling::isInsideSamplingArea(float& min_radius, const std::array& _point, const std::vector>& _top, - const std::vector>& bottom, const std::array& _probe, const bool check_bottom, const bool includes_probe) { + const std::vector>& bottom, const std::array& _probe, const std::array& _probe_dir, const bool check_bottom, const bool includes_probe) { assert(bottom.size() > 3); assert(_top.size() > 3); @@ -434,8 +434,7 @@ inline bool DualMeshProbeSampling::isInsideSamplingArea(float& min_radius, const // check bottom if (check_bottom) { // calculate normal - glm::vec3 const bottom_normal = glm::normalize( - glm::cross(to_vec3(bottom[2]) - to_vec3(bottom[0]), to_vec3(bottom[1]) - to_vec3(bottom[0]))); + glm::vec3 const bottom_normal = to_vec3(_probe_dir); // check direction of diff vec auto dot = glm::dot(bottom_normal, to_vec3(bottom[0]) - point); min_radius = std::min(min_radius, std::abs(dot)); @@ -445,6 +444,16 @@ inline bool DualMeshProbeSampling::isInsideSamplingArea(float& min_radius, const } // check sides + // DEBUG CODE + //glm::vec3 com(0.0f,0.0f,0.0f); + //for (int i = 0; i < _top.size(); i++) { + // com += to_vec3(top[i]); + //} + //com /= _top.size(); + //std::vector top_star(_top.size()); + //for (int i = 0; i < _top.size(); i++) { + // top_star[i] = to_vec3(top[i]) - com; + //} for (int i = 0; i < _top.size(); i++) { glm::vec3 const side_normal = glm::normalize(glm::cross(to_vec3(bottom[i]) - to_vec3(top[i]), to_vec3(top[i + 1]) - to_vec3(top[i]))); // check direction of diff vec @@ -469,8 +478,7 @@ inline bool DualMeshProbeSampling::isInsideSamplingArea(float& min_radius, const } } else { // calculate normal - glm::vec3 const top_normal = glm::normalize( - glm::cross(to_vec3(top[1]) - to_vec3(top[0]), to_vec3(top[2]) - to_vec3(top[0]))); + glm::vec3 const top_normal = -1.0f * to_vec3(_probe_dir); // check direction of diff vec auto dot = glm::dot(to_vec3(top[0]) - point, top_normal); min_radius = std::min(min_radius, std::abs(dot)); From bf1607d8f3b4968d132db3875ebf2c1ecd992da4 Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 28 Sep 2022 14:35:35 +0200 Subject: [PATCH 31/47] added levels to probe collection --- plugins/probe/include/probe/ProbeCollection.h | 109 +++++++++++++++--- 1 file changed, 91 insertions(+), 18 deletions(-) diff --git a/plugins/probe/include/probe/ProbeCollection.h b/plugins/probe/include/probe/ProbeCollection.h index c0b80492bd..bb050ebd23 100644 --- a/plugins/probe/include/probe/ProbeCollection.h +++ b/plugins/probe/include/probe/ProbeCollection.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace megamol { namespace probe { @@ -47,7 +48,7 @@ struct BaseProbe { /** vertex id on the original mesh the probe is placed */ std::vector m_face_vert_ids; /** saves the placement method used to create probe */ - PlacementMethod m_placement_method; + PlacementMethod m_placement_method = UNKNOWN; // virtual void probe() = 0; }; @@ -136,35 +137,45 @@ using GenericMinMax = std::variant, std::array, class ProbeCollection { public: + struct ProbeLevel { + // indices of sub_probes correspond to previous level indices + std::vector> sub_probes; + // indices of super_probes correspond to next level indices + std::vector super_probes; + std::vector probes; + int level_index = -1; + }; + ProbeCollection() = default; ~ProbeCollection() = default; template void addProbe(ProbeType const& probe) { - m_probes.push_back(probe); + lod_collection[max_level].probes.push_back(probe); } template void setProbe(size_t idx, ProbeType const& probe) { - m_probes[idx] = probe; + lod_collection[max_level].probes[idx] = probe; } template ProbeType getProbe(size_t idx) const { - return std::get(m_probes[idx]); + return std::get(lod_collection[max_level].probes[idx]); } GenericProbe getGenericProbe(size_t idx) const { - return m_probes[idx]; + return lod_collection[max_level].probes[idx]; } - const BaseProbe& getBaseProbe(size_t idx) const { - const BaseProbe& x = std::visit([](const auto& x) -> const BaseProbe& { return x; }, m_probes[idx]); + BaseProbe const& getBaseProbe(size_t idx) const { + const BaseProbe& x = std::visit([](const auto& x) -> const BaseProbe& { + return x; }, lod_collection[max_level].probes[idx]); return x; } uint32_t getProbeCount() const { - return m_probes.size(); + return lod_collection[max_level].probes.size(); } template @@ -177,35 +188,97 @@ class ProbeCollection { return std::get>(m_global_min_max); } - GenericMinMax getGenericGlobalMinMax() { + GenericMinMax getGenericGlobalMinMax() const { return m_global_min_max; } - void erase_probes(std::vector const& indicator) { - if (indicator.size() != m_probes.size()) + void eraseProbes(std::vector const& indicator) { + if (indicator.size() != lod_collection[max_level].probes.size()) return; auto const num_el = std::count_if(indicator.begin(), indicator.end(), [](auto const el) { return el == 0; }); std::vector tmp; tmp.reserve(num_el); - for (std::vector::size_type idx = 0; idx < m_probes.size(); ++idx) { + for (std::vector::size_type idx = 0; idx < lod_collection[max_level].probes.size(); ++idx) { if (indicator[idx] == 0) { - tmp.push_back(m_probes[idx]); + tmp.emplace_back(lod_collection[max_level].probes[idx]); } } - m_probes = tmp; + lod_collection[max_level].probes = tmp; } - void shuffle_probes() { + void shuffleProbes() { std::random_device rd; std::mt19937 g(rd()); - std::shuffle(m_probes.begin(), m_probes.end(), g); + std::shuffle(lod_collection[max_level].probes.begin(), lod_collection[max_level].probes.end(), g); + } + + bool setLevel(int const idx, ProbeLevel const level) { + if (idx >= lod_collection.size()) { + core::utility::log::Log::DefaultLog.WriteError("[ProbeLoDCollection] Level index too large."); + return false; + } + if (level.super_probes.empty() && level.sub_probes.empty()) { + core::utility::log::Log::DefaultLog.WriteError("[ProbeLoDCollection] Level not complete."); + return false; + } + lod_collection[idx] = level; + return true; + } + + ProbeLevel getLevel(int const idx) { + if (idx >= lod_collection.size()) { + core::utility::log::Log::DefaultLog.WriteError("[ProbeLoDCollection] Probe level does not exist."); + return ProbeLevel{}; + } + return lod_collection[idx]; } + template + ProbeType getSuperProbe(int const level, size_t const idx) const { + if (level - 1 < 0) { + core::utility::log::Log::DefaultLog.WriteError("[ProbeLoDCollection] Level for get super probe too low."); + return ProbeType(); + } + auto const super_index = lod_collection[level].super_probes[idx]; + return std::get(lod_collection[level - 1].probes[super_index]); + } + + template + std::vector getSubProbes(int const level, size_t const idx) const { + if (level + 1 >= lod_collection.size()) { + core::utility::log::Log::DefaultLog.WriteError("[ProbeLoDCollection] Level for get sub probe too high."); + return nullptr; + } + auto const sub_indices = lod_collection[level].sub_probes[idx]; + std::vector sub_probes; + sub_probes.reserve(sub_indices.size()); + for (auto const index : sub_indices) { + sub_probes.emplace_back(std::get(lod_collection[level + 1].probes[index])); + } + return sub_probes; + } + + int getNumLevels() const { + return lod_collection.size(); + } + + int getActiveLevels() { + int i = 0; + for (auto const& level : lod_collection) { + if (!level.probes.empty()) { + i++; + } + } + return i; + } + + private: - std::vector m_probes; + std::array lod_collection; + int max_level = 3; GenericMinMax m_global_min_max; -}; +}; } // namespace probe } // namespace megamol From 8a12650e873546aa51dd10a6903227913d6babd6 Mon Sep 17 00:00:00 2001 From: becherml Date: Wed, 5 Oct 2022 17:26:30 +0200 Subject: [PATCH 32/47] Fix old scalar glyph before archiving --- .../shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl | 9 +++++---- .../shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl index 12799ed065..8fd633384e 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.frag.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -57,14 +58,14 @@ void main() { float sample_0 = mesh_shader_params[draw_id].samples[sample_idx_0]; float sample_1 = mesh_shader_params[draw_id].samples[sample_idx_1]; - sampler2D tf_tx = sampler2D(mesh_shader_params[draw_id].tf_texture_handle); + sampler2D tf_tx = sampler2D(per_frame_data[0].tf_texture_handle); bool interpolate = bool(per_frame_data[0].use_interpolation); if(interpolate) { float sample_value = mix(sample_0,sample_1,lerp); - float sample_value_normalized = (sample_value - mesh_shader_params[draw_id].min_value) / (mesh_shader_params[draw_id].max_value - mesh_shader_params[draw_id].min_value); + float sample_value_normalized = (sample_value - per_frame_data[0].tf_min) / (per_frame_data[0].tf_max - per_frame_data[0].tf_min); //out_colour = fakeViridis(sample_value_normalized); out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; @@ -75,7 +76,7 @@ void main() { int sample_idx = int(round(angle_shifted * sample_cnt)); float sample_value = mesh_shader_params[draw_id].samples[sample_idx]; - float sample_value_normalized = (sample_value - mesh_shader_params[draw_id].min_value) / (mesh_shader_params[draw_id].max_value - mesh_shader_params[draw_id].min_value); + float sample_value_normalized = (sample_value - per_frame_data[0].tf_min) / (per_frame_data[0].tf_max - per_frame_data[0].tf_min); //out_colour = fakeViridis(sample_value_normalized); out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; @@ -83,7 +84,7 @@ void main() { } } - float zero_value_radius = (- mesh_shader_params[draw_id].min_value) / (mesh_shader_params[draw_id].max_value - mesh_shader_params[draw_id].min_value); + float zero_value_radius = (- per_frame_data[0].tf_min) / (per_frame_data[0].tf_max - per_frame_data[0].tf_min); if(abs(radius - zero_value_radius) < 0.005) out_colour = vec3(1.0); if(radius > 0.96 && radius < 0.98) out_colour = vec3(0.0); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl index 4240f701b1..c1a6e789db 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph.vert.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; From c31cf52668178cee1aa98c8f4561a857e7975187 Mon Sep 17 00:00:00 2001 From: becherml Date: Wed, 5 Oct 2022 17:33:00 +0200 Subject: [PATCH 33/47] New dial glyph background work in progress --- .../glyphs/base_probe_struct.inc.glsl | 12 + .../glyphs/dial_glyph_background.frag.glsl | 110 +++++ .../probe_gl/glyphs/dial_glyph_base.vert.glsl | 83 ++++ .../glyphs/per_frame_data_struct.inc.glsl | 15 + .../scalar_distribution_probe_glyph.frag.glsl | 1 + ...alar_distribution_probe_glyph_v2.vert.glsl | 1 + .../scalar_distribution_probe_struct.inc.glsl | 16 - .../glyphs/scalar_probe_glyph_v2.frag.glsl | 1 + .../glyphs/scalar_probe_glyph_v2.vert.glsl | 1 + .../glyphs/scalar_probe_struct.inc.glsl | 16 - .../glyphs/vector_probe_glyph.frag.glsl | 1 + .../glyphs/vector_probe_glyph.vert.glsl | 1 + .../glyphs/vector_probe_struct.inc.glsl | 16 - plugins/probe_gl/src/ProbeGlyphRenderer.cpp | 379 +++++++++++------- plugins/probe_gl/src/ProbeGlyphRenderer.h | 71 ++++ plugins/probe_gl/src/ProbeInteraction.cpp | 34 +- plugins/probe_gl/src/ProbeRenderer.cpp | 62 +-- 17 files changed, 576 insertions(+), 244 deletions(-) create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/base_probe_struct.inc.glsl create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/per_frame_data_struct.inc.glsl diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/base_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/base_probe_struct.inc.glsl new file mode 100644 index 0000000000..0cccf405c1 --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/base_probe_struct.inc.glsl @@ -0,0 +1,12 @@ + +struct MeshShaderParams +{ + vec4 glpyh_position; + vec4 probe_direction; + float scale; + + int probe_id; + int state; + + float padding0; +}; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl new file mode 100644 index 0000000000..6428968b6c --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl @@ -0,0 +1,110 @@ +#version 450 + +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" +#include "probe_gl/glyphs/base_probe_struct.inc.glsl" + +layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; + +layout(std430, binding = 1) readonly buffer PerFrameDataBuffer { PerFrameData[] per_frame_data; }; + +layout(location = 0) flat in int draw_id; +layout(location = 1) in vec2 uv_coords; +layout(location = 2) in vec3 pixel_vector; +layout(location = 3) in vec3 cam_vector; + +layout(location = 0) out vec4 albedo_out; +layout(location = 1) out vec3 normal_out; +layout(location = 2) out float depth_out; +layout(location = 3) out int objID_out; +layout(location = 4) out vec4 interactionData_out; + +void main() { + + if(dot(cam_vector,mesh_shader_params[draw_id].probe_direction.xyz) < 0.0 ){ + discard; + } + + vec2 pixel_coords = uv_coords * 2.0 - vec2(1.0,1.0); + float radius = length(pixel_coords); + + if(radius > 1.0){ + discard; + } + + vec2 pixel_direction = normalize(pixel_coords); + float angle = atan( + pixel_direction.x, + pixel_direction.x > 0.0 ? -pixel_direction.y : pixel_direction.y + ); + angle = pixel_coords.x < 0.0 ? angle * -1.0 + 3.14159 : angle; + float angle_normalized = 1.0 - (angle/6.283185 /*2pi*/); + + float pixel_diag_width = 1.5 * max(dFdx(uv_coords.x),dFdy(uv_coords.y)); + float line_width = max(0.02, pixel_diag_width); + + float border_circle_width = line_width; + if(mesh_shader_params[draw_id].state == 1) { + border_circle_width *= 2.0; + } + else if(mesh_shader_params[draw_id].state == 2) { + border_circle_width *= 2.0; + } + + // Glyph config + float inner_radius = 0.333; + float border_line_width = border_circle_width; + float angle_start = 0.05; + float angle_end = 0.95; + float angle_arrow_start = 0.85; + float angle_line_width = line_width / (6.283185 * radius); + + float arrow_radius = angle_normalized < angle_arrow_start ? 0.2 : 0.2 + pow(angle_normalized-angle_arrow_start,4.0) * 20.0; + float arrow_line_width = angle_normalized < angle_arrow_start ? border_line_width : border_line_width + border_line_width*(1.0-2.0*smoothstep(angle_arrow_start,angle_end,angle_normalized)); + arrow_line_width *= 0.5; + + bool radius_is_outer_border_circle = radius > (1.0 - border_line_width); + bool radius_is_plot_draw_area = (radius < (1.0 - border_line_width)) && (radius > (inner_radius + border_line_width)); + bool radius_is_inner_border_circle = (radius < (inner_radius + border_line_width)) && (radius > inner_radius); + bool radius_is_arrow = (radius < arrow_radius+arrow_line_width && radius > arrow_radius-arrow_line_width); + + if(angle_normalized < angle_start || angle_normalized > angle_end){ + discard; + } + else if(angle_normalized < angle_start+angle_line_width){ + if(!(radius_is_outer_border_circle || radius_is_inner_border_circle || radius_is_arrow) && !radius_is_plot_draw_area){ + discard; + } + } + else if(angle_normalized < angle_arrow_start){ + if(!(radius_is_outer_border_circle || radius_is_inner_border_circle || radius_is_arrow)){ + discard; + } + } + else if(angle_normalized < angle_end-angle_line_width){ + if(!(radius_is_outer_border_circle || radius_is_inner_border_circle || radius_is_arrow)){ + discard; + } + } + else{ + if(!(radius_is_outer_border_circle || radius_is_inner_border_circle || radius_is_arrow) && !radius_is_plot_draw_area){ + discard; + } + } + + vec4 out_colour = vec4(0.0,0.0,0.0,1.0); + + if(mesh_shader_params[draw_id].state == 1) { + out_colour = vec4(1.0,1.0,0.0,1.0); + } + else if(mesh_shader_params[draw_id].state == 2) { + out_colour = vec4(1.0,0.58,0.0,1.0); + } + + albedo_out = out_colour; + normal_out = vec3(0.0,0.0,1.0); + depth_out = gl_FragCoord.z; + + objID_out = mesh_shader_params[draw_id].probe_id; + interactionData_out = vec4(0.0); +} diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl new file mode 100644 index 0000000000..d7e5abca12 --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl @@ -0,0 +1,83 @@ +#version 450 + +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" +#include "probe_gl/glyphs/base_probe_struct.inc.glsl" + +layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; + +uniform mat4 view_mx; +uniform mat4 proj_mx; + +layout(location = 0) flat out int draw_id; +layout(location = 1) out vec2 uv_coords; +layout(location = 2) out vec3 pixel_vector; +layout(location = 3) out vec3 cam_vector; + +//http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ +mat4 rotationMatrix(vec3 axis, float angle) +{ + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, + 0.0, 0.0, 0.0, 1.0); +} + +void main() +{ + const vec4 vertices[6] = vec4[6]( vec4( -1.0,-1.0,0.0,0.0 ), + vec4( 1.0,1.0,1.0,1.0 ), + vec4( -1.0,1.0,0.0,1.0 ), + vec4( 1.0,1.0,1.0,1.0 ), + vec4( -1.0,-1.0,0.0,0.0 ), + vec4( 1.0,-1.0,1.0,0.0 ) ); + + draw_id = gl_DrawIDARB; + uv_coords = vertices[gl_VertexID].zw; + + vec4 glyph_pos = vec4(mesh_shader_params[gl_DrawIDARB].glpyh_position.xyz, 1.0); + vec4 clip_pos = (proj_mx * view_mx * glyph_pos); + float aspect = proj_mx[1][1] / proj_mx[0][0]; + vec2 bboard_vertex = vertices[gl_VertexID].xy; + + //// + // compute plausible glyph up vector + + vec3 glyph_up = normalize(transpose(mat3(view_mx)) * vec3(0.0,1.0,0.0)); + vec3 glyph_right= normalize(transpose(mat3(view_mx)) * vec3(1.0,0.0,0.0)); + + vec2 pixel_coords = uv_coords * 2.0 - 1.0; + pixel_vector = normalize( pixel_coords.x * glyph_right + pixel_coords.y * glyph_up ); + + // tilt glyph to be orthognal to probe direction + vec3 probe_direction = normalize( mesh_shader_params[draw_id].probe_direction.xyz ); + vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); + cam_vector = cam_front; + + float probe_dot_cam = dot(probe_direction, cam_front); + if( probe_dot_cam > 0.0 ) + { + float angle = probe_dot_cam; + vec3 axis = normalize(cross(probe_direction, cam_front)); + + mat4 rot = rotationMatrix(axis,acos(angle)); + + vec3 tilted_glyph_up = (rot * vec4(glyph_up,1.0)).xyz; + vec3 tilted_glyph_right = (rot * vec4(glyph_right,1.0)).xyz; + + float tilt_factor = (acos(probe_dot_cam) / 1.57); + tilt_factor = pow(tilt_factor,4.0); + tilt_factor = 1.0 - tilt_factor; + glyph_up = normalize(mix(tilted_glyph_up, glyph_up, tilt_factor)); + glyph_right = normalize(mix(tilted_glyph_right, glyph_right, tilt_factor)); + } + + glyph_pos.xyz = glyph_pos.xyz + (glyph_up * bboard_vertex.y * mesh_shader_params[gl_DrawIDARB].scale) + (glyph_right * bboard_vertex.x * mesh_shader_params[gl_DrawIDARB].scale); + + gl_Position = (proj_mx * view_mx * glyph_pos); +} diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/per_frame_data_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/per_frame_data_struct.inc.glsl new file mode 100644 index 0000000000..1978f2abf8 --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/per_frame_data_struct.inc.glsl @@ -0,0 +1,15 @@ +struct PerFrameData +{ + int use_interpolation; + + int show_canvas; + + int padding0; + int padding1; + + vec4 canvas_color; + + uvec2 tf_texture_handle; + float tf_min; + float tf_max; +}; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl index 152c088c0a..927c625a28 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl index 4235c25ab3..12f41fed83 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl index 771ed86a4b..913bfd8dd1 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl @@ -11,19 +11,3 @@ struct MeshShaderParams float sample_cnt; vec4 samples[32]; }; - -struct PerFrameData -{ - int use_interpolation; - - int show_canvas; - - int padding0; - int padding1; - - vec4 canvas_color; - - uvec2 tf_texture_handle; - float tf_min; - float tf_max; -}; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl index ad4ee8e035..4e8fa8624f 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl index 463898bda2..6598dbdada 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_struct.inc.glsl index e131ab13c2..07a1955e80 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_struct.inc.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_struct.inc.glsl @@ -11,19 +11,3 @@ struct MeshShaderParams int probe_id; int state; }; - -struct PerFrameData -{ - int use_interpolation; - - int show_canvas; - - int padding0; - int padding1; - - vec4 canvas_color; - - uvec2 tf_texture_handle; - float tf_min; - float tf_max; -}; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl index 878446e414..a08e53571d 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/vector_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl index f7268c4b39..154c1236ad 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl @@ -1,6 +1,7 @@ #version 450 #include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/vector_probe_struct.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_struct.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_struct.inc.glsl index 764926eb90..3ba0975daf 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_struct.inc.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_struct.inc.glsl @@ -11,19 +11,3 @@ struct MeshShaderParams float sample_cnt; vec4 samples[32]; }; - -struct PerFrameData -{ - int use_interpolation; - - int show_canvas; - - int padding0; - int padding1; - - vec4 canvas_color; - - uvec2 tf_texture_handle; - float tf_min; - float tf_max; -}; diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp index 0b9abd0059..11db5563df 100644 --- a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp @@ -104,7 +104,7 @@ void megamol::probe_gl::ProbeGlyphRenderer::createMaterialCollection() { // scalar glyph shader program material_collection_->addMaterial(this->instance(), "ScalarProbeGlyph", - {"probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl"}); + {"probe_gl/glyphs/scalar_probe_glyph.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph.frag.glsl"}); // scalar distribution glyph shader program material_collection_->addMaterial(this->instance(), "ScalarDistributionProbeGlyph", @@ -118,6 +118,10 @@ void megamol::probe_gl::ProbeGlyphRenderer::createMaterialCollection() { material_collection_->addMaterial(this->instance(), "ClusterIDProbeGlyph", {"probe_gl/glyphs/clusterID_probe_glyph.vert.glsl", "probe_gl/glyphs/clusterID_probe_glyph.frag.glsl"}); + // dial glyph background shader + material_collection_->addMaterial(this->instance(), "DialGlyphBackground", + {"probe_gl/glyphs/dial_glyph_base.vert.glsl", "probe_gl/glyphs/dial_glyph_background.frag.glsl"}); + // render to texture program material_collection_->addMaterial(this->instance(), "RenderToTexture", {"probe_gl/glyphs/renderToTexture.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl"}); @@ -189,18 +193,21 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( m_scalar_probe_glyph_identifiers.clear(); m_scalar_distribution_probe_glyph_identifiers.clear(); m_clusterID_glyph_identifiers.clear(); + m_dial_glyph_background_identifiers.clear(); m_textured_glyph_data.clear(); m_vector_probe_glyph_data.clear(); m_scalar_probe_glyph_data.clear(); m_scalar_distribution_probe_glyph_data.clear(); m_clusterID_glyph_data.clear(); + m_dial_glyph_background_data.clear(); m_textured_gylph_draw_commands.clear(); m_vector_probe_gylph_draw_commands.clear(); m_scalar_probe_gylph_draw_commands.clear(); m_scalar_distribution_probe_gylph_draw_commands.clear(); m_clusterID_gylph_draw_commands.clear(); + m_dial_glyph_background_draw_commands.clear(); m_textured_gylph_draw_commands.reserve(probe_cnt); m_textured_glyph_data.reserve(probe_cnt); @@ -217,6 +224,9 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( m_clusterID_gylph_draw_commands.reserve(probe_cnt); m_clusterID_glyph_data.reserve(probe_cnt); + m_dial_glyph_background_draw_commands.reserve(probe_cnt); + m_dial_glyph_background_data.reserve(probe_cnt); + // draw command looks the same for all billboards because geometry is reused glowl::DrawElementsCommand draw_command; draw_command.base_instance = 0; @@ -310,6 +320,14 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( } else { // unknown probe type, throw error? do nothing? } + + // for all probe types, add glyph background + auto glyph_data = createBaseProbeGlyphData(arg, probe_idx, scale); + m_dial_glyph_background_draw_commands.push_back(draw_command); + m_dial_glyph_background_data.push_back(glyph_data); + m_dial_glyph_background_identifiers.push_back( + std::string(FullName()) + "_dgbg_" + std::to_string(probe_idx)); + m_type_index_map.push_back({std::type_index(typeid(GlyphBaseProbeData)), probe_idx}); }; std::visit(visitor, generic_probe); @@ -466,63 +484,67 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_highlight_events = event_collection->get(); for (auto& evt : pending_highlight_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - per_probe_data[0].state = 1; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - per_probe_data[0].state = 1; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - per_probe_data[0].state = 1; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } + if (evt.obj_id < m_type_index_map.size()) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + per_probe_data[0].state = 1; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + per_probe_data[0].state = 1; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + per_probe_data[0].state = 1; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } - // bool my_tool_active = true; - // float my_color[4] = {0.0, 0.0, 0.0, 0.0}; - // - // // ImGui::NewFrame(); - // // Create a window called "My First Tool", with a menu bar. - // auto ctx = reinterpret_cast(this->GetCoreInstance()->GetCurrentImGuiContext()); - // if (ctx != nullptr) { - // ImGui::SetCurrentContext(ctx); - // ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar); - // if (ImGui::BeginMenuBar()) { - // if (ImGui::BeginMenu("File")) { - // if (ImGui::MenuItem("Open..", "Ctrl+O")) { /* Do stuff */ - // } - // if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Do stuff */ - // } - // if (ImGui::MenuItem("Close", "Ctrl+W")) { - // my_tool_active = false; - // } - // ImGui::EndMenu(); - // } - // ImGui::EndMenuBar(); - // } - // - // // Edit a color (stored as ~4 floats) - // ImGui::ColorEdit4("Color", my_color); - // - // // Plot some values - // const float my_values[] = {0.2f, 0.1f, 1.0f, 0.5f, 0.9f, 2.2f}; - // ImGui::PlotLines("Frame Times", my_values, IM_ARRAYSIZE(my_values)); - // - // // Display contents in a scrolling region - // ImGui::TextColored(ImVec4(1, 1, 0, 1), "Important Stuff"); - // ImGui::BeginChild("Scrolling"); - // for (int n = 0; n < 50; n++) ImGui::Text("%04d: Some text", n); - // ImGui::EndChild(); - // ImGui::End(); - // } + // bool my_tool_active = true; + // float my_color[4] = {0.0, 0.0, 0.0, 0.0}; + // + // // ImGui::NewFrame(); + // // Create a window called "My First Tool", with a menu bar. + // auto ctx = reinterpret_cast(this->GetCoreInstance()->GetCurrentImGuiContext()); + // if (ctx != nullptr) { + // ImGui::SetCurrentContext(ctx); + // ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar); + // if (ImGui::BeginMenuBar()) { + // if (ImGui::BeginMenu("File")) { + // if (ImGui::MenuItem("Open..", "Ctrl+O")) { /* Do stuff */ + // } + // if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Do stuff */ + // } + // if (ImGui::MenuItem("Close", "Ctrl+W")) { + // my_tool_active = false; + // } + // ImGui::EndMenu(); + // } + // ImGui::EndMenuBar(); + // } + // + // // Edit a color (stored as ~4 floats) + // ImGui::ColorEdit4("Color", my_color); + // + // // Plot some values + // const float my_values[] = {0.2f, 0.1f, 1.0f, 0.5f, 0.9f, 2.2f}; + // ImGui::PlotLines("Frame Times", my_values, IM_ARRAYSIZE(my_values)); + // + // // Display contents in a scrolling region + // ImGui::TextColored(ImVec4(1, 1, 0, 1), "Important Stuff"); + // ImGui::BeginChild("Scrolling"); + // for (int n = 0; n < 50; n++) ImGui::Text("%04d: Some text", n); + // ImGui::EndChild(); + // ImGui::End(); + // } + } else { + //TODO warning + } } } @@ -530,21 +552,25 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_dehighlight_events = event_collection->get(); for (auto& evt : pending_dehighlight_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (evt.obj_id < m_type_index_map.size()) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } @@ -553,24 +579,28 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_select_events = event_collection->get(); for (auto& evt : pending_select_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = 2; - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_ProbeBillboard_Scalar"; - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = 2; - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_ProbeBillboard_Vector"; - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = 2; - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_ProbeBillboard_ClusterID"; - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (evt.obj_id < m_type_index_map.size()) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = 2; + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_ProbeBillboard_Scalar"; + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = 2; + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_ProbeBillboard_Vector"; + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = 2; + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_ProbeBillboard_ClusterID"; + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } @@ -579,24 +609,28 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_deselect_events = event_collection->get(); for (auto& evt : pending_deselect_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = 0; - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = 0; - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = 0; - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (evt.obj_id < m_type_index_map.size()) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = 0; + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = 0; + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = 0; + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } @@ -606,29 +640,33 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( auto pending_events = event_collection->get(); if (!pending_events.empty()) { - for (auto& draw_data : m_scalar_probe_glyph_data) { - draw_data.state = 0; - } - for (auto& draw_data : m_vector_probe_glyph_data) { - draw_data.state = 0; - } - for (auto& draw_data : m_clusterID_glyph_data) { - draw_data.state = 0; - } + if (pending_events.back().obj_id < m_type_index_map.size()) { + for (auto& draw_data : m_scalar_probe_glyph_data) { + draw_data.state = 0; + } + for (auto& draw_data : m_vector_probe_glyph_data) { + draw_data.state = 0; + } + for (auto& draw_data : m_clusterID_glyph_data) { + draw_data.state = 0; + } - auto probe_type = m_type_index_map[pending_events.back().obj_id].first; - auto probe_idx = m_type_index_map[pending_events.back().obj_id].second; + auto probe_type = m_type_index_map[pending_events.back().obj_id].first; + auto probe_idx = m_type_index_map[pending_events.back().obj_id].second; - // multiple exclusive selections make no sense, just apply the last one - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = 2; - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = 2; - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = 2; - } + // multiple exclusive selections make no sense, just apply the last one + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = 2; + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = 2; + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = 2; + } - updateAllRenderTasks(); + updateAllRenderTasks(); + } else { + //TODO warning + } } } @@ -636,26 +674,31 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_select_events = event_collection->get(); for (auto& evt : pending_select_events) { - auto probe_type = m_type_index_map[evt.obj_id].first; - auto probe_idx = m_type_index_map[evt.obj_id].second; - - if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { - m_scalar_probe_glyph_data[probe_idx].state = - m_scalar_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; - std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { - m_vector_probe_glyph_data[probe_idx].state = - m_vector_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; - std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { - m_clusterID_glyph_data[probe_idx].state = m_clusterID_glyph_data[probe_idx].state == 2 ? 0 : 2; - std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (evt.obj_id < m_type_index_map.size()) { + auto probe_type = m_type_index_map[evt.obj_id].first; + auto probe_idx = m_type_index_map[evt.obj_id].second; + + if (probe_type == std::type_index(typeid(GlyphScalarProbeData))) { + m_scalar_probe_glyph_data[probe_idx].state = + m_scalar_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; + std::array per_probe_data = {m_scalar_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_sg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphVectorProbeData))) { + m_vector_probe_glyph_data[probe_idx].state = + m_vector_probe_glyph_data[probe_idx].state == 2 ? 0 : 2; + std::array per_probe_data = {m_vector_probe_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_vg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphClusterIDData))) { + m_clusterID_glyph_data[probe_idx].state = + m_clusterID_glyph_data[probe_idx].state == 2 ? 0 : 2; + std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } @@ -830,12 +873,14 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { std::shared_ptr scalar_distribution_shader(nullptr); std::shared_ptr vector_shader(nullptr); std::shared_ptr clusterID_shader(nullptr); + std::shared_ptr dial_background_shader(nullptr); auto textured_query = material_collection_->getMaterials().find("TexturedProbeGlyph"); auto scalar_query = material_collection_->getMaterials().find("ScalarProbeGlyph"); auto scalar_distribution_query = material_collection_->getMaterials().find("ScalarDistributionProbeGlyph"); auto vector_query = material_collection_->getMaterials().find("VectorProbeGlyph"); auto clusterID_query = material_collection_->getMaterials().find("ClusterIDProbeGlyph"); + auto dial_background_query = material_collection_->getMaterials().find("DialGlyphBackground"); if (textured_query != material_collection_->getMaterials().end()) { textured_shader = textured_query->second.shader_program; @@ -852,7 +897,9 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { if (clusterID_query != material_collection_->getMaterials().end()) { clusterID_shader = clusterID_query->second.shader_program; } - + if (dial_background_query != material_collection_->getMaterials().end()) { + dial_background_shader = dial_background_query->second.shader_program; + } if (textured_shader == nullptr) { megamol::core::utility::log::Log::DefaultLog.WriteError( @@ -879,6 +926,11 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { "Could not get ClusterIDProbeGlyph material, identifier not found. [%s, %s, line %d]\n", __FILE__, __FUNCTION__, __LINE__); } + if (dial_background_shader == nullptr) { + megamol::core::utility::log::Log::DefaultLog.WriteError( + "Could not get DialGlyphBackground material, identifier not found. [%s, %s, line %d]\n", __FILE__, + __FUNCTION__, __LINE__); + } if (!m_textured_gylph_draw_commands.empty()) { render_task_collection_->addRenderTasks(m_textured_glyph_identifiers, textured_shader, @@ -905,6 +957,12 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { render_task_collection_->addRenderTasks(m_clusterID_glyph_identifiers, clusterID_shader, m_billboard_dummy_mesh, m_clusterID_gylph_draw_commands, m_clusterID_glyph_data); } + + if (!m_dial_glyph_background_draw_commands.empty()) { + // render_task_collection_->addRenderTasks(m_dial_glyph_background_identifiers, dial_background_shader, + // m_billboard_dummy_mesh, + // m_dial_glyph_background_draw_commands, m_dial_glyph_background_data); + } return true; } @@ -925,6 +983,10 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateAllRenderTasks() { std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } else if (probe_type == std::type_index(typeid(GlyphBaseProbeData))) { + std::array per_probe_data = {m_dial_glyph_background_data[probe_idx]}; + std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(probe_idx); + // render_task_collection_->updatePerDrawData(identifier, per_probe_data); } } } @@ -1014,6 +1076,25 @@ megamol::probe_gl::ProbeGlyphRenderer::createVectorProbeGlyphData( return glyph_data; } +megamol::probe_gl::ProbeGlyphRenderer::GlyphBaseProbeData +megamol::probe_gl::ProbeGlyphRenderer::createBaseProbeGlyphData( + probe::BaseProbe const& probe, int probe_id, float scale) { + + GlyphBaseProbeData glyph_data; + + glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), + probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), + probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); + + glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); + + glyph_data.scale = scale; + + glyph_data.probe_id = probe_id; + + return glyph_data; +} + megamol::probe_gl::ProbeGlyphRenderer::GlyphClusterIDData megamol::probe_gl::ProbeGlyphRenderer::createClusterIDGlyphData( probe::BaseProbe const& probe, int probe_id, float scale) { diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.h b/plugins/probe_gl/src/ProbeGlyphRenderer.h index 2cf4908dcd..c18fe1e9fc 100644 --- a/plugins/probe_gl/src/ProbeGlyphRenderer.h +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.h @@ -164,6 +164,17 @@ class ProbeGlyphRenderer : public mesh_gl::BaseRenderTaskRenderer { int padding2; }; + struct GlyphBaseProbeData { + glm::vec4 position; + glm::vec4 probe_direction; + float scale; + + int probe_id; + int state; + + float padding0; + }; + bool m_show_glyphs; std::vector> m_type_index_map; @@ -173,18 +184,76 @@ class ProbeGlyphRenderer : public mesh_gl::BaseRenderTaskRenderer { std::vector m_scalar_probe_glyph_identifiers; std::vector m_scalar_distribution_probe_glyph_identifiers; std::vector m_clusterID_glyph_identifiers; + std::vector m_dial_glyph_background_identifiers; std::vector m_textured_glyph_data; std::vector m_vector_probe_glyph_data; std::vector m_scalar_probe_glyph_data; std::vector m_scalar_distribution_probe_glyph_data; std::vector m_clusterID_glyph_data; + std::vector m_dial_glyph_background_data; std::vector m_textured_gylph_draw_commands; std::vector m_vector_probe_gylph_draw_commands; std::vector m_scalar_probe_gylph_draw_commands; std::vector m_scalar_distribution_probe_gylph_draw_commands; std::vector m_clusterID_gylph_draw_commands; + std::vector m_dial_glyph_background_draw_commands; + + struct HierachicalScalarAIOGlyphs { + struct Glyph { + std::string boxplot_submesh; + std::string histrogram_submesh; + std::string value_arcs_submesh; + std::string scatterplot_submesh; + + glowl::DrawElementsCommand circular_grid_draw_command; + glowl::DrawElementsCommand boxplot_draw_command; + glowl::DrawElementsCommand histogram_draw_command; + glowl::DrawElementsCommand value_arcs_draw_command; + glowl::DrawElementsCommand scatterplot_draw_command; + + struct Data { + glm::vec4 position; + glm::vec4 probe_direction; + + float scale; + + int probe_id; + int state; + + float sample_cnt; + + // int sample_offset; + // int padding0; + // int padding1; + // int padding2; + }; + }; + + // Probably don't need to store sample values or depth on the GPU since everything is baked into vertices + //struct PerFrameData { + // float sample_value; + // float sample_depth; + //}; + + static constexpr char circular_grid_shader_identifier[] = "HSAIOG_CircGrid"; + static constexpr char boxplot_shader_identifier[] = "HSAIOG_Boxplot"; + static constexpr char histogram_shader_identifier[] = "HSAIOG_Histogram"; + static constexpr char value_arcs_shader_identifier[] = "HSAIOG_ValueArcs"; + static constexpr char scatterplot_shader_identifier[] = "HSAIOG_Scatterplot"; + + static constexpr char circular_grid_submesh_identifier[] = "HSAIOG_CircGrid"; + + std::vector per_frame_data; + std::vector per_glpyh_data; + std::vector glyphs; + + static void createShaders(std::shared_ptr material_collection); + + void addGlyph(probe::FloatDistributionProbe const& probe, + std::shared_ptr mesh_collection); + }; bool addAllRenderTasks(); @@ -201,6 +270,8 @@ class ProbeGlyphRenderer : public mesh_gl::BaseRenderTaskRenderer { GlyphVectorProbeData createVectorProbeGlyphData(probe::Vec4Probe const& probe, int probe_id, float scale); + GlyphBaseProbeData createBaseProbeGlyphData(probe::BaseProbe const& probe, int probe_id, float scale); + GlyphClusterIDData createClusterIDGlyphData(probe::BaseProbe const& probe, int probe_id, float scale); }; diff --git a/plugins/probe_gl/src/ProbeInteraction.cpp b/plugins/probe_gl/src/ProbeInteraction.cpp index 74f2e41660..9504247647 100644 --- a/plugins/probe_gl/src/ProbeInteraction.cpp +++ b/plugins/probe_gl/src/ProbeInteraction.cpp @@ -492,32 +492,26 @@ bool megamol::probe_gl::ProbeInteraction::Render(mmstd_gl::CallRender3DGL& call) } if (m_open_dataFilterByDepth_popup) { + ImGuiIO& io = ImGui::GetIO(); + ImVec2 viewport = ImVec2(io.DisplaySize.x, io.DisplaySize.y); - auto ctx = reinterpret_cast(this->GetCoreInstance()->GetCurrentImGuiContext()); - if (ctx != nullptr) { - ImGui::SetCurrentContext(ctx); + ImGui::SetNextWindowPos(ImVec2(750, 150)); - ImGuiIO& io = ImGui::GetIO(); - ImVec2 viewport = ImVec2(io.DisplaySize.x, io.DisplaySize.y); + ImGui::Begin("Filter By Probing Depth", &m_open_dataFilterByDepth_popup, ImGuiWindowFlags_NoResize); - ImGui::SetNextWindowPos(ImVec2(750, 150)); - - ImGui::Begin("Filter By Probing Depth", &m_open_dataFilterByDepth_popup, ImGuiWindowFlags_NoResize); - - static float probing_depth = 5.0f; - if (ImGui::SliderFloat("DataFilter::robingDepth", &probing_depth, 0.0f, 100.0f)) { - auto evt = std::make_unique( - this->GetCoreInstance()->GetFrameID(), probing_depth); - event_collection->add(std::move(evt)); - } + static float probing_depth = 5.0f; + if (ImGui::SliderFloat("DataFilter::robingDepth", &probing_depth, 0.0f, 100.0f)) { + auto evt = std::make_unique( + this->GetCoreInstance()->GetFrameID(), probing_depth); + event_collection->add(std::move(evt)); + } - //if (ImGui::Button("Close")) { + //if (ImGui::Button("Close")) { - // m_open_dataFilterByDepth_popup = false; - //} + // m_open_dataFilterByDepth_popup = false; + //} - ImGui::End(); - } + ImGui::End(); } } } diff --git a/plugins/probe_gl/src/ProbeRenderer.cpp b/plugins/probe_gl/src/ProbeRenderer.cpp index a9f498190a..56b1b022a0 100644 --- a/plugins/probe_gl/src/ProbeRenderer.cpp +++ b/plugins/probe_gl/src/ProbeRenderer.cpp @@ -82,14 +82,6 @@ void megamol::probe_gl::ProbeRenderTasks::updateRenderTaskCollection( auto probes = pc->getData(); - struct PerObjData { - glm::mat4x4 object_transform; - int highlighted; - float pad0; - float pad1; - float pad2; - }; - if (something_has_changed) { render_task_collection_->clear(); @@ -215,12 +207,16 @@ void megamol::probe_gl::ProbeRenderTasks::updateRenderTaskCollection( { auto pending_highlight_events = event_collection->get(); for (auto& evt : pending_highlight_events) { - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - per_probe_data[0].highlighted = 1; + if (evt.obj_id < m_probe_draw_data.size()) { + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + per_probe_data[0].highlighted = 1; - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } @@ -229,11 +225,15 @@ void megamol::probe_gl::ProbeRenderTasks::updateRenderTaskCollection( { auto pending_dehighlight_events = event_collection->get(); for (auto& evt : pending_dehighlight_events) { - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + if (evt.obj_id < m_probe_draw_data.size()) { + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } @@ -242,12 +242,16 @@ void megamol::probe_gl::ProbeRenderTasks::updateRenderTaskCollection( { auto pending_select_events = event_collection->get(); for (auto& evt : pending_select_events) { - m_probe_draw_data[evt.obj_id].highlighted = 2; - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + if (evt.obj_id < m_probe_draw_data.size()) { + m_probe_draw_data[evt.obj_id].highlighted = 2; + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } @@ -256,12 +260,16 @@ void megamol::probe_gl::ProbeRenderTasks::updateRenderTaskCollection( { auto pending_deselect_events = event_collection->get(); for (auto& evt : pending_deselect_events) { - m_probe_draw_data[evt.obj_id].highlighted = 0; - std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; + if (evt.obj_id < m_probe_draw_data.size()) { + m_probe_draw_data[evt.obj_id].highlighted = 0; + std::array per_probe_data = {m_probe_draw_data[evt.obj_id]}; - if (m_show_probes) { - std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); + if (m_show_probes) { + std::string identifier = std::string(FullName()) + "_probe_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + } else { + //TODO warning } } } From 7fa26c0bcc88850a36c0521eb711b8d2a894981f Mon Sep 17 00:00:00 2001 From: becherml Date: Wed, 5 Oct 2022 17:40:36 +0200 Subject: [PATCH 34/47] Fix function names --- plugins/probe/src/SampleAlongProbes.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/probe/src/SampleAlongProbes.h b/plugins/probe/src/SampleAlongProbes.h index de9ee957bf..d769648adb 100644 --- a/plugins/probe/src/SampleAlongProbes.h +++ b/plugins/probe/src/SampleAlongProbes.h @@ -598,7 +598,7 @@ void SampleAlongPobes::doTetrahedralSampling( global_max = std::max(global_max, samples->max_value); } // end for probes _probes->setGlobalMinMax(global_min, global_max); - _probes->shuffle_probes(); + _probes->shuffleProbes(); } template @@ -758,8 +758,8 @@ inline void SampleAlongPobes::doTetrahedralVectorSamling(const std::shared_ptrsetGlobalMinMax(global_min, global_max); - _probes->erase_probes(invalid_probes); - _probes->shuffle_probes(); + _probes->eraseProbes(invalid_probes); + _probes->shuffleProbes(); } From 03b86525a0ca85efefbab60708a14af252dea33c Mon Sep 17 00:00:00 2001 From: becherml Date: Thu, 6 Oct 2022 15:45:32 +0200 Subject: [PATCH 35/47] Cleaning up glyph shaders --- .../glyphs/dial_glyph_background.frag.glsl | 24 +-- .../probe_gl/glyphs/dial_glyph_base.vert.glsl | 61 ++----- .../glyphs/dial_glyph_constants.inc.glsl | 13 ++ .../glyphs/dial_glyph_utility.inc.glsl | 36 ++++ .../scalar_distribution_probe_glyph.frag.glsl | 5 - ...alar_distribution_probe_glyph_v2.vert.glsl | 110 ++---------- .../glyphs/scalar_probe_glyph_v2.frag.glsl | 25 +-- .../glyphs/scalar_probe_glyph_v2.vert.glsl | 110 ++---------- .../glyphs/scalar_probe_glyph_v3.frag.glsl | 166 ++++++++++++++++++ .../glyphs/vector_probe_glyph.frag.glsl | 20 +-- .../glyphs/vector_probe_glyph.vert.glsl | 15 +- plugins/probe_gl/src/ProbeGlyphRenderer.cpp | 27 +-- 12 files changed, 287 insertions(+), 325 deletions(-) create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl create mode 100644 plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl index 6428968b6c..a83b0f97f3 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl @@ -3,6 +3,7 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/base_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_constants.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -11,7 +12,6 @@ layout(std430, binding = 1) readonly buffer PerFrameDataBuffer { PerFrameData[] layout(location = 0) flat in int draw_id; layout(location = 1) in vec2 uv_coords; layout(location = 2) in vec3 pixel_vector; -layout(location = 3) in vec3 cam_vector; layout(location = 0) out vec4 albedo_out; layout(location = 1) out vec3 normal_out; @@ -20,11 +20,6 @@ layout(location = 3) out int objID_out; layout(location = 4) out vec4 interactionData_out; void main() { - - if(dot(cam_vector,mesh_shader_params[draw_id].probe_direction.xyz) < 0.0 ){ - discard; - } - vec2 pixel_coords = uv_coords * 2.0 - vec2(1.0,1.0); float radius = length(pixel_coords); @@ -41,25 +36,18 @@ void main() { float angle_normalized = 1.0 - (angle/6.283185 /*2pi*/); float pixel_diag_width = 1.5 * max(dFdx(uv_coords.x),dFdy(uv_coords.y)); - float line_width = max(0.02, pixel_diag_width); + float border_line_width = max(base_line_width, pixel_diag_width); - float border_circle_width = line_width; if(mesh_shader_params[draw_id].state == 1) { - border_circle_width *= 2.0; + border_line_width *= 2.0; } else if(mesh_shader_params[draw_id].state == 2) { - border_circle_width *= 2.0; + border_line_width *= 2.0; } - // Glyph config - float inner_radius = 0.333; - float border_line_width = border_circle_width; - float angle_start = 0.05; - float angle_end = 0.95; - float angle_arrow_start = 0.85; - float angle_line_width = line_width / (6.283185 * radius); + float angle_line_width = border_line_width / (6.283185 * radius); - float arrow_radius = angle_normalized < angle_arrow_start ? 0.2 : 0.2 + pow(angle_normalized-angle_arrow_start,4.0) * 20.0; + float arrow_radius = angle_normalized < angle_arrow_start ? arrow_base_radius : arrow_base_radius + pow(angle_normalized-angle_arrow_start,4.0) * 20.0; float arrow_line_width = angle_normalized < angle_arrow_start ? border_line_width : border_line_width + border_line_width*(1.0-2.0*smoothstep(angle_arrow_start,angle_end,angle_normalized)); arrow_line_width *= 0.5; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl index d7e5abca12..047bab6962 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_base.vert.glsl @@ -3,6 +3,8 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/base_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_constants.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -12,71 +14,28 @@ uniform mat4 proj_mx; layout(location = 0) flat out int draw_id; layout(location = 1) out vec2 uv_coords; layout(location = 2) out vec3 pixel_vector; -layout(location = 3) out vec3 cam_vector; - -//http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ -mat4 rotationMatrix(vec3 axis, float angle) -{ - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, - 0.0, 0.0, 0.0, 1.0); -} void main() { - const vec4 vertices[6] = vec4[6]( vec4( -1.0,-1.0,0.0,0.0 ), - vec4( 1.0,1.0,1.0,1.0 ), - vec4( -1.0,1.0,0.0,1.0 ), - vec4( 1.0,1.0,1.0,1.0 ), - vec4( -1.0,-1.0,0.0,0.0 ), - vec4( 1.0,-1.0,1.0,0.0 ) ); - draw_id = gl_DrawIDARB; uv_coords = vertices[gl_VertexID].zw; - vec4 glyph_pos = vec4(mesh_shader_params[gl_DrawIDARB].glpyh_position.xyz, 1.0); - vec4 clip_pos = (proj_mx * view_mx * glyph_pos); - float aspect = proj_mx[1][1] / proj_mx[0][0]; - vec2 bboard_vertex = vertices[gl_VertexID].xy; + vec3 probe_direction = normalize( mesh_shader_params[draw_id].probe_direction.xyz ); + vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - //// - // compute plausible glyph up vector - + // initialize glyph right and up to camera plane vec3 glyph_up = normalize(transpose(mat3(view_mx)) * vec3(0.0,1.0,0.0)); - vec3 glyph_right= normalize(transpose(mat3(view_mx)) * vec3(1.0,0.0,0.0)); + vec3 glyph_right= normalize(transpose(mat3(view_mx)) * vec3(sign(dot(probe_direction, cam_front)) * 1.0,0.0,0.0)); + // compute world space pixel vector vec2 pixel_coords = uv_coords * 2.0 - 1.0; pixel_vector = normalize( pixel_coords.x * glyph_right + pixel_coords.y * glyph_up ); // tilt glyph to be orthognal to probe direction - vec3 probe_direction = normalize( mesh_shader_params[draw_id].probe_direction.xyz ); - vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - cam_vector = cam_front; - - float probe_dot_cam = dot(probe_direction, cam_front); - if( probe_dot_cam > 0.0 ) - { - float angle = probe_dot_cam; - vec3 axis = normalize(cross(probe_direction, cam_front)); - - mat4 rot = rotationMatrix(axis,acos(angle)); - - vec3 tilted_glyph_up = (rot * vec4(glyph_up,1.0)).xyz; - vec3 tilted_glyph_right = (rot * vec4(glyph_right,1.0)).xyz; - - float tilt_factor = (acos(probe_dot_cam) / 1.57); - tilt_factor = pow(tilt_factor,4.0); - tilt_factor = 1.0 - tilt_factor; - glyph_up = normalize(mix(tilted_glyph_up, glyph_up, tilt_factor)); - glyph_right = normalize(mix(tilted_glyph_right, glyph_right, tilt_factor)); - } + tiltGlyph(glyph_right,glyph_up,probe_direction,cam_front); + vec4 glyph_pos = vec4(mesh_shader_params[gl_DrawIDARB].glpyh_position.xyz, 1.0); + vec2 bboard_vertex = vertices[gl_VertexID].xy; glyph_pos.xyz = glyph_pos.xyz + (glyph_up * bboard_vertex.y * mesh_shader_params[gl_DrawIDARB].scale) + (glyph_right * bboard_vertex.x * mesh_shader_params[gl_DrawIDARB].scale); gl_Position = (proj_mx * view_mx * glyph_pos); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl new file mode 100644 index 0000000000..33c455498e --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl @@ -0,0 +1,13 @@ +const float base_line_width = 0.02; +const float inner_radius = 0.333; +const float arrow_base_radius = 0.2; +const float angle_start = 0.05; +const float angle_end = 0.95; +const float angle_arrow_start = 0.85; + +const vec4 vertices[6] = vec4[6]( vec4( -1.0,-1.0,0.0,0.0 ), + vec4( 1.0,1.0,1.0,1.0 ), + vec4( -1.0,1.0,0.0,1.0 ), + vec4( 1.0,1.0,1.0,1.0 ), + vec4( -1.0,-1.0,0.0,0.0 ), + vec4( 1.0,-1.0,1.0,0.0 ) ); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl new file mode 100644 index 0000000000..8b09170949 --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl @@ -0,0 +1,36 @@ +bool highlightCorners(vec2 uv_coords){ + return ( (uv_coords.x > 0.99 && uv_coords.x > uv_coords.y && uv_coords.y > 0.9) || + (uv_coords.y > 0.99 && uv_coords.x < uv_coords.y && uv_coords.x > 0.9) || + (uv_coords.x < 0.01 && uv_coords.x < uv_coords.y && uv_coords.y < 0.05) || + (uv_coords.y < 0.01 && uv_coords.x > uv_coords.y && uv_coords.x < 0.05) ); +}; + +//http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ +mat4 rotationMatrix(vec3 axis, float angle) +{ + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, + 0.0, 0.0, 0.0, 1.0); +} + +void tiltGlyph(inout vec3 glyph_right, inout vec3 glyph_up, in vec3 probe_direction, in vec3 camera_front){ + float angle = acos(abs(dot(probe_direction, camera_front))); + vec3 axis = normalize(cross(probe_direction, camera_front)); + + mat4 rot = rotationMatrix(axis,angle); + + vec3 tilted_glyph_up = (rot * vec4(glyph_up,1.0)).xyz; + vec3 tilted_glyph_right = (rot * vec4(glyph_right,1.0)).xyz; + + float tilt_factor = (angle / 1.57); + tilt_factor = pow(tilt_factor,4.0); + tilt_factor = 1.0 - tilt_factor; + glyph_up = normalize(mix(tilted_glyph_up, glyph_up, tilt_factor)); + glyph_right = normalize(mix(tilted_glyph_right, glyph_right, tilt_factor)); +}; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl index 927c625a28..ec1612f335 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl @@ -11,7 +11,6 @@ layout(std430, binding = 1) readonly buffer PerFrameDataBuffer { PerFrameData[] layout(location = 0) flat in int draw_id; layout(location = 1) in vec2 uv_coords; layout(location = 2) in vec3 pixel_vector; -layout(location = 3) in vec3 cam_vector; layout(location = 0) out vec4 albedo_out; layout(location = 1) out vec3 normal_out; @@ -30,10 +29,6 @@ vec3 fakeViridis(float lerp) void main() { - if(dot(cam_vector,mesh_shader_params[draw_id].probe_direction.xyz) < 0.0 ){ - discard; - } - vec4 glyph_border_color = vec4(0.0,0.0,0.0,1.0); if(mesh_shader_params[draw_id].state == 1) { diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl index 12f41fed83..aeb8f2b082 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl @@ -3,6 +3,8 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_distribution_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_constants.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -12,121 +14,29 @@ uniform mat4 proj_mx; layout(location = 0) flat out int draw_id; layout(location = 1) out vec2 uv_coords; layout(location = 2) out vec3 pixel_vector; -layout(location = 3) out vec3 cam_vector; - -//http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ -mat4 rotationMatrix(vec3 axis, float angle) -{ - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, - 0.0, 0.0, 0.0, 1.0); -} void main() { - const vec4 vertices[6] = vec4[6]( vec4( -1.0,-1.0,0.0,0.0 ), - vec4( 1.0,1.0,1.0,1.0 ), - vec4( -1.0,1.0,0.0,1.0 ), - vec4( 1.0,1.0,1.0,1.0 ), - vec4( -1.0,-1.0,0.0,0.0 ), - vec4( 1.0,-1.0,1.0,0.0 ) ); - draw_id = gl_DrawIDARB; uv_coords = vertices[gl_VertexID].zw; - vec4 glyph_pos = vec4(mesh_shader_params[gl_DrawIDARB].glpyh_position.xyz, 1.0); - vec4 clip_pos = (proj_mx * view_mx * glyph_pos); - float aspect = proj_mx[1][1] / proj_mx[0][0]; - vec2 bboard_vertex = vertices[gl_VertexID].xy; + vec3 probe_direction = normalize( mesh_shader_params[draw_id].probe_direction.xyz ); + vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - //// - // compute plausible glyph up vector - + // initialize glyph right and up to camera plane vec3 glyph_up = normalize(transpose(mat3(view_mx)) * vec3(0.0,1.0,0.0)); - vec3 glyph_right= normalize(transpose(mat3(view_mx)) * vec3(1.0,0.0,0.0)); + vec3 glyph_right= normalize(transpose(mat3(view_mx)) * vec3(sign(dot(probe_direction, cam_front)) * 1.0,0.0,0.0)); + // compute world space pixel vector vec2 pixel_coords = uv_coords * 2.0 - 1.0; pixel_vector = normalize( pixel_coords.x * glyph_right + pixel_coords.y * glyph_up ); // tilt glyph to be orthognal to probe direction - vec3 probe_direction = normalize( mesh_shader_params[draw_id].probe_direction.xyz ); - vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - cam_vector = cam_front; - - float probe_dot_cam = dot(probe_direction, cam_front); - if( probe_dot_cam > 0.0 ) - { - float angle = probe_dot_cam; - vec3 axis = normalize(cross(probe_direction, cam_front)); - - mat4 rot = rotationMatrix(axis,acos(angle)); - - vec3 tilted_glyph_up = (rot * vec4(glyph_up,1.0)).xyz; - vec3 tilted_glyph_right = (rot * vec4(glyph_right,1.0)).xyz; - - float tilt_factor = (acos(probe_dot_cam) / 1.57); - tilt_factor = pow(tilt_factor,4.0); - tilt_factor = 1.0 - tilt_factor; - glyph_up = normalize(mix(tilted_glyph_up, glyph_up, tilt_factor)); - glyph_right = normalize(mix(tilted_glyph_right, glyph_right, tilt_factor)); - } + tiltGlyph(glyph_right,glyph_up,probe_direction,cam_front); + vec4 glyph_pos = vec4(mesh_shader_params[gl_DrawIDARB].glpyh_position.xyz, 1.0); + vec2 bboard_vertex = vertices[gl_VertexID].xy; glyph_pos.xyz = glyph_pos.xyz + (glyph_up * bboard_vertex.y * mesh_shader_params[gl_DrawIDARB].scale) + (glyph_right * bboard_vertex.x * mesh_shader_params[gl_DrawIDARB].scale); gl_Position = (proj_mx * view_mx * glyph_pos); - - { - /* - vec3 cam_right = normalize(transpose(mat3(view_mx)) * vec3(1.0,0.0,0.0)); - vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - - float cr_dot_pd = dot(cam_right,probe_direction); - float cf_dot_pd = dot(cam_front,probe_direction); - - vec3 glyph_up_0 = normalize(cross(probe_direction,cam_right)) * -sign(cf_dot_pd);; - vec3 glyph_up_1 = normalize(cross(probe_direction,cam_front)) * sign(cr_dot_pd);; - - vec3 glyph_right_0 = normalize(cross(probe_direction,glyph_up_0)); - vec3 glyph_right_1 = normalize(cross(probe_direction,glyph_up_1)); - - vec2 pixel_coords = uv_coords * 2.0 - 1.0; - - if( abs(cf_dot_pd) < 0.9 && abs(cf_dot_pd) > 0.25 ) - { - glyph_up = normalize( mix(glyph_up_0,glyph_up_1, 1.0 - (cf_dot_pd * 0.5 + 0.5) ) ); - glyph_right = normalize( mix(glyph_right_0,glyph_right_1, 1.0 - (cf_dot_pd * 0.5 + 0.5) ) ); - - //pixel_vector = pixel_coords.x * glyph_right; - //pixel_vector = vec3(1.0,0.0,1.0); - } - else if(abs(cr_dot_pd) < abs(cf_dot_pd)) - { - glyph_up = glyph_up_0; - glyph_right = glyph_right_0; - - //pixel_vector = pixel_coords.x * glyph_right_0; - //pixel_vector = vec3(1.0,0.0,1.0); - } - else - { - glyph_up = glyph_up_1; - glyph_right = glyph_right_1; - - //pixel_vector = pixel_coords.x * glyph_right_1; - //pixel_vector = vec3(1.0,0.0,1.0); - } - - pixel_vector = normalize( pixel_coords.x * glyph_right + pixel_coords.y * glyph_up ); - //pixel_vector = vec3(dot(glyph_right_0,glyph_right_1),0.0,0.0); - */ - } - - //gl_Position = clip_pos + vec4(bboard_vertex.x * mesh_shader_params[gl_DrawIDARB].scale, - // bboard_vertex.y * mesh_shader_params[gl_DrawIDARB].scale * aspect, 0.0, 0.0); } diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl index 4e8fa8624f..a83fb312b9 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl @@ -3,6 +3,7 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -11,7 +12,6 @@ layout(std430, binding = 1) readonly buffer PerFrameDataBuffer { PerFrameData[] layout(location = 0) flat in int draw_id; layout(location = 1) in vec2 uv_coords; layout(location = 2) in vec3 pixel_vector; -layout(location = 3) in vec3 cam_vector; layout(location = 0) out vec4 albedo_out; layout(location = 1) out vec3 normal_out; @@ -30,10 +30,6 @@ vec3 fakeViridis(float lerp) void main() { - if(dot(cam_vector,mesh_shader_params[draw_id].probe_direction.xyz) < 0.0 ){ - discard; - } - vec4 glyph_border_color = vec4(0.0,0.0,0.0,1.0); if(mesh_shader_params[draw_id].state == 1) { @@ -44,17 +40,14 @@ void main() { } // Highlight glyph up and glyph right directions - // if( (uv_coords.x > 0.99 && uv_coords.x > uv_coords.y && uv_coords.y > 0.9) || - // (uv_coords.y > 0.99 && uv_coords.x < uv_coords.y && uv_coords.x > 0.9) || - // (uv_coords.x < 0.01 && uv_coords.x < uv_coords.y && uv_coords.y < 0.05) || - // (uv_coords.y < 0.01 && uv_coords.x > uv_coords.y && uv_coords.x < 0.05) ) - // { - // albedo_out = glyph_border_color; - // normal_out = vec3(0.0,0.0,1.0); - // depth_out = gl_FragCoord.z; - // objID_out = mesh_shader_params[draw_id].probe_id; - // return; - // } + if(highlightCorners(uv_coords)) + { + albedo_out = glyph_border_color; + normal_out = vec3(0.0,0.0,1.0); + depth_out = gl_FragCoord.z; + objID_out = mesh_shader_params[draw_id].probe_id; + return; + } float pixel_diag_width = 1.5 * max(dFdx(uv_coords.x),dFdy(uv_coords.y)); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl index 6598dbdada..5652c80773 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl @@ -3,6 +3,8 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_constants.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -12,121 +14,29 @@ uniform mat4 proj_mx; layout(location = 0) flat out int draw_id; layout(location = 1) out vec2 uv_coords; layout(location = 2) out vec3 pixel_vector; -layout(location = 3) out vec3 cam_vector; - -//http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ -mat4 rotationMatrix(vec3 axis, float angle) -{ - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, - 0.0, 0.0, 0.0, 1.0); -} void main() { - const vec4 vertices[6] = vec4[6]( vec4( -1.0,-1.0,0.0,0.0 ), - vec4( 1.0,1.0,1.0,1.0 ), - vec4( -1.0,1.0,0.0,1.0 ), - vec4( 1.0,1.0,1.0,1.0 ), - vec4( -1.0,-1.0,0.0,0.0 ), - vec4( 1.0,-1.0,1.0,0.0 ) ); - draw_id = gl_DrawIDARB; uv_coords = vertices[gl_VertexID].zw; - vec4 glyph_pos = vec4(mesh_shader_params[gl_DrawIDARB].glpyh_position.xyz, 1.0); - vec4 clip_pos = (proj_mx * view_mx * glyph_pos); - float aspect = proj_mx[1][1] / proj_mx[0][0]; - vec2 bboard_vertex = vertices[gl_VertexID].xy; + vec3 probe_direction = normalize( mesh_shader_params[draw_id].probe_direction.xyz ); + vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - //// - // compute plausible glyph up vector - + // initialize glyph right and up to camera plane vec3 glyph_up = normalize(transpose(mat3(view_mx)) * vec3(0.0,1.0,0.0)); - vec3 glyph_right= normalize(transpose(mat3(view_mx)) * vec3(1.0,0.0,0.0)); + vec3 glyph_right= normalize(transpose(mat3(view_mx)) * vec3(sign(dot(probe_direction, cam_front)) * 1.0,0.0,0.0)); + // compute world space pixel vector vec2 pixel_coords = uv_coords * 2.0 - 1.0; pixel_vector = normalize( pixel_coords.x * glyph_right + pixel_coords.y * glyph_up ); // tilt glyph to be orthognal to probe direction - vec3 probe_direction = normalize( mesh_shader_params[draw_id].probe_direction.xyz ); - vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - cam_vector = cam_front; - - float probe_dot_cam = dot(probe_direction, cam_front); - if( probe_dot_cam > 0.0 ) - { - float angle = probe_dot_cam; - vec3 axis = normalize(cross(probe_direction, cam_front)); - - mat4 rot = rotationMatrix(axis,acos(angle)); - - vec3 tilted_glyph_up = (rot * vec4(glyph_up,1.0)).xyz; - vec3 tilted_glyph_right = (rot * vec4(glyph_right,1.0)).xyz; - - float tilt_factor = (acos(probe_dot_cam) / 1.57); - tilt_factor = pow(tilt_factor,4.0); - tilt_factor = 1.0 - tilt_factor; - glyph_up = normalize(mix(tilted_glyph_up, glyph_up, tilt_factor)); - glyph_right = normalize(mix(tilted_glyph_right, glyph_right, tilt_factor)); - } + tiltGlyph(glyph_right,glyph_up,probe_direction,cam_front); + vec4 glyph_pos = vec4(mesh_shader_params[gl_DrawIDARB].glpyh_position.xyz, 1.0); + vec2 bboard_vertex = vertices[gl_VertexID].xy; glyph_pos.xyz = glyph_pos.xyz + (glyph_up * bboard_vertex.y * mesh_shader_params[gl_DrawIDARB].scale) + (glyph_right * bboard_vertex.x * mesh_shader_params[gl_DrawIDARB].scale); gl_Position = (proj_mx * view_mx * glyph_pos); - - { - /* - vec3 cam_right = normalize(transpose(mat3(view_mx)) * vec3(1.0,0.0,0.0)); - vec3 cam_front = normalize(transpose(mat3(view_mx)) * vec3(0.0,0.0,-1.0)); - - float cr_dot_pd = dot(cam_right,probe_direction); - float cf_dot_pd = dot(cam_front,probe_direction); - - vec3 glyph_up_0 = normalize(cross(probe_direction,cam_right)) * -sign(cf_dot_pd);; - vec3 glyph_up_1 = normalize(cross(probe_direction,cam_front)) * sign(cr_dot_pd);; - - vec3 glyph_right_0 = normalize(cross(probe_direction,glyph_up_0)); - vec3 glyph_right_1 = normalize(cross(probe_direction,glyph_up_1)); - - vec2 pixel_coords = uv_coords * 2.0 - 1.0; - - if( abs(cf_dot_pd) < 0.9 && abs(cf_dot_pd) > 0.25 ) - { - glyph_up = normalize( mix(glyph_up_0,glyph_up_1, 1.0 - (cf_dot_pd * 0.5 + 0.5) ) ); - glyph_right = normalize( mix(glyph_right_0,glyph_right_1, 1.0 - (cf_dot_pd * 0.5 + 0.5) ) ); - - //pixel_vector = pixel_coords.x * glyph_right; - //pixel_vector = vec3(1.0,0.0,1.0); - } - else if(abs(cr_dot_pd) < abs(cf_dot_pd)) - { - glyph_up = glyph_up_0; - glyph_right = glyph_right_0; - - //pixel_vector = pixel_coords.x * glyph_right_0; - //pixel_vector = vec3(1.0,0.0,1.0); - } - else - { - glyph_up = glyph_up_1; - glyph_right = glyph_right_1; - - //pixel_vector = pixel_coords.x * glyph_right_1; - //pixel_vector = vec3(1.0,0.0,1.0); - } - - pixel_vector = normalize( pixel_coords.x * glyph_right + pixel_coords.y * glyph_up ); - //pixel_vector = vec3(dot(glyph_right_0,glyph_right_1),0.0,0.0); - */ - } - - //gl_Position = clip_pos + vec4(bboard_vertex.x * mesh_shader_params[gl_DrawIDARB].scale, - // bboard_vertex.y * mesh_shader_params[gl_DrawIDARB].scale * aspect, 0.0, 0.0); } diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl new file mode 100644 index 0000000000..35cd044d60 --- /dev/null +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl @@ -0,0 +1,166 @@ +#version 450 + +#include "probe_gl/glyphs/extensions.inc.glsl" +#include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" +#include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" + +layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; + +layout(std430, binding = 1) readonly buffer PerFrameDataBuffer { PerFrameData[] per_frame_data; }; + +layout(location = 0) flat in int draw_id; +layout(location = 1) in vec2 uv_coords; +layout(location = 2) in vec3 pixel_vector; +layout(location = 3) in vec3 cam_vector; + +layout(location = 0) out vec4 albedo_out; +layout(location = 1) out vec3 normal_out; +layout(location = 2) out float depth_out; +layout(location = 3) out int objID_out; +layout(location = 4) out vec4 interactionData_out; + +vec3 fakeViridis(float lerp) +{ + vec3 c0 = vec3(0.2823645529290169,0.0,0.3310101940118055); + vec3 c1 = vec3(0.24090172204161298,0.7633448774061599,0.42216355577803744); + vec3 c2 = vec3(0.9529994532916154,0.9125452328290099,0.11085876909361342); + + return lerp < 0.5 ? mix(c0,c1,lerp * 2.0) : mix(c1,c2,(lerp*2.0)-1.0); +}; + +void main() { + + if(dot(cam_vector,mesh_shader_params[draw_id].probe_direction.xyz) < 0.0 ){ + discard; + } + + vec4 glyph_border_color = vec4(0.0,0.0,0.0,1.0); + + if(mesh_shader_params[draw_id].state == 1) { + glyph_border_color = vec4(1.0,1.0,0.0,1.0); + } + else if(mesh_shader_params[draw_id].state == 2) { + glyph_border_color = vec4(1.0,0.58,0.0,1.0); + } + + // Highlight glyph up and glyph right directions + if(highlightCorners(uv_coords)) + { + albedo_out = glyph_border_color; + normal_out = vec3(0.0,0.0,1.0); + depth_out = gl_FragCoord.z; + objID_out = mesh_shader_params[draw_id].probe_id; + return; + } + + float pixel_diag_width = 1.5 * max(dFdx(uv_coords.x),dFdy(uv_coords.y)); + + vec2 pixel_coords = uv_coords * 2.0 - vec2(1.0,1.0); + float radius = length(pixel_coords); + + if(radius > 1.0) discard; + + float border_circle_width = 0.04; + if(mesh_shader_params[draw_id].state == 1) { + border_circle_width = 0.08; + } + else if(mesh_shader_params[draw_id].state == 2) { + border_circle_width = 0.08; + } + border_circle_width = 2.0 * max(border_circle_width,pixel_diag_width); + + float angle = atan( + pixel_coords.x, + pixel_coords.x > 0.0 ? -pixel_coords.y : pixel_coords.y + ); + + if(pixel_coords.x < 0.0){ + angle = angle * -1.0 + 3.14159; + } + + float angle_normalized = angle / (3.14159*2.0); + angle_normalized = 1.0 - angle_normalized; // invert for clockwise reading + + vec3 out_colour = vec3(0.0,0.0,0.0); + + float min_value = per_frame_data[0].tf_min; + float max_value = per_frame_data[0].tf_max; + float value_range = max_value - min_value; + + float zero_value_radius = -min_value / value_range; + float zero_arc_width = max(0.005, 0.5 * pixel_diag_width); + + if(angle_normalized > 0.025 && angle_normalized < 0.975 && (radius > zero_value_radius+zero_arc_width || radius < zero_value_radius-zero_arc_width) ) + { + float angle_shifted = (angle_normalized - 0.025) / 0.95; + + int sample_cnt = int(mesh_shader_params[draw_id].sample_cnt); + int sample_idx_0 = int(floor(angle_shifted * sample_cnt)); + int sample_idx_1 = int(ceil(angle_shifted * sample_cnt)); + float lerp = fract(angle_shifted * sample_cnt); + + float sample_0 = mesh_shader_params[draw_id].samples[sample_idx_0]; + float sample_1 = mesh_shader_params[draw_id].samples[sample_idx_1]; + + if( isnan(sample_0) || isnan(sample_1)) discard; + + sampler2D tf_tx = sampler2D(per_frame_data[0].tf_texture_handle); + + bool interpolate = bool(per_frame_data[0].use_interpolation); + + float sample_value_normalized = 0.0; + + if(interpolate) + { + float sample_value = mix(sample_0,sample_1,lerp); + sample_value_normalized = (sample_value - min_value) / (value_range); + //out_colour = fakeViridis(sample_value_normalized); + //out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; + //if( radius > sample_value_normalized && radius < border_circle_width ) discard; + } + else + { + int sample_idx = int(round(angle_shifted * sample_cnt)); + float sample_value = mesh_shader_params[draw_id].samples[sample_idx]; + sample_value_normalized = (sample_value - min_value) / (value_range); + //out_colour = fakeViridis(sample_value_normalized); + //out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; + //if( radius > sample_value_normalized && radius < border_circle_width ) discard; + } + + out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; + + if( sample_value_normalized >= zero_value_radius && radius < (1.0 - border_circle_width)){ + if( radius < (zero_value_radius) || radius > sample_value_normalized ){ + if(bool(per_frame_data[0].show_canvas)){ + out_colour = per_frame_data[0].canvas_color.rgb; + } + else{ + discard; + } + } + } + else if(sample_value_normalized < zero_value_radius && radius < (1.0 - border_circle_width)){ + if( radius > (zero_value_radius) || radius < sample_value_normalized ){ + if(bool(per_frame_data[0].show_canvas)){ + out_colour = per_frame_data[0].canvas_color.rgb; + } + else{ + discard; + } + } + } + + } + + if(abs(radius - zero_value_radius) < zero_arc_width) out_colour = vec3(1.0); + if(radius > (1.0 - border_circle_width) && radius < (1.0 - (0.5*border_circle_width) )) out_colour = glyph_border_color.rgb; + + albedo_out = vec4(out_colour,1.0); + normal_out = vec3(0.0,0.0,1.0); + depth_out = gl_FragCoord.z; + + objID_out = mesh_shader_params[draw_id].probe_id; + interactionData_out = vec4(0.0); +} diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl index a08e53571d..6c9b71d691 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl @@ -3,6 +3,7 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/vector_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -53,17 +54,14 @@ void main() { } // Highlight glyph up and glyph right directions - // if( (uv_coords.x > 0.99 && uv_coords.x > uv_coords.y && uv_coords.y > 0.9) || - // (uv_coords.y > 0.99 && uv_coords.x < uv_coords.y && uv_coords.x > 0.9) || - // (uv_coords.x < 0.01 && uv_coords.x < uv_coords.y && uv_coords.y < 0.05) || - // (uv_coords.y < 0.01 && uv_coords.x > uv_coords.y && uv_coords.x < 0.05) ) - // { - // albedo_out = glyph_border_color; - // normal_out = vec3(0.0,0.0,1.0); - // depth_out = gl_FragCoord.z; - // objID_out = mesh_shader_params[draw_id].probe_id; - // return; - // } + if(highlightCorners(uv_coords)) + { + albedo_out = glyph_border_color; + normal_out = vec3(0.0,0.0,1.0); + depth_out = gl_FragCoord.z; + objID_out = mesh_shader_params[draw_id].probe_id; + return; + } float r = length(uv_coords - vec2(0.5)) * 2.0; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl index 154c1236ad..ee988dc400 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.vert.glsl @@ -3,6 +3,7 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/vector_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -14,20 +15,6 @@ layout(location = 1) out vec2 uv_coords; layout(location = 2) out vec3 pixel_vector; layout(location = 3) out vec3 cam_vector; -//http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ -mat4 rotationMatrix(vec3 axis, float angle) -{ - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, - 0.0, 0.0, 0.0, 1.0); -} - void main() { const vec4 vertices[6] = vec4[6]( vec4( -1.0,-1.0,0.0,0.0 ), diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp index 11db5563df..6ae38e1fed 100644 --- a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp @@ -104,7 +104,7 @@ void megamol::probe_gl::ProbeGlyphRenderer::createMaterialCollection() { // scalar glyph shader program material_collection_->addMaterial(this->instance(), "ScalarProbeGlyph", - {"probe_gl/glyphs/scalar_probe_glyph.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph.frag.glsl"}); + {"probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl"}); // scalar distribution glyph shader program material_collection_->addMaterial(this->instance(), "ScalarDistributionProbeGlyph", @@ -932,25 +932,32 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { __FUNCTION__, __LINE__); } + auto set_gl_state = []() { + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + }; + if (!m_textured_gylph_draw_commands.empty()) { render_task_collection_->addRenderTasks(m_textured_glyph_identifiers, textured_shader, m_billboard_dummy_mesh, m_textured_gylph_draw_commands, m_textured_glyph_data); } if (!m_scalar_probe_glyph_data.empty()) { - render_task_collection_->addRenderTasks(m_scalar_probe_glyph_identifiers, scalar_shader, - m_billboard_dummy_mesh, m_scalar_probe_gylph_draw_commands, m_scalar_probe_glyph_data); + render_task_collection_->addRenderTasks(m_scalar_probe_glyph_identifiers, scalar_shader, m_billboard_dummy_mesh, + m_scalar_probe_gylph_draw_commands, m_scalar_probe_glyph_data, set_gl_state); } if (!m_scalar_distribution_probe_glyph_data.empty()) { render_task_collection_->addRenderTasks(m_scalar_distribution_probe_glyph_identifiers, scalar_distribution_shader, m_billboard_dummy_mesh, m_scalar_distribution_probe_gylph_draw_commands, - m_scalar_distribution_probe_glyph_data); + m_scalar_distribution_probe_glyph_data, set_gl_state); } if (!m_vector_probe_glyph_data.empty()) { - render_task_collection_->addRenderTasks(m_vector_probe_glyph_identifiers, vector_shader, - m_billboard_dummy_mesh, m_vector_probe_gylph_draw_commands, m_vector_probe_glyph_data); + render_task_collection_->addRenderTasks(m_vector_probe_glyph_identifiers, vector_shader, m_billboard_dummy_mesh, + m_vector_probe_gylph_draw_commands, m_vector_probe_glyph_data, set_gl_state); } if (!m_clusterID_gylph_draw_commands.empty()) { @@ -959,9 +966,9 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { } if (!m_dial_glyph_background_draw_commands.empty()) { - // render_task_collection_->addRenderTasks(m_dial_glyph_background_identifiers, dial_background_shader, - // m_billboard_dummy_mesh, - // m_dial_glyph_background_draw_commands, m_dial_glyph_background_data); + render_task_collection_->addRenderTasks(m_dial_glyph_background_identifiers, dial_background_shader, + m_billboard_dummy_mesh, + m_dial_glyph_background_draw_commands, m_dial_glyph_background_data, set_gl_state); } return true; } @@ -986,7 +993,7 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateAllRenderTasks() { } else if (probe_type == std::type_index(typeid(GlyphBaseProbeData))) { std::array per_probe_data = {m_dial_glyph_background_data[probe_idx]}; std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(probe_idx); - // render_task_collection_->updatePerDrawData(identifier, per_probe_data); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); } } } From b5583a94a99288cf6a085daaa857e05c75b4f7c1 Mon Sep 17 00:00:00 2001 From: becherml Date: Thu, 6 Oct 2022 19:12:34 +0200 Subject: [PATCH 36/47] Add new scaler glpyh shader --- .../glyphs/dial_glyph_background.frag.glsl | 21 ++-- .../glyphs/dial_glyph_constants.inc.glsl | 2 + .../glyphs/dial_glyph_utility.inc.glsl | 20 +++ .../scalar_distribution_probe_glyph.frag.glsl | 9 -- .../glyphs/scalar_probe_glyph_v2.frag.glsl | 9 -- .../glyphs/scalar_probe_glyph_v3.frag.glsl | 94 ++++---------- .../glyphs/vector_probe_glyph.frag.glsl | 9 -- plugins/probe_gl/src/ProbeGlyphRenderer.cpp | 116 +++++++++++++----- 8 files changed, 140 insertions(+), 140 deletions(-) diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl index a83b0f97f3..54a8bf696f 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_background.frag.glsl @@ -4,6 +4,7 @@ #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/base_probe_struct.inc.glsl" #include "probe_gl/glyphs/dial_glyph_constants.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -27,13 +28,17 @@ void main() { discard; } - vec2 pixel_direction = normalize(pixel_coords); - float angle = atan( - pixel_direction.x, - pixel_direction.x > 0.0 ? -pixel_direction.y : pixel_direction.y - ); - angle = pixel_coords.x < 0.0 ? angle * -1.0 + 3.14159 : angle; - float angle_normalized = 1.0 - (angle/6.283185 /*2pi*/); + // Highlight glyph up and glyph right directions + if(highlightCorners(uv_coords)) + { + albedo_out = glyph_border_color; + normal_out = vec3(0.0,0.0,1.0); + depth_out = gl_FragCoord.z; + objID_out = mesh_shader_params[draw_id].probe_id; + return; + } + + float angle_normalized = computeNormalizedAngle(uv_coords); float pixel_diag_width = 1.5 * max(dFdx(uv_coords.x),dFdy(uv_coords.y)); float border_line_width = max(base_line_width, pixel_diag_width); @@ -80,7 +85,7 @@ void main() { } } - vec4 out_colour = vec4(0.0,0.0,0.0,1.0); + vec4 out_colour = glyph_border_color; if(mesh_shader_params[draw_id].state == 1) { out_colour = vec4(1.0,1.0,0.0,1.0); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl index 33c455498e..972bae947f 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_constants.inc.glsl @@ -1,3 +1,5 @@ +const vec4 glyph_border_color = vec4(0.0,0.0,0.0,1.0); + const float base_line_width = 0.02; const float inner_radius = 0.333; const float arrow_base_radius = 0.2; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl index 8b09170949..2cfdecf908 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/dial_glyph_utility.inc.glsl @@ -34,3 +34,23 @@ void tiltGlyph(inout vec3 glyph_right, inout vec3 glyph_up, in vec3 probe_direct glyph_up = normalize(mix(tilted_glyph_up, glyph_up, tilt_factor)); glyph_right = normalize(mix(tilted_glyph_right, glyph_right, tilt_factor)); }; + +vec3 fakeViridis(float lerp) +{ + vec3 c0 = vec3(0.2823645529290169,0.0,0.3310101940118055); + vec3 c1 = vec3(0.24090172204161298,0.7633448774061599,0.42216355577803744); + vec3 c2 = vec3(0.9529994532916154,0.9125452328290099,0.11085876909361342); + + return lerp < 0.5 ? mix(c0,c1,lerp * 2.0) : mix(c1,c2,(lerp*2.0)-1.0); +}; + +// Compute clockwise angle of polar coordinates starting at south normalized to [0,1] +float computeNormalizedAngle(vec2 uv_coords){ + vec2 pixel_direction = normalize(uv_coords * 2.0 - vec2(1.0,1.0)); + float angle = atan( + pixel_direction.x, + pixel_direction.x > 0.0 ? -pixel_direction.y : pixel_direction.y + ); + angle = pixel_direction.x < 0.0 ? angle * -1.0 + 3.14159 : angle; + return (1.0 - (angle / 6.283185 /*2pi*/)); +}; diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl index ec1612f335..fde0351702 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl @@ -18,15 +18,6 @@ layout(location = 2) out float depth_out; layout(location = 3) out int objID_out; layout(location = 4) out vec4 interactionData_out; -vec3 fakeViridis(float lerp) -{ - vec3 c0 = vec3(0.2823645529290169,0.0,0.3310101940118055); - vec3 c1 = vec3(0.24090172204161298,0.7633448774061599,0.42216355577803744); - vec3 c2 = vec3(0.9529994532916154,0.9125452328290099,0.11085876909361342); - - return lerp < 0.5 ? mix(c0,c1,lerp * 2.0) : mix(c1,c2,(lerp*2.0)-1.0); -}; - void main() { vec4 glyph_border_color = vec4(0.0,0.0,0.0,1.0); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl index a83fb312b9..1c1363bd84 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl @@ -19,15 +19,6 @@ layout(location = 2) out float depth_out; layout(location = 3) out int objID_out; layout(location = 4) out vec4 interactionData_out; -vec3 fakeViridis(float lerp) -{ - vec3 c0 = vec3(0.2823645529290169,0.0,0.3310101940118055); - vec3 c1 = vec3(0.24090172204161298,0.7633448774061599,0.42216355577803744); - vec3 c2 = vec3(0.9529994532916154,0.9125452328290099,0.11085876909361342); - - return lerp < 0.5 ? mix(c0,c1,lerp * 2.0) : mix(c1,c2,(lerp*2.0)-1.0); -}; - void main() { vec4 glyph_border_color = vec4(0.0,0.0,0.0,1.0); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl index 35cd044d60..cc12045dcd 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl @@ -3,6 +3,7 @@ #include "probe_gl/glyphs/extensions.inc.glsl" #include "probe_gl/glyphs/per_frame_data_struct.inc.glsl" #include "probe_gl/glyphs/scalar_probe_struct.inc.glsl" +#include "probe_gl/glyphs/dial_glyph_constants.inc.glsl" #include "probe_gl/glyphs/dial_glyph_utility.inc.glsl" layout(std430, binding = 0) readonly buffer MeshShaderParamsBuffer { MeshShaderParams[] mesh_shader_params; }; @@ -12,7 +13,6 @@ layout(std430, binding = 1) readonly buffer PerFrameDataBuffer { PerFrameData[] layout(location = 0) flat in int draw_id; layout(location = 1) in vec2 uv_coords; layout(location = 2) in vec3 pixel_vector; -layout(location = 3) in vec3 cam_vector; layout(location = 0) out vec4 albedo_out; layout(location = 1) out vec3 normal_out; @@ -20,40 +20,8 @@ layout(location = 2) out float depth_out; layout(location = 3) out int objID_out; layout(location = 4) out vec4 interactionData_out; -vec3 fakeViridis(float lerp) -{ - vec3 c0 = vec3(0.2823645529290169,0.0,0.3310101940118055); - vec3 c1 = vec3(0.24090172204161298,0.7633448774061599,0.42216355577803744); - vec3 c2 = vec3(0.9529994532916154,0.9125452328290099,0.11085876909361342); - - return lerp < 0.5 ? mix(c0,c1,lerp * 2.0) : mix(c1,c2,(lerp*2.0)-1.0); -}; - void main() { - if(dot(cam_vector,mesh_shader_params[draw_id].probe_direction.xyz) < 0.0 ){ - discard; - } - - vec4 glyph_border_color = vec4(0.0,0.0,0.0,1.0); - - if(mesh_shader_params[draw_id].state == 1) { - glyph_border_color = vec4(1.0,1.0,0.0,1.0); - } - else if(mesh_shader_params[draw_id].state == 2) { - glyph_border_color = vec4(1.0,0.58,0.0,1.0); - } - - // Highlight glyph up and glyph right directions - if(highlightCorners(uv_coords)) - { - albedo_out = glyph_border_color; - normal_out = vec3(0.0,0.0,1.0); - depth_out = gl_FragCoord.z; - objID_out = mesh_shader_params[draw_id].probe_id; - return; - } - float pixel_diag_width = 1.5 * max(dFdx(uv_coords.x),dFdy(uv_coords.y)); vec2 pixel_coords = uv_coords * 2.0 - vec2(1.0,1.0); @@ -70,17 +38,7 @@ void main() { } border_circle_width = 2.0 * max(border_circle_width,pixel_diag_width); - float angle = atan( - pixel_coords.x, - pixel_coords.x > 0.0 ? -pixel_coords.y : pixel_coords.y - ); - - if(pixel_coords.x < 0.0){ - angle = angle * -1.0 + 3.14159; - } - - float angle_normalized = angle / (3.14159*2.0); - angle_normalized = 1.0 - angle_normalized; // invert for clockwise reading + float angle_normalized = computeNormalizedAngle(uv_coords); vec3 out_colour = vec3(0.0,0.0,0.0); @@ -88,12 +46,13 @@ void main() { float max_value = per_frame_data[0].tf_max; float value_range = max_value - min_value; - float zero_value_radius = -min_value / value_range; - float zero_arc_width = max(0.005, 0.5 * pixel_diag_width); - - if(angle_normalized > 0.025 && angle_normalized < 0.975 && (radius > zero_value_radius+zero_arc_width || radius < zero_value_radius-zero_arc_width) ) + if(angle_normalized > angle_start && angle_normalized < angle_end && radius > (inner_radius+base_line_width) && radius < (1.0 - base_line_width)) { - float angle_shifted = (angle_normalized - 0.025) / 0.95; + float angle_shifted = (angle_normalized - angle_start) / (angle_end-angle_start); + float radius_shifted = (radius - (inner_radius+base_line_width)) / (1.0 - base_line_width - (inner_radius+base_line_width)); + + float zero_value_radius = -min_value / value_range; + float zero_arc_width = max(0.005, 0.5 * pixel_diag_width); int sample_cnt = int(mesh_shader_params[draw_id].sample_cnt); int sample_idx_0 = int(floor(angle_shifted * sample_cnt)); @@ -115,47 +74,36 @@ void main() { { float sample_value = mix(sample_0,sample_1,lerp); sample_value_normalized = (sample_value - min_value) / (value_range); - //out_colour = fakeViridis(sample_value_normalized); - //out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; - //if( radius > sample_value_normalized && radius < border_circle_width ) discard; } else { int sample_idx = int(round(angle_shifted * sample_cnt)); float sample_value = mesh_shader_params[draw_id].samples[sample_idx]; sample_value_normalized = (sample_value - min_value) / (value_range); - //out_colour = fakeViridis(sample_value_normalized); - //out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; - //if( radius > sample_value_normalized && radius < border_circle_width ) discard; } out_colour = texture(tf_tx, vec2(sample_value_normalized, 1.0) ).rgb; - if( sample_value_normalized >= zero_value_radius && radius < (1.0 - border_circle_width)){ - if( radius < (zero_value_radius) || radius > sample_value_normalized ){ - if(bool(per_frame_data[0].show_canvas)){ - out_colour = per_frame_data[0].canvas_color.rgb; - } - else{ - discard; - } + if( sample_value_normalized >= zero_value_radius){ + if( radius_shifted < (zero_value_radius) || ( radius_shifted > sample_value_normalized && radius_shifted < (1.0 - 2.0*base_line_width) ) ){ + discard; } } - else if(sample_value_normalized < zero_value_radius && radius < (1.0 - border_circle_width)){ - if( radius > (zero_value_radius) || radius < sample_value_normalized ){ - if(bool(per_frame_data[0].show_canvas)){ - out_colour = per_frame_data[0].canvas_color.rgb; - } - else{ - discard; - } + else if(sample_value_normalized < zero_value_radius){ + if( (radius_shifted > (zero_value_radius) && radius_shifted < (1.0 - 2.0*base_line_width)) || radius_shifted < sample_value_normalized ){ + discard; } } + if(abs(radius_shifted - zero_value_radius) < zero_arc_width) out_colour = vec3(1.0); } + else{ + discard; + } + + - if(abs(radius - zero_value_radius) < zero_arc_width) out_colour = vec3(1.0); - if(radius > (1.0 - border_circle_width) && radius < (1.0 - (0.5*border_circle_width) )) out_colour = glyph_border_color.rgb; + //if(radius > (1.0 - border_circle_width) && radius < (1.0 - (0.5*border_circle_width) )) out_colour = glyph_border_color.rgb; albedo_out = vec4(out_colour,1.0); normal_out = vec3(0.0,0.0,1.0); diff --git a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl index 6c9b71d691..4cbabd3053 100644 --- a/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl +++ b/plugins/probe_gl/shaders/probe_gl/glyphs/vector_probe_glyph.frag.glsl @@ -24,15 +24,6 @@ layout(location = 4) out vec4 interactionData_out; #define PI 3.1415926 -vec3 fakeViridis(float lerp) -{ - vec3 c0 = vec3(0.2823645529290169,0.0,0.3310101940118055); - vec3 c1 = vec3(0.24090172204161298,0.7633448774061599,0.42216355577803744); - vec3 c2 = vec3(0.9529994532916154,0.9125452328290099,0.11085876909361342); - - return lerp < 0.5 ? mix(c0,c1,lerp * 2.0) : mix(c1,c2,(lerp*2.0)-1.0); -}; - vec3 projectOntoPlane(vec3 v, vec3 n) { return ( v - (( dot(v,n) / length(n) ) * n) ); diff --git a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp index 6ae38e1fed..331c434fde 100644 --- a/plugins/probe_gl/src/ProbeGlyphRenderer.cpp +++ b/plugins/probe_gl/src/ProbeGlyphRenderer.cpp @@ -104,11 +104,12 @@ void megamol::probe_gl::ProbeGlyphRenderer::createMaterialCollection() { // scalar glyph shader program material_collection_->addMaterial(this->instance(), "ScalarProbeGlyph", - {"probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph_v2.frag.glsl"}); + {"probe_gl/glyphs/scalar_probe_glyph_v2.vert.glsl", "probe_gl/glyphs/scalar_probe_glyph_v3.frag.glsl"}); // scalar distribution glyph shader program material_collection_->addMaterial(this->instance(), "ScalarDistributionProbeGlyph", - {"probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl", "probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl"}); + {"probe_gl/glyphs/scalar_distribution_probe_glyph_v2.vert.glsl", + "probe_gl/glyphs/scalar_distribution_probe_glyph.frag.glsl"}); // vector glyph shader program material_collection_->addMaterial(this->instance(), "VectorProbeGlyph", @@ -327,7 +328,6 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( m_dial_glyph_background_data.push_back(glyph_data); m_dial_glyph_background_identifiers.push_back( std::string(FullName()) + "_dgbg_" + std::to_string(probe_idx)); - m_type_index_map.push_back({std::type_index(typeid(GlyphBaseProbeData)), probe_idx}); }; std::visit(visitor, generic_probe); @@ -475,6 +475,9 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( for (auto& draw_data : m_clusterID_glyph_data) { draw_data.state = 0; } + for (auto& draw_data : m_dial_glyph_background_data) { + draw_data.state = 0; + } updateAllRenderTasks(); } @@ -484,6 +487,16 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_highlight_events = event_collection->get(); for (auto& evt : pending_highlight_events) { + + // update glyph background + if (evt.obj_id < m_dial_glyph_background_data.size()) { + std::array per_probe_data = {m_dial_glyph_background_data[evt.obj_id]}; + per_probe_data[0].state = 1; + std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + + // update glyph foreground if (evt.obj_id < m_type_index_map.size()) { auto probe_type = m_type_index_map[evt.obj_id].first; auto probe_idx = m_type_index_map[evt.obj_id].second; @@ -504,7 +517,6 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); render_task_collection_->updatePerDrawData(identifier, per_probe_data); } - // bool my_tool_active = true; // float my_color[4] = {0.0, 0.0, 0.0, 0.0}; // @@ -552,6 +564,14 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_dehighlight_events = event_collection->get(); for (auto& evt : pending_dehighlight_events) { + // update glyph background + if (evt.obj_id < m_dial_glyph_background_data.size()) { + std::array per_probe_data = {m_dial_glyph_background_data[evt.obj_id]}; + std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + + // update glyph foreground if (evt.obj_id < m_type_index_map.size()) { auto probe_type = m_type_index_map[evt.obj_id].first; auto probe_idx = m_type_index_map[evt.obj_id].second; @@ -569,6 +589,7 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); render_task_collection_->updatePerDrawData(identifier, per_probe_data); } + } else { //TODO warning } @@ -579,6 +600,15 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_select_events = event_collection->get(); for (auto& evt : pending_select_events) { + // update glyph background + if (evt.obj_id < m_dial_glyph_background_data.size()) { + m_dial_glyph_background_data[evt.obj_id].state = 2; + std::array per_probe_data = {m_dial_glyph_background_data[evt.obj_id]}; + std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + + // update glyph foreground if (evt.obj_id < m_type_index_map.size()) { auto probe_type = m_type_index_map[evt.obj_id].first; auto probe_idx = m_type_index_map[evt.obj_id].second; @@ -609,6 +639,15 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_deselect_events = event_collection->get(); for (auto& evt : pending_deselect_events) { + // update glyph background + if (evt.obj_id < m_dial_glyph_background_data.size()) { + m_dial_glyph_background_data[evt.obj_id].state = 0; + std::array per_probe_data = {m_dial_glyph_background_data[evt.obj_id]}; + std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + + // update glyph foreground if (evt.obj_id < m_type_index_map.size()) { auto probe_type = m_type_index_map[evt.obj_id].first; auto probe_idx = m_type_index_map[evt.obj_id].second; @@ -639,7 +678,16 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_events = event_collection->get(); if (!pending_events.empty()) { + // update glyph background + if (pending_events.back().obj_id < m_dial_glyph_background_data.size()) { + for (auto& draw_data : m_dial_glyph_background_data) { + draw_data.state = 0; + } + + m_dial_glyph_background_data[pending_events.back().obj_id].state = 2; + } + // update glyph foreground if (pending_events.back().obj_id < m_type_index_map.size()) { for (auto& draw_data : m_scalar_probe_glyph_data) { draw_data.state = 0; @@ -674,6 +722,16 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateRenderTaskCollection( { auto pending_select_events = event_collection->get(); for (auto& evt : pending_select_events) { + // update glyph background + if (evt.obj_id < m_dial_glyph_background_data.size()) { + m_dial_glyph_background_data[evt.obj_id].state = + m_dial_glyph_background_data[evt.obj_id].state == 2 ? 0 : 2; + std::array per_probe_data = {m_dial_glyph_background_data[evt.obj_id]}; + std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(evt.obj_id); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } + + // update glyph foreground if (evt.obj_id < m_type_index_map.size()) { auto probe_type = m_type_index_map[evt.obj_id].first; auto probe_idx = m_type_index_map[evt.obj_id].second; @@ -747,12 +805,10 @@ bool megamol::probe_gl::ProbeGlyphRenderer::saveGlyphsToImages(core::param::Para } } - auto render_func = []( - std::shared_ptr shdr_prgm, - std::shared_ptr fbo, - std::shared_ptr draw_data_buffer, - std::shared_ptr draw_command_buffer) - { + auto render_func = [](std::shared_ptr shdr_prgm, + std::shared_ptr fbo, + std::shared_ptr draw_data_buffer, + std::shared_ptr draw_command_buffer) { glDisable(GL_DEPTH_TEST); fbo->bind(); @@ -782,10 +838,7 @@ bool megamol::probe_gl::ProbeGlyphRenderer::saveGlyphsToImages(core::param::Para glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); }; - auto save_to_disk_func = []( - std::string const& filename, - std::shared_ptr fbo) - { + auto save_to_disk_func = [](std::string const& filename, std::shared_ptr fbo) { megamol::frontend_resources::ScreenshotImageData result; result.resize(static_cast(fbo->getWidth()), static_cast(fbo->getHeight())); @@ -817,9 +870,7 @@ bool megamol::probe_gl::ProbeGlyphRenderer::saveGlyphsToImages(core::param::Para // save texture to disk auto filename = "probe_scalar_glyph" + std::to_string(draw_idx) + ".png"; save_to_disk_func(filename, fbo); - } catch (const std::exception&) { - - } + } catch (const std::exception&) {} draw_idx++; } @@ -936,12 +987,12 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); - glFrontFace(GL_CCW); + glFrontFace(GL_CCW); }; if (!m_textured_gylph_draw_commands.empty()) { - render_task_collection_->addRenderTasks(m_textured_glyph_identifiers, textured_shader, - m_billboard_dummy_mesh, m_textured_gylph_draw_commands, m_textured_glyph_data); + render_task_collection_->addRenderTasks(m_textured_glyph_identifiers, textured_shader, m_billboard_dummy_mesh, + m_textured_gylph_draw_commands, m_textured_glyph_data); } if (!m_scalar_probe_glyph_data.empty()) { @@ -961,16 +1012,15 @@ bool megamol::probe_gl::ProbeGlyphRenderer::addAllRenderTasks() { } if (!m_clusterID_gylph_draw_commands.empty()) { - render_task_collection_->addRenderTasks(m_clusterID_glyph_identifiers, clusterID_shader, - m_billboard_dummy_mesh, m_clusterID_gylph_draw_commands, m_clusterID_glyph_data); + render_task_collection_->addRenderTasks(m_clusterID_glyph_identifiers, clusterID_shader, m_billboard_dummy_mesh, + m_clusterID_gylph_draw_commands, m_clusterID_glyph_data); } if (!m_dial_glyph_background_draw_commands.empty()) { render_task_collection_->addRenderTasks(m_dial_glyph_background_identifiers, dial_background_shader, - m_billboard_dummy_mesh, - m_dial_glyph_background_draw_commands, m_dial_glyph_background_data, set_gl_state); + m_billboard_dummy_mesh, m_dial_glyph_background_draw_commands, m_dial_glyph_background_data, set_gl_state); } - return true; + return true; } void megamol::probe_gl::ProbeGlyphRenderer::updateAllRenderTasks() { @@ -990,12 +1040,14 @@ void megamol::probe_gl::ProbeGlyphRenderer::updateAllRenderTasks() { std::array per_probe_data = {m_clusterID_glyph_data[probe_idx]}; std::string identifier = std::string(FullName()) + "_cg_" + std::to_string(probe_idx); render_task_collection_->updatePerDrawData(identifier, per_probe_data); - } else if (probe_type == std::type_index(typeid(GlyphBaseProbeData))) { - std::array per_probe_data = {m_dial_glyph_background_data[probe_idx]}; - std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(probe_idx); - render_task_collection_->updatePerDrawData(identifier, per_probe_data); } } + + for (int i = 0; i < m_dial_glyph_background_data.size(); ++i) { + std::array per_probe_data = {m_dial_glyph_background_data[i]}; + std::string identifier = std::string(FullName()) + "_dgbg_" + std::to_string(i); + render_task_collection_->updatePerDrawData(identifier, per_probe_data); + } } megamol::probe_gl::ProbeGlyphRenderer::GlyphScalarProbeData @@ -1089,9 +1141,9 @@ megamol::probe_gl::ProbeGlyphRenderer::createBaseProbeGlyphData( GlyphBaseProbeData glyph_data; - glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.25f), - probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.25f), - probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.25f), 1.0f); + glyph_data.position = glm::vec4(probe.m_position[0] + probe.m_direction[0] * (probe.m_begin * 1.24f), + probe.m_position[1] + probe.m_direction[1] * (probe.m_begin * 1.24f), + probe.m_position[2] + probe.m_direction[2] * (probe.m_begin * 1.24f), 1.0f); glyph_data.probe_direction = glm::vec4(probe.m_direction[0], probe.m_direction[1], probe.m_direction[2], 1.0f); From 8c0eaa15f466a37c20f1f55cd95c2b526e522f45 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 7 Oct 2022 15:19:03 +0200 Subject: [PATCH 37/47] added generateProbeLevels module --- plugins/probe/src/GenerateProbeLevels.cpp | 325 ++++++++++++++++++++++ plugins/probe/src/GenerateProbeLevels.h | 91 ++++++ plugins/probe/src/probe.cpp | 2 + 3 files changed, 418 insertions(+) create mode 100644 plugins/probe/src/GenerateProbeLevels.cpp create mode 100644 plugins/probe/src/GenerateProbeLevels.h diff --git a/plugins/probe/src/GenerateProbeLevels.cpp b/plugins/probe/src/GenerateProbeLevels.cpp new file mode 100644 index 0000000000..d25f2ac12f --- /dev/null +++ b/plugins/probe/src/GenerateProbeLevels.cpp @@ -0,0 +1,325 @@ +/* + * GenerateProbeLevels.cpp + * Copyright (C) 2022 by MegaMol Team + * Alle Rechte vorbehalten. + */ + +#include "GenerateProbeLevels.h" +#include "probe/ProbeCalls.h" + + +namespace megamol { +namespace probe { + +GenerateProbeLevels::GenerateProbeLevels() + : Module() + , _version(0) + , _probe_rhs_slot("getProbes", "") + , _probe_lhs_slot("deployProbes", "") +{ + _probe_rhs_slot.SetCompatibleCall(); + MakeSlotAvailable(&_probe_rhs_slot); + _probe_rhs_slot.SetNecessity(megamol::core::AbstractCallSlotPresentation::SLOT_REQUIRED); + + _probe_lhs_slot.SetCallback(CallProbes::ClassName(), CallProbes::FunctionName(0), &GenerateProbeLevels::getData); + _probe_lhs_slot.SetCallback( + CallProbes::ClassName(), CallProbes::FunctionName(1), &GenerateProbeLevels::getMetaData); + MakeSlotAvailable(&_probe_lhs_slot); +} + +GenerateProbeLevels::~GenerateProbeLevels() { + this->Release(); +} + +bool GenerateProbeLevels::create() { + return true; +} + +void GenerateProbeLevels::release() {} + +float GenerateProbeLevels::getAvgDist() { + int const neighbors = 5; + int const num_samples = 5; + std::vector ret_index(neighbors); + std::vector out_dist_sqr(neighbors); + nanoflann::KNNResultSet resultSet(neighbors); + + std::mt19937 rnd; + rnd.seed(std::random_device()()); + std::uniform_int_distribution dist(0, _probe_positions.size()); + + float avg_dist = 0; + for (int i = 0; i < num_samples; i++) { + auto const sample_pos = _probe_positions[dist(rnd)]; + + _probe_tree->findNeighbors(resultSet, &sample_pos[0], nanoflann::SearchParams()); + + float distance = 0; + for (auto current_dist : out_dist_sqr) { + distance += current_dist * current_dist; + } + distance /= (neighbors -1); + avg_dist = distance; + } + avg_dist /= num_samples; + + return avg_dist; +} + +bool GenerateProbeLevels::getData(core::Call& call) { + + auto const lhs_probes = dynamic_cast(&call); + if (lhs_probes == nullptr) + return false; + + auto const rhs_probes = _probe_rhs_slot.CallAs(); + if (rhs_probes == nullptr) + return false; + + auto meta_data = rhs_probes->getMetaData(); + if (!(*rhs_probes)(0)) + return false; + + bool const rhs_dirty = rhs_probes->hasUpdate(); + if (rhs_dirty) { + ++_version; + + auto tmp_center = meta_data.m_bboxs.BoundingBox().CalcCenter(); + _center = {tmp_center.GetX(), tmp_center.GetY(), tmp_center.GetZ()}; + auto const probe_count = rhs_probes->getData()->getProbeCount(); + _probe_positions.resize(probe_count); + for (auto i = 0; i < probe_count; i++) { + auto const base_probe = rhs_probes->getData()->getBaseProbe(i); + _probe_positions[i] = base_probe.m_position; + } + + _probe_dataKD = std::make_shared(_probe_positions); + _probe_tree = std::make_shared( + 3 /*dim*/, *_probe_dataKD, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + _probe_tree->buildIndex(); + + //float const avg_dist = getAvgDist(); + + //// estimate pack of 4 + //int const neighbors = 10 + 1; + //std::vector ret_index(neighbors); + //std::vector out_dist_sqr(neighbors); + //nanoflann::KNNResultSet resultSet(neighbors); + + //std::mt19937 rnd; + //rnd.seed(std::random_device()()); + //std::uniform_int_distribution dist(0, _probe_positions.size()); + //int rnd_probe_idx = dist(rnd); + //auto rnd_probe_pos = _probe_positions[rnd_probe_idx]; + + //_probe_tree->findNeighbors(resultSet, &rnd_probe_pos[0], nanoflann::SearchParams()); + + + // map surface to sphere + // calcMolecularMap()... + + // transform x,y,z -> r,theta,phi + if (!calcSphericalCoordinates()) + return false; + + // do a mercator projection + if (!calcMercatorProjection()) + return false; + + // start with grouping from bottom left + if (!calcLevels(rhs_probes->getData())) + return false; + + } + + + for (int i = 0; i < lhs_probes->getData()->getNumLevels(); i++) { + lhs_probes->getData()->setLevel(i, _levels[i]); + } + + return true; +} + +bool GenerateProbeLevels::getMetaData(core::Call& call) { + + auto const rhs_probe = this->_probe_rhs_slot.CallAs(); + auto const lhs_probe = dynamic_cast(&call); + if (lhs_probe == nullptr) + return false; + + if (rhs_probe == nullptr) + return false; + + auto lhs_meta_data = lhs_probe->getMetaData(); + auto rhs_meta_data = rhs_probe->getMetaData(); + rhs_meta_data.m_frame_ID = lhs_meta_data.m_frame_ID; + rhs_probe->setMetaData(rhs_meta_data); + + if (!(*rhs_probe)(1)) + return false; + rhs_meta_data = rhs_probe->getMetaData(); + + lhs_meta_data.m_frame_cnt = rhs_meta_data.m_frame_cnt; + lhs_meta_data.m_bboxs = rhs_meta_data.m_bboxs; + + // put metadata in mesh call + lhs_probe->setMetaData(rhs_meta_data); + + return true; +} + +bool GenerateProbeLevels::parameterChanged(core::param::ParamSlot& p) { + _recalc = true; + return true; +} + +bool GenerateProbeLevels::calcSphericalCoordinates() { + if (_probe_positions.empty()) { + core::utility::log::Log::DefaultLog.WriteError("[GenerateProbeLevels] Probe positions empty. Abort."); + return false; + } + + _probe_positions_spherical_coodrinates.clear(); + _probe_positions_spherical_coodrinates.resize(_probe_positions.size()); + for (int i = 0; i < _probe_positions.size(); ++i) { + glm::vec3 const pos = glm::vec3(_probe_positions[i][0], _probe_positions[i][1], _probe_positions[i][2]) - + glm::vec3(_center[0], _center[1], _center[2]); + + auto const r = glm::length(pos); + auto const theta = std::acosf(pos.z/ r); + auto const phi = std::atan2f(pos.y, pos.x); + + _probe_positions_spherical_coodrinates[i][0] = r; + _probe_positions_spherical_coodrinates[i][1] = theta; + _probe_positions_spherical_coodrinates[i][2] = phi; + } + + return true; +} + +bool GenerateProbeLevels::calcMercatorProjection() { + + if (_probe_positions_spherical_coodrinates.empty()) { + core::utility::log::Log::DefaultLog.WriteError("[GenerateProbeLevels] Calculate spherical coordinates first. Abort."); + return false; + } + _probe_positions_mercator.clear(); + _probe_positions_mercator.resize(_probe_positions_spherical_coodrinates.size()); + + std::vector bounds(4); + bounds[0] = std::numeric_limits::max(); + bounds[1] = std::numeric_limits::max(); + bounds[2] = std::numeric_limits::lowest(); + bounds[3] = std::numeric_limits::lowest(); + for (int i = 0; i < _probe_positions_spherical_coodrinates.size(); i++) { + // theta -> phi , phi -> lambda + auto const phi = _probe_positions_spherical_coodrinates[i][1]; + auto const lambda = _probe_positions_spherical_coodrinates[i][2]; + + _probe_positions_mercator[i][0] = lambda; + _probe_positions_mercator[i][1] = 0.5f * std::logf((1.0f + std::sinf(phi)) / (1.0f - std::sinf(phi))); + + bounds[0] = std::min(bounds[0], _probe_positions_mercator[i][0]); + bounds[1] = std::min(bounds[1], _probe_positions_mercator[i][1]); + bounds[2] = std::max(bounds[2], _probe_positions_mercator[i][0]); + bounds[3] = std::max(bounds[3], _probe_positions_mercator[i][1]); + + } + + _mercator_bounds = bounds; + + return true; +} + +bool GenerateProbeLevels::calcLevels(std::shared_ptr inputProbes) { + + if (_probe_positions_mercator.empty()) { + return false; + } + + auto const grid_dim_x = 20; + auto const grid_dim_y = 20; + + auto const grid_step_x = (_mercator_bounds[2] - _mercator_bounds[0]) / static_cast(grid_dim_x); + auto const grid_step_y = (_mercator_bounds[3] - _mercator_bounds[1]) / static_cast(grid_dim_y); + + std::vector> level_by_id; + level_by_id.resize(grid_dim_x * grid_dim_y); + + // span grid over projection and use one grid cell as first superlevel + for (int i = 0; i < _probe_positions_mercator.size(); i ++) { + + auto id_x = std::clamp(_probe_positions_mercator[i][0], _mercator_bounds[0], _mercator_bounds[2]) / + static_cast(grid_dim_x); + auto id_y = std::clamp(_probe_positions_mercator[i][1], _mercator_bounds[1], _mercator_bounds[3]) / + static_cast(grid_dim_y); + + auto const n = grid_dim_x * id_y + id_x; + level_by_id[n].emplace_back(i); + } + + // generate level from level_by_id + ProbeCollection::ProbeLevel level; + + + for (int n = 0; n < level_by_id.size(); n++) { + if (level_by_id.empty()) { + core::utility::log::Log::DefaultLog.WriteError("[GenerateProbeLevels] Level found to be empty."); + } + auto const id_x = n % grid_dim_x; + auto const id_y = n / grid_dim_x; + std::array level_midpoint = {id_x * grid_step_x + 0.5f * grid_step_x, id_y * grid_step_y + 0.5f * grid_step_y}; + auto const radius = _probe_positions_spherical_coodrinates[level_by_id[n][0]][0]; + auto const new_probe_pos_spherical = calcInverseMercatorProjection(level_midpoint, radius); + auto const new_probe_pos = calcInverseSphericalProjection(new_probe_pos_spherical); + + if (std::holds_alternative(inputProbes->getGenericProbe(0))) { + + FloatDistributionProbe probe; + probe.m_position = new_probe_pos; + /// ... fill with meta data + + for (auto probe_id : level_by_id[n]) { + /// accumulate sample results + + } + } else { + + } + } + + // generate next level by joining cells + // starting from left bottom + + + + + return true; +} + + +std::array GenerateProbeLevels::calcInverseMercatorProjection(std::array const& coords, float const& r) { + + std::array res; + + res[0] = r; + res[1] = std::atanf(std::sinhf(coords[1])); + res[2] = coords[0]; // lambda + + return res; +} + +std::array GenerateProbeLevels::calcInverseSphericalProjection(std::array const& coords) { + + std::array res; + + res[0] = coords[0] * std::sinf(coords[1]) * + std::cosf(coords[2]); + res[1] = coords[0] * std::sinf(coords[1]) * std::sinf(coords[2]); + res[2] = coords[0] * std::cosf(coords[1]); + + return res; +} + +} // namespace probe +} // namespace megamol diff --git a/plugins/probe/src/GenerateProbeLevels.h b/plugins/probe/src/GenerateProbeLevels.h new file mode 100644 index 0000000000..3900745e6a --- /dev/null +++ b/plugins/probe/src/GenerateProbeLevels.h @@ -0,0 +1,91 @@ +/* + * GenerateProbeLevels.h + * Copyright (C) 2022 by MegaMol Team + * Alle Rechte vorbehalten. + */ + + +#pragma once + +#include "glm/glm.hpp" + +#include "mmcore/CalleeSlot.h" +#include "mmcore/CallerSlot.h" +#include "mmcore/Module.h" + +#include "mesh/MeshCalls.h" +#include "mmcore/param/ParamSlot.h" +#include "probe/CallKDTree.h" +#include "probe/ProbeCollection.h" + + +namespace megamol { +namespace probe { + + +class GenerateProbeLevels : public core::Module { +public: + /** + * Answer the name of this module. + * + * @return The name of this module. + */ + static const char* ClassName() { + return "GenerateProbeLevels"; + } + + /** + * Answer a human readable description of this module. + * + * @return A human readable description of this module. + */ + static const char* Description() { + return "..."; + } + + /** + * Answers whether this module is available on the current system. + * + * @return 'true' if the module is available, 'false' otherwise. + */ + static bool IsAvailable(void) { + return true; + } + + GenerateProbeLevels(); + virtual ~GenerateProbeLevels(); + +protected: + virtual bool create(); + virtual void release(); + + uint32_t _version; + + core::CallerSlot _probe_rhs_slot; + core::CalleeSlot _probe_lhs_slot; + +private: + float getAvgDist(); + bool getData(core::Call& call); + bool getMetaData(core::Call& call); + bool parameterChanged(core::param::ParamSlot& p); + bool calcSphericalCoordinates(); + bool calcMercatorProjection(); + bool calcLevels(std::shared_ptr inputProbes); + std::array calcInverseMercatorProjection(std::array const& coords, float const& r); + std::array calcInverseSphericalProjection(std::array const& coords); + + std::vector _levels; + bool _recalc = false; + + std::shared_ptr _probe_tree; + std::shared_ptr _probe_dataKD; + std::vector> _probe_positions; + std::vector> _probe_positions_spherical_coodrinates; + std::vector> _probe_positions_mercator; + std::vector _mercator_bounds; + std::array _center; +}; + +} // namespace probe +} // namespace megamol diff --git a/plugins/probe/src/probe.cpp b/plugins/probe/src/probe.cpp index 17b09d212f..7a27f2996a 100644 --- a/plugins/probe/src/probe.cpp +++ b/plugins/probe/src/probe.cpp @@ -35,6 +35,7 @@ #include "TessellateBoundingBox.h" #include "FilterProbes.h" #include "DualMeshProbeSampling.h" +#include "GenerateProbeLevels.h" namespace megamol::probe { class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { @@ -77,6 +78,7 @@ class ProbePluginInstance : public megamol::core::utility::plugins::AbstractPlug this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); this->module_descriptions.RegisterAutoDescription(); + this->module_descriptions.RegisterAutoDescription(); // register calls From 83bd9c51d793fb85a9f04bf9012b1895670831a4 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 7 Oct 2022 15:20:13 +0200 Subject: [PATCH 38/47] added posibility to filter columns in computeDistance --- plugins/probe_gl/src/ComputeDistance.cpp | 46 +++++++++++++++++++++--- plugins/probe_gl/src/ComputeDistance.h | 9 +++++ 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/plugins/probe_gl/src/ComputeDistance.cpp b/plugins/probe_gl/src/ComputeDistance.cpp index c97bbf25a5..4451517895 100644 --- a/plugins/probe_gl/src/ComputeDistance.cpp +++ b/plugins/probe_gl/src/ComputeDistance.cpp @@ -2,7 +2,8 @@ #include "mmcore/CoreInstance.h" #include "mmcore/param/FloatParam.h" -#include "mmcore_gl/utility/ShaderSourceFactory.h" +#include "mmcore/param/IntParam.h" +#include "mmcore/param/ButtonParam.h" #include "glm/glm.hpp" @@ -19,7 +20,10 @@ megamol::probe_gl::ComputeDistance::ComputeDistance() : _out_table_slot("outTable", "") , _in_probes_slot("inProbes", "") - , _stretching_factor_slot("stretching factor", "") { + , _stretching_factor_slot("stretching factor", "") + , _min_sample_slot("minSample", "") + , _max_sample_slot("maxSample", "") + , _recalc_slot("recalc", "") { _out_table_slot.SetCallback(datatools::table::TableDataCall::ClassName(), datatools::table::TableDataCall::FunctionName(0), &ComputeDistance::get_data_cb); _out_table_slot.SetCallback(datatools::table::TableDataCall::ClassName(), @@ -31,6 +35,17 @@ megamol::probe_gl::ComputeDistance::ComputeDistance() _stretching_factor_slot << new core::param::FloatParam(5.0f, 0.0f); MakeSlotAvailable(&_stretching_factor_slot); + + _min_sample_slot << new core::param::IntParam(-1); + MakeSlotAvailable(&_min_sample_slot); + + _max_sample_slot << new core::param::IntParam(-1); + MakeSlotAvailable(&_max_sample_slot); + + _recalc_slot << new core::param::ButtonParam(); + _recalc_slot.SetUpdateCallback(&ComputeDistance::paramChanged); + MakeSlotAvailable(&_recalc_slot); + } @@ -62,10 +77,13 @@ bool megamol::probe_gl::ComputeDistance::get_data_cb(core::Call& c) { auto const& meta_data = in_probes->getMetaData(); - if (in_probes->hasUpdate() || meta_data.m_frame_ID != _frame_id || _stretching_factor_slot.IsDirty()) { + if (in_probes->hasUpdate() || meta_data.m_frame_ID != _frame_id || _stretching_factor_slot.IsDirty() || _trigger_recalc) { + auto const& probe_data = in_probes->getData(); auto const probe_count = probe_data->getProbeCount(); + _trigger_recalc = false; + _row_count = probe_count; _col_count = probe_count; _col_infos.clear(); @@ -327,12 +345,24 @@ bool megamol::probe_gl::ComputeDistance::get_data_cb(core::Call& c) { base_skip = 0; core::utility::log::Log::DefaultLog.WriteInfo( "[ComputeDistance] Skipping first %d samples due to NaNs", base_skip); - auto base_sample_count = sample_count - base_skip; + + // user defined range + auto const bottom = _min_sample_slot.Param()->Value(); + auto top = _max_sample_slot.Param()->Value(); + std::size_t base_sample_count = 0; + if (bottom >= 0 && top >= 1) { + base_sample_count = top - bottom; + base_skip = bottom; + } else { + base_sample_count = sample_count - base_skip; + top = base_sample_count; + } + auto X = Eigen::MatrixXd(probe_count, base_sample_count); for (std::int64_t a_pidx = 0; a_pidx < probe_count; ++a_pidx) { auto const a_probe = probe_data->getProbe(a_pidx); auto const& a_samples_tmp = a_probe.getSamplingResult()->samples; - for (std::size_t sample_idx = base_skip; sample_idx < base_sample_count; ++sample_idx) { + for (std::size_t sample_idx = base_skip; sample_idx < top; ++sample_idx) { X(a_pidx, sample_idx - base_skip) = a_samples_tmp[sample_idx]; } } @@ -440,3 +470,9 @@ bool megamol::probe_gl::ComputeDistance::get_extent_cb(core::Call& c) { return true; } + +bool megamol::probe_gl::ComputeDistance::paramChanged(core::param::ParamSlot& p) { + + _trigger_recalc = true; + return true; +} diff --git a/plugins/probe_gl/src/ComputeDistance.h b/plugins/probe_gl/src/ComputeDistance.h index 02adaa6390..9724735cb2 100644 --- a/plugins/probe_gl/src/ComputeDistance.h +++ b/plugins/probe_gl/src/ComputeDistance.h @@ -56,6 +56,7 @@ class ComputeDistance : public core::Module { bool get_data_cb(core::Call& c); bool get_extent_cb(core::Call& c); + bool paramChanged(core::param::ParamSlot& p); core::CalleeSlot _out_table_slot; @@ -63,6 +64,12 @@ class ComputeDistance : public core::Module { core::param::ParamSlot _stretching_factor_slot; + core::param::ParamSlot _min_sample_slot; + + core::param::ParamSlot _max_sample_slot; + + core::param::ParamSlot _recalc_slot; + std::size_t _row_count = 0; std::size_t _col_count = 0; @@ -78,5 +85,7 @@ class ComputeDistance : public core::Module { vislib_gl::graphics::gl::GLSLComputeShader _fd_shader; vislib_gl::graphics::gl::ShaderSource _compute_shader_src; + + bool _trigger_recalc; }; } // namespace megamol::probe_gl From a1ebb90ba97f6b0fdbcd90751460585591f21f82 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 7 Oct 2022 15:21:52 +0200 Subject: [PATCH 39/47] fixed dirty missbehavior in felx convert --- plugins/mmadios/src/ADIOSFlexConvert.cpp | 3 ++- plugins/mmadios/src/ADIOSFlexConvert.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/mmadios/src/ADIOSFlexConvert.cpp b/plugins/mmadios/src/ADIOSFlexConvert.cpp index b519610dbe..3e2db57264 100644 --- a/plugins/mmadios/src/ADIOSFlexConvert.cpp +++ b/plugins/mmadios/src/ADIOSFlexConvert.cpp @@ -88,10 +88,11 @@ bool ADIOSFlexConvert::getDataCallback(core::Call& call) { megamol::core::utility::log::Log::DefaultLog.WriteError("[ADIOSFlexConvert] Error during GetHeader"); return false; } - bool dathashChanged = (mpdc->DataHash() != cad->getDataHash()); + bool dathashChanged = (currentDatahash != cad->getDataHash()); if ((mpdc->FrameID() != currentFrame) || dathashChanged || _trigger_recalc) { _trigger_recalc = false; + currentDatahash = cad->getDataHash(); // get adios meta data auto availVars = cad->getAvailableVars(); diff --git a/plugins/mmadios/src/ADIOSFlexConvert.h b/plugins/mmadios/src/ADIOSFlexConvert.h index 5dd58038f8..5520e7d4fc 100644 --- a/plugins/mmadios/src/ADIOSFlexConvert.h +++ b/plugins/mmadios/src/ADIOSFlexConvert.h @@ -92,6 +92,7 @@ class ADIOSFlexConvert : public core::Module { std::vector mix; size_t currentFrame = -1; + size_t currentDatahash = -1; geocalls::SimpleSphericalParticles::ColourDataType colType = geocalls::SimpleSphericalParticles::COLDATA_NONE; geocalls::SimpleSphericalParticles::VertexDataType vertType = geocalls::SimpleSphericalParticles::VERTDATA_NONE; From 65af92339372781f7a06259ce885ebb1fa6b040c Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 7 Oct 2022 15:55:16 +0200 Subject: [PATCH 40/47] probe placement now supports skipping edges and corners --- plugins/probe/src/PlaceProbes.cpp | 90 +++++++++++++++++++++++++++++-- plugins/probe/src/PlaceProbes.h | 5 ++ 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/plugins/probe/src/PlaceProbes.cpp b/plugins/probe/src/PlaceProbes.cpp index 35b3fee402..09bc0887f9 100644 --- a/plugins/probe/src/PlaceProbes.cpp +++ b/plugins/probe/src/PlaceProbes.cpp @@ -7,6 +7,7 @@ #include "PlaceProbes.h" #include "mmcore/param/EnumParam.h" #include "mmcore/param/FloatParam.h" +#include "mmcore/param/BoolParam.h" #include "probe/MeshUtilities.h" #include "probe/ProbeCalls.h" #include "mmstd/renderer/CallClipPlane.h" @@ -17,6 +18,9 @@ namespace megamol { namespace probe { + +glm::vec3 to_vec3(vislib::math::Vector vec) {return glm::vec3(vec.GetX(), vec.GetY(),vec.GetZ());} + megamol::probe::PlaceProbes::PlaceProbes() : Module() , _version(0) @@ -30,6 +34,7 @@ megamol::probe::PlaceProbes::PlaceProbes() , _scale_probe_begin_slot("distanceFromSurfaceFactor", "") , _override_probe_length_slot("overrideProbeLength", "") , _clipplane_slot("getClipplane", "") + , _skip_edges_corers_slot("skipEdgesAndCorners", "") , _longest_edge_index(0) { this->_probe_slot.SetCallback(CallProbes::ClassName(), CallProbes::FunctionName(0), &PlaceProbes::getData); @@ -79,6 +84,10 @@ megamol::probe::PlaceProbes::PlaceProbes() this->_scale_probe_begin_slot.SetUpdateCallback(&PlaceProbes::parameterChanged); this->MakeSlotAvailable(&this->_scale_probe_begin_slot); + this->_skip_edges_corers_slot << new core::param::BoolParam(false); + this->_skip_edges_corers_slot.SetUpdateCallback(&PlaceProbes::parameterChanged); + this->MakeSlotAvailable(&this->_skip_edges_corers_slot); + /* Feasibility test */ _probes = std::make_shared(); _probes->addProbe(FloatProbe()); @@ -539,7 +548,7 @@ void megamol::probe::PlaceProbes::vertexNormalSampling(mesh::MeshDataAccessColle auto normal_accessor = reinterpret_cast(normals.data); auto normal_step = normals.stride / sizeof(float); - auto probe_id_accessor = reinterpret_cast(probe_ids.data); + bool const skip_edges_and_corners = _skip_edges_corers_slot.Param()->Value(); //#pragma omp parallel for for (int i = 0; i < probe_count; i++) { @@ -548,6 +557,15 @@ void megamol::probe::PlaceProbes::vertexNormalSampling(mesh::MeshDataAccessColle probe.m_position = {vertex_accessor[vertex_step * i + 0], vertex_accessor[vertex_step * i + 1], vertex_accessor[vertex_step * i + 2]}; + + if (skip_edges_and_corners) { + auto const sample_point = glm::vec3(probe.m_position[0],probe.m_position[1],probe.m_position[2]); + auto const is_on_edge = isOnCornerOrEdge(sample_point); + if (is_on_edge) { + continue; + } + } + probe.m_direction = {-normal_accessor[normal_step * i + 0], -normal_accessor[normal_step * i + 1], -normal_accessor[normal_step * i + 2]}; probe.m_begin = -2.0 * _scale_probe_begin_slot.Param()->Value(); @@ -555,11 +573,10 @@ void megamol::probe::PlaceProbes::vertexNormalSampling(mesh::MeshDataAccessColle probe.m_orig_end = probe.m_end; probe.m_cluster_id = -1; probe.m_placement_method = BaseProbe::VERTEX_NORMAL; + probe.m_geo_ids.emplace_back(_mesh->accessMeshes().begin()->first); + probe.m_vert_ids.emplace_back(i); - auto probe_idx = this->_probes->getProbeCount(); - this->_probes->addProbe(std::move(probe)); - - probe_id_accessor[i] = probe_idx; + _probes->addProbe(std::move(probe)); } } @@ -1102,5 +1119,68 @@ void PlaceProbes::processClipplane() { } } + +bool PlaceProbes::isOnCornerOrEdge(glm::vec3 const samplePoint) { + + constexpr float epsilon = 0.5f; + + float distance = std::numeric_limits::max(); + + auto rtf = to_vec3(_bbox.BoundingBox().GetRightTopFront()); + + std::vector> corners(8); + _bbox.BoundingBox().GetPoints(corners.begin()); + + for (auto const& corner : corners) { + auto const c = to_vec3(corner); + distance = std::min(distance, glm::length(c - samplePoint)); + } + + // LBF RBF + distance = std::min(distance, distanceToLine( + to_vec3(_bbox.BoundingBox().GetLeftBottomFront()), to_vec3(_bbox.BoundingBox().GetRightBottomFront()), samplePoint)); + // LBF LTF + distance = std::min(distance,distanceToLine(to_vec3(_bbox.BoundingBox().GetLeftBottomFront()), + to_vec3(_bbox.BoundingBox().GetLeftTopFront()), samplePoint)); + // LBF LBB + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetLeftBottomFront()), + to_vec3(_bbox.BoundingBox().GetLeftBottomBack()), samplePoint)); + // RTF RBF + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetRightTopFront()), + to_vec3(_bbox.BoundingBox().GetRightBottomFront()), samplePoint)); + // RTF LTF + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetRightTopFront()), + to_vec3(_bbox.BoundingBox().GetLeftTopFront()), samplePoint)); + // RTF RTB + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetRightTopFront()), + to_vec3(_bbox.BoundingBox().GetRightTopBack()), samplePoint)); + // LTB LTF + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetLeftTopBack()), + to_vec3(_bbox.BoundingBox().GetLeftTopFront()), samplePoint)); + // LTB LBB + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetLeftTopBack()), + to_vec3(_bbox.BoundingBox().GetLeftBottomBack()), samplePoint)); + // LTB RTB + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetLeftTopBack()), + to_vec3(_bbox.BoundingBox().GetRightTopBack()), samplePoint)); + // RBB RTB + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetRightBottomBack()), + to_vec3(_bbox.BoundingBox().GetRightTopBack()), samplePoint)); + // RBB RBF + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetRightBottomBack()), + to_vec3(_bbox.BoundingBox().GetRightBottomFront()), samplePoint)); + // RBB LBB + distance = std::min(distance, distanceToLine(to_vec3(_bbox.BoundingBox().GetRightBottomBack()), + to_vec3(_bbox.BoundingBox().GetLeftBottomBack()), samplePoint)); + _allDists.emplace_back(distance); + return (distance < epsilon); +} + + +float PlaceProbes::distanceToLine(glm::vec3 const linePointA, glm::vec3 const linePointB, glm::vec3 const samplePoint) { + return glm::length(glm::cross(linePointA - linePointB, samplePoint - linePointB)) / glm::length(samplePoint - linePointB); +} + + } // namespace probe } // namespace megamol diff --git a/plugins/probe/src/PlaceProbes.h b/plugins/probe/src/PlaceProbes.h index 2e453629fe..45931a37a1 100644 --- a/plugins/probe/src/PlaceProbes.h +++ b/plugins/probe/src/PlaceProbes.h @@ -76,6 +76,7 @@ class PlaceProbes : public core::Module { core::param::ParamSlot _probes_per_unit_slot; core::param::ParamSlot _scale_probe_begin_slot; core::param::ParamSlot _override_probe_length_slot; + core::param::ParamSlot _skip_edges_corers_slot; private: @@ -103,6 +104,8 @@ class PlaceProbes : public core::Module { bool loadFromFile(); bool parameterChanged(core::param::ParamSlot& p); void processClipplane(); + float distanceToLine(glm::vec3 const linePointA, glm::vec3 const linePointB, glm::vec3 const samplePoint); + bool isOnCornerOrEdge(glm::vec3 const samplePoint); uint32_t _longest_edge_index; @@ -121,6 +124,8 @@ class PlaceProbes : public core::Module { std::vector _probeVertices; adios::adiosDataMap dataMap; bool _recalc; + + std::vector _allDists; }; From 79e06616533b3c98976af1f051d9c1300ae59439 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 7 Oct 2022 15:56:20 +0200 Subject: [PATCH 41/47] rename erase and shuffle proves --- plugins/probe/src/SampleAlongProbes.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/probe/src/SampleAlongProbes.h b/plugins/probe/src/SampleAlongProbes.h index de9ee957bf..d769648adb 100644 --- a/plugins/probe/src/SampleAlongProbes.h +++ b/plugins/probe/src/SampleAlongProbes.h @@ -598,7 +598,7 @@ void SampleAlongPobes::doTetrahedralSampling( global_max = std::max(global_max, samples->max_value); } // end for probes _probes->setGlobalMinMax(global_min, global_max); - _probes->shuffle_probes(); + _probes->shuffleProbes(); } template @@ -758,8 +758,8 @@ inline void SampleAlongPobes::doTetrahedralVectorSamling(const std::shared_ptrsetGlobalMinMax(global_min, global_max); - _probes->erase_probes(invalid_probes); - _probes->shuffle_probes(); + _probes->eraseProbes(invalid_probes); + _probes->shuffleProbes(); } From 3570db089bcb740c9c16924d9d43a79e203bb003 Mon Sep 17 00:00:00 2001 From: rauts Date: Fri, 7 Oct 2022 15:57:13 +0200 Subject: [PATCH 42/47] fixes and improvements on dual mesh sampling --- plugins/probe/src/DualMeshProbeSampling.cpp | 9 +++++++-- plugins/probe/src/DualMeshProbeSampling.h | 16 ++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/plugins/probe/src/DualMeshProbeSampling.cpp b/plugins/probe/src/DualMeshProbeSampling.cpp index 4f33eef3e6..7255cf47c6 100644 --- a/plugins/probe/src/DualMeshProbeSampling.cpp +++ b/plugins/probe/src/DualMeshProbeSampling.cpp @@ -243,7 +243,6 @@ bool DualMeshProbeSampling::getData(core::Call& call) { } // put data into probes - if (cd != nullptr) { _old_datahash = cd->getDataHash(); meta_data.m_bboxs = tree_meta_data.m_bboxs; @@ -566,7 +565,7 @@ bool DualMeshProbeSampling::calcDualMesh(std::shared_ptr triangles; triangles.reserve(5); @@ -604,6 +603,9 @@ bool DualMeshProbeSampling::calcDualMesh(std::shared_ptr::lowest(); T probe_avg = 0.0; samples->samples.resize(samples_per_probe); + // _dual_mesh_vertices is sorted after probe ids auto dual_mesh_top_vertices = _dual_mesh_vertices[i]; auto dual_mesh_bottom_vertices = _dual_mesh_vertices[i]; for (int j = 0; j < samples_per_probe; j++) { @@ -202,7 +203,7 @@ inline void DualMeshProbeSampling::doScalarDistributionSampling( // DEBUG USE: auto sampledist_to_probe = glm::length(to_vec3(sample_center) - to_vec3(probe.m_position)); float min_radius = std::numeric_limits::max(); - float blub = 0.0f; + float _ = 0.0f; float radius = sample_step/2.0f; for (int d = 0; d < dual_mesh_top_vertices.size(); d++) { // determine max radius of sampling geometry @@ -236,8 +237,7 @@ inline void DualMeshProbeSampling::doScalarDistributionSampling( bool check_bottom = true; bool includes_probe = false; - if (j == 0 && (probe.m_placement_method == BaseProbe::CENTERPOINT || - probe.m_placement_method == BaseProbe::CENTERLINE)) { + if (j == 0 && probe.m_placement_method != BaseProbe::VERTEX_NORMAL) { includes_probe = true; } if ((j == samples_per_probe - 1) && (probe.m_placement_method == BaseProbe::CENTERPOINT || @@ -262,7 +262,7 @@ inline void DualMeshProbeSampling::doScalarDistributionSampling( points_to_keep.emplace_back(id); kept_dists.emplace_back(std::sqrtf(id.second)); }else { - if (isInsideSamplingArea(blub, point, dual_mesh_top_vertices, dual_mesh_bottom_vertices, + if (isInsideSamplingArea(_, point, dual_mesh_top_vertices, dual_mesh_bottom_vertices, probe.m_position, probe.m_direction, check_bottom, includes_probe)) { points_to_keep.emplace_back(id); kept_dists.emplace_back(std::sqrtf(id.second)); @@ -400,13 +400,9 @@ inline void DualMeshProbeSampling::doVectorSamling(const std::shared_ptrsamples[j][0] = value_x / num_neighbors; - ; samples->samples[j][1] = value_y / num_neighbors; - ; samples->samples[j][2] = value_z / num_neighbors; - ; samples->samples[j][3] = value_w / num_neighbors; - ; //min_value = std::min(min_value, value); //max_value = std::max(max_value, value); //avg_value += value; @@ -424,8 +420,8 @@ inline bool DualMeshProbeSampling::isInsideSamplingArea(float& min_radius, const const std::vector>& _top, const std::vector>& bottom, const std::array& _probe, const std::array& _probe_dir, const bool check_bottom, const bool includes_probe) { - assert(bottom.size() > 3); - assert(_top.size() > 3); + assert(bottom.size() >= 3); + assert(_top.size() >= 3); glm::vec3 const point = to_vec3(_point); glm::vec3 const probe = to_vec3(_probe); From 4828d122357ef11fefda9e55798feaee4cae7044 Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 12 Oct 2022 12:04:55 +0200 Subject: [PATCH 43/47] added vector distribution probe --- plugins/probe/include/probe/ProbeCollection.h | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/plugins/probe/include/probe/ProbeCollection.h b/plugins/probe/include/probe/ProbeCollection.h index bb050ebd23..e13a30151f 100644 --- a/plugins/probe/include/probe/ProbeCollection.h +++ b/plugins/probe/include/probe/ProbeCollection.h @@ -107,6 +107,32 @@ struct FloatDistributionProbe : public BaseProbe { std::shared_ptr m_result; }; +struct VectorDistributionProbe : public BaseProbe { +public: + struct SampleValue { + std::vector> norm_directions; + std::vector magnitudes; + std::vector> positions; + }; + + struct SamplingResult { + std::vector samples; + }; + + VectorDistributionProbe() : m_result(std::make_shared()) {} + + template + void probe(DatafieldType const& datafield) { /* ToDo*/ + } + + std::shared_ptr getSamplingResult() const { + return m_result; + } + +private: + std::shared_ptr m_result; +}; + struct IntProbe : public BaseProbe { void probe() { /*ToDo*/ } From f700e063b0a2e43cb84a5a93c914ce7e6dba00b5 Mon Sep 17 00:00:00 2001 From: rauts Date: Wed, 19 Oct 2022 14:39:13 +0200 Subject: [PATCH 44/47] added PBC kd tree adaptor --- plugins/probe/include/probe/PBCkdTree.h | 91 +++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 plugins/probe/include/probe/PBCkdTree.h diff --git a/plugins/probe/include/probe/PBCkdTree.h b/plugins/probe/include/probe/PBCkdTree.h new file mode 100644 index 0000000000..5bbedd9f17 --- /dev/null +++ b/plugins/probe/include/probe/PBCkdTree.h @@ -0,0 +1,91 @@ + +#pragma once + +namespace megamol::probe { + + +class PBC_adaptor { +private: + std::vector> dat; + std::array bounds; + bool cycleX = false; + bool cycleY = false; + + enum applyPBC { X = (1 << 0), Y = (1 << 1)}; + +public: + typedef float coord_t; + + PBC_adaptor(std::vector>& dat, std::array const& bounds) + : dat(dat) + , bounds(bounds) {} + + PBC_adaptor(std::vector> const& dat, std::array const& bounds, bool pbcX, bool pbcY) + : dat(dat) + , bounds(bounds) + , cycleX(pbcX) + , cycleY(pbcY) {} + + ~PBC_adaptor() {} + + // Must return the number of data points + inline size_t kdtree_get_point_count() const { + return dat.size(); + } + + // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class: + inline coord_t kdtree_distance(const coord_t* p1, const size_t idx_p2, size_t /*size*/) const { + coord_t const* p2 = get_position(idx_p2); + + coord_t d0 = p1[0] - p2[0]; + coord_t d1 = p1[1] - p2[1]; + + const coord_t bboxW = bounds[2] - bounds[0]; + const coord_t bboxH = bounds[3] - bounds[1]; + + + bool a = std::abs(d0) > 0.5f * bboxW; + bool b = std::abs(d1) > 0.5f * bboxH; + + + const uint32_t flags_dist = ((std::abs(d0) > 0.5f * bboxW) << 0) | ((std::abs(d1) > 0.5f * bboxH) << 1); + const uint32_t flags_p2 = ((p2[0] > 0.5f * bboxW) << 0) | ((p2[1] > 0.5f * bboxH) << 1); + + + if (flags_dist & applyPBC::X && cycleX) { + const coord_t movedir = (flags_p2 & applyPBC::X) ? -1.0f : 1.0f; + d0 = p1[0] - (p2[0] + movedir*bboxW); + } + + if (flags_dist & applyPBC::Y && cycleY) { + const coord_t movedir = (flags_p2 & applyPBC::Y) ? -1.0f : 1.0f; + d1 = p1[1] - (p2[1] + movedir * bboxW); + } + + return d0 * d0 + d1 * d1; + } + + // Returns the dim'th component of the idx'th point in the class: + // Since this is inlined and the "dim" argument is typically an immediate value, the + // "if/else's" are actually solved at compile time. + inline coord_t kdtree_get_pt(const size_t idx, int dim) const { + assert((dim >= 0) && (dim < 2)); + return get_position(idx)[dim]; + } + + // Optional bounding-box computation: return false to default to a standard bbox computation loop. + // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo + // it again. Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) + template + bool kdtree_get_bbox(BBOX& /*bb*/) const { + return false; + } + + inline const coord_t* get_position(size_t index) const { + + return dat[index].data(); + } + +}; + +} From c833c3dc0580663996f3648cd0df389fc7ca4711 Mon Sep 17 00:00:00 2001 From: rauts Date: Mon, 24 Oct 2022 12:26:23 +0200 Subject: [PATCH 45/47] added relaxation algorithm in probe level generation --- plugins/probe/src/GenerateProbeLevels.cpp | 214 +++++++++++++++++++--- plugins/probe/src/GenerateProbeLevels.h | 24 ++- 2 files changed, 206 insertions(+), 32 deletions(-) diff --git a/plugins/probe/src/GenerateProbeLevels.cpp b/plugins/probe/src/GenerateProbeLevels.cpp index d25f2ac12f..1af001dcec 100644 --- a/plugins/probe/src/GenerateProbeLevels.cpp +++ b/plugins/probe/src/GenerateProbeLevels.cpp @@ -126,6 +126,11 @@ bool GenerateProbeLevels::getData(core::Call& call) { if (!calcMercatorProjection()) return false; + // apply force directed distribution + if (!doRelaxation()) { + return false; + } + // start with grouping from bottom left if (!calcLevels(rhs_probes->getData())) return false; @@ -179,8 +184,8 @@ bool GenerateProbeLevels::calcSphericalCoordinates() { return false; } - _probe_positions_spherical_coodrinates.clear(); - _probe_positions_spherical_coodrinates.resize(_probe_positions.size()); + _probe_positions_spherical_coordinates.clear(); + _probe_positions_spherical_coordinates.resize(_probe_positions.size()); for (int i = 0; i < _probe_positions.size(); ++i) { glm::vec3 const pos = glm::vec3(_probe_positions[i][0], _probe_positions[i][1], _probe_positions[i][2]) - glm::vec3(_center[0], _center[1], _center[2]); @@ -189,9 +194,9 @@ bool GenerateProbeLevels::calcSphericalCoordinates() { auto const theta = std::acosf(pos.z/ r); auto const phi = std::atan2f(pos.y, pos.x); - _probe_positions_spherical_coodrinates[i][0] = r; - _probe_positions_spherical_coodrinates[i][1] = theta; - _probe_positions_spherical_coodrinates[i][2] = phi; + _probe_positions_spherical_coordinates[i][0] = r; + _probe_positions_spherical_coordinates[i][1] = theta; + _probe_positions_spherical_coordinates[i][2] = phi; } return true; @@ -199,25 +204,37 @@ bool GenerateProbeLevels::calcSphericalCoordinates() { bool GenerateProbeLevels::calcMercatorProjection() { - if (_probe_positions_spherical_coodrinates.empty()) { + if (_probe_positions_spherical_coordinates.empty()) { core::utility::log::Log::DefaultLog.WriteError("[GenerateProbeLevels] Calculate spherical coordinates first. Abort."); return false; } _probe_positions_mercator.clear(); - _probe_positions_mercator.resize(_probe_positions_spherical_coodrinates.size()); + _probe_positions_mercator.resize(_probe_positions_spherical_coordinates.size()); - std::vector bounds(4); + std::array bounds; bounds[0] = std::numeric_limits::max(); bounds[1] = std::numeric_limits::max(); bounds[2] = std::numeric_limits::lowest(); bounds[3] = std::numeric_limits::lowest(); - for (int i = 0; i < _probe_positions_spherical_coodrinates.size(); i++) { + + constexpr float pi = 3.14159265359f; + + int inf_count = 0; + for (int i = 0; i < _probe_positions_spherical_coordinates.size(); i++) { // theta -> phi , phi -> lambda - auto const phi = _probe_positions_spherical_coodrinates[i][1]; - auto const lambda = _probe_positions_spherical_coodrinates[i][2]; + auto const phi = _probe_positions_spherical_coordinates[i][1]; + auto const lambda = _probe_positions_spherical_coordinates[i][2]; + + //_probe_positions_mercator[i][0] = lambda; + //_probe_positions_mercator[i][1] = 0.5f * std::logf((1.0f + std::sinf(phi)) / (1.0f - std::sinf(phi))); - _probe_positions_mercator[i][0] = lambda; - _probe_positions_mercator[i][1] = 0.5f * std::logf((1.0f + std::sinf(phi)) / (1.0f - std::sinf(phi))); + _probe_positions_mercator[i][0] = phi; + _probe_positions_mercator[i][1] = std::sin(lambda); + + if (!std::isfinite(_probe_positions_mercator[i][1])) { + _probe_positions_mercator[i][1] = std::copysignf(5.0f, _probe_positions_mercator[i][1]); + inf_count++; + } bounds[0] = std::min(bounds[0], _probe_positions_mercator[i][0]); bounds[1] = std::min(bounds[1], _probe_positions_mercator[i][1]); @@ -231,7 +248,9 @@ bool GenerateProbeLevels::calcMercatorProjection() { return true; } -bool GenerateProbeLevels::calcLevels(std::shared_ptr inputProbes) { +bool GenerateProbeLevels::calcLevels(std::shared_ptr inputProbes) { + + auto const rhs_probe = this->_probe_rhs_slot.CallAs(); if (_probe_positions_mercator.empty()) { return false; @@ -249,42 +268,86 @@ bool GenerateProbeLevels::calcLevels(std::shared_ptr inputProbe // span grid over projection and use one grid cell as first superlevel for (int i = 0; i < _probe_positions_mercator.size(); i ++) { - auto id_x = std::clamp(_probe_positions_mercator[i][0], _mercator_bounds[0], _mercator_bounds[2]) / - static_cast(grid_dim_x); - auto id_y = std::clamp(_probe_positions_mercator[i][1], _mercator_bounds[1], _mercator_bounds[3]) / - static_cast(grid_dim_y); + int id_x = grid_dim_x * + (_probe_positions_mercator[i][0] - _mercator_bounds[0]) / (_mercator_bounds[2] - _mercator_bounds[0]); + int id_y = grid_dim_y * + (_probe_positions_mercator[i][1] - _mercator_bounds[1]) / (_mercator_bounds[3] - _mercator_bounds[1]); + + id_x = (id_x == grid_dim_x) ? id_x - 1 : id_x; + id_y = (id_y == grid_dim_y) ? id_y - 1 : id_y; auto const n = grid_dim_x * id_y + id_x; level_by_id[n].emplace_back(i); } // generate level from level_by_id - ProbeCollection::ProbeLevel level; + ProbeCol::ProbeLevel level; + level.probes.reserve(level_by_id.size()); for (int n = 0; n < level_by_id.size(); n++) { if (level_by_id.empty()) { - core::utility::log::Log::DefaultLog.WriteError("[GenerateProbeLevels] Level found to be empty."); + core::utility::log::Log::DefaultLog.WriteWarn("[GenerateProbeLevels] Level found to be empty."); } + // since we do a relaxation, the mapping from projection to sphere is not bijective anymore + /* auto const id_x = n % grid_dim_x; auto const id_y = n / grid_dim_x; std::array level_midpoint = {id_x * grid_step_x + 0.5f * grid_step_x, id_y * grid_step_y + 0.5f * grid_step_y}; - auto const radius = _probe_positions_spherical_coodrinates[level_by_id[n][0]][0]; + auto const radius = _probe_positions_spherical_coordinates[level_by_id[n][0]][0]; auto const new_probe_pos_spherical = calcInverseMercatorProjection(level_midpoint, radius); auto const new_probe_pos = calcInverseSphericalProjection(new_probe_pos_spherical); + */ + + glm::vec3 probe_center_of_mass = {0.0f,0.0f,0.0f}; + for (auto const probe_id : level_by_id[n]) { + // calc center of mass + probe_center_of_mass[0] += _probe_positions[probe_id][0]; + probe_center_of_mass[1] += _probe_positions[probe_id][1]; + probe_center_of_mass[2] += _probe_positions[probe_id][2]; + } + probe_center_of_mass /= static_cast(level_by_id[n].size()); + + std::vector dists_to_com; + dists_to_com.reserve(level_by_id[n].size()); + for (auto const probe_id : level_by_id[n]) { + // calc dists to center of mass + dists_to_com.emplace_back(glm::length(probe_center_of_mass - to_vec3(_probe_positions[probe_id]))); + } + + auto min_element = std::min_element(dists_to_com.begin(), dists_to_com.end()); + auto min_element_pos = min_element - dists_to_com.begin(); + + auto const min_dist_id = level_by_id[n][min_element_pos]; if (std::holds_alternative(inputProbes->getGenericProbe(0))) { FloatDistributionProbe probe; - probe.m_position = new_probe_pos; - /// ... fill with meta data - - for (auto probe_id : level_by_id[n]) { - /// accumulate sample results - + probe = rhs_probe->getData()->getProbe(min_dist_id); + auto sampling_result = probe.getSamplingResult(); + float new_min = 0.0f; + float new_max = 0.0f; + float new_avg = 0.0f; + for (auto const probe_id : level_by_id[n]) { + auto const& current_probe = rhs_probe->getData()->getProbe(probe_id); + auto const& current_sampling_result = current_probe.getSamplingResult(); + new_min += current_sampling_result->min_value; + new_max += current_sampling_result->max_value; + new_avg += current_sampling_result->average_value; } + new_min /= static_cast(level_by_id[n].size()); + new_max /= static_cast(level_by_id[n].size()); + new_avg /= static_cast(level_by_id[n].size()); + + sampling_result->min_value = new_min; + sampling_result->max_value = new_max; + sampling_result->average_value = new_avg; + + level.probes.emplace_back(probe); + level.level_index = 0; + } else { - + // Vector distribution probe } } @@ -321,5 +384,100 @@ std::array GenerateProbeLevels::calcInverseSphericalProjection(std::ar return res; } +bool GenerateProbeLevels::doRelaxation() { + + auto const w = _mercator_bounds[2] - _mercator_bounds[0]; + auto const h = _mercator_bounds[3] - _mercator_bounds[1]; + + float delta_t = std::max(w,h) / 1000.0f; + + float const radius = std::min(w,h)/10.0f; + + int const iterations = 150; + + for (int n = 0; n < iterations; n++) { + + auto const old_probe_positions_mercator = _probe_positions_mercator; + + _probe_mercator_dataKD = + std::make_shared(_probe_positions_mercator, _mercator_bounds, true, true); + _probe_mercator_tree = std::make_shared( + 2 /*dim*/, *_probe_mercator_dataKD, nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */)); + _probe_mercator_tree->buildIndex(); + + for (int i = 0; i < _probe_positions_mercator.size(); i++) { + + auto& current_pos = _probe_positions_mercator[i]; + + std::vector> res; + auto num_neighbors = _probe_mercator_tree->radiusSearch( + _probe_positions_mercator[i].data(), std::powf(radius, 2), res, nanoflann::SearchParams()); + + // calc force and dir + glm::vec2 tot_force(0.0f, 0.0f); + for (auto const& neighbor : res) { + + auto const dist = std::sqrtf(neighbor.second); + // filter self interaction + if (dist < (radius / 1000.0f)) { + continue; + } + + // check if pbc has to be applied into force calculation + auto const hand_calced_dist = + glm::length(to_vec2(current_pos) - + to_vec2(_probe_positions_mercator[neighbor.first])); + auto neighbor_pos = to_vec2(_probe_positions_mercator[neighbor.first]); + if (hand_calced_dist > radius) { + // apply pbc + auto const dist_x = current_pos[0] - neighbor_pos[0]; + auto const dist_y = current_pos[1] - neighbor_pos[1]; + if ((std::abs(dist_x) > radius && dist_x > 0)) { + neighbor_pos[0] += w; + } else if ((std::abs(dist_x) > radius && dist_x < 0)) { + neighbor_pos[0] -= w; + } + + if ((std::abs(dist_y) > radius && dist_y > 0)) { + neighbor_pos[1] += h; + } else if ((std::abs(dist_y) > radius && dist_y < 0)) { + neighbor_pos[1] -= h; + } + } + + auto const dir = glm::normalize(to_vec2(current_pos) - neighbor_pos); + auto const current_force = coulomb_force(dist); + tot_force[0] += dir[0] * current_force; + tot_force[1] += dir[1] * current_force; + + } + // move the probe according to verlet + + current_pos[0] = 2 * current_pos[0] - + old_probe_positions_mercator[i][0] + + tot_force[0] * std::powf(delta_t, 2.0f); + current_pos[1] = 2 * current_pos[1] - + old_probe_positions_mercator[i][1] + + tot_force[1] * std::powf(delta_t, 2.0f); + + + + // check if repositioning would kick probe out of bounds + // since we use pbc in the neighbor search, the probes should not get kicked out too hard + if (current_pos[0] < _mercator_bounds[0] || + current_pos[1] < _mercator_bounds[1] || + current_pos[0] > _mercator_bounds[2] || + current_pos[1] > _mercator_bounds[3]) { + + // reset pos + current_pos = old_probe_positions_mercator[i]; + + } + } + } + + return true; +} + } // namespace probe } // namespace megamol diff --git a/plugins/probe/src/GenerateProbeLevels.h b/plugins/probe/src/GenerateProbeLevels.h index 3900745e6a..602f09d57a 100644 --- a/plugins/probe/src/GenerateProbeLevels.h +++ b/plugins/probe/src/GenerateProbeLevels.h @@ -17,11 +17,18 @@ #include "mmcore/param/ParamSlot.h" #include "probe/CallKDTree.h" #include "probe/ProbeCollection.h" +#include "PlaceProbes.h" + +#include "probe/PBCkdTree.h" +#include "DualMeshProbeSampling.h" namespace megamol { namespace probe { +inline glm::vec2 to_vec2(std::array input) { + return glm::vec2(input[0], input[1]); +} class GenerateProbeLevels : public core::Module { public: @@ -71,19 +78,28 @@ class GenerateProbeLevels : public core::Module { bool parameterChanged(core::param::ParamSlot& p); bool calcSphericalCoordinates(); bool calcMercatorProjection(); - bool calcLevels(std::shared_ptr inputProbes); + bool calcLevels(std::shared_ptr inputProbes); std::array calcInverseMercatorProjection(std::array const& coords, float const& r); std::array calcInverseSphericalProjection(std::array const& coords); + bool doRelaxation(); - std::vector _levels; + std::vector _levels; bool _recalc = false; std::shared_ptr _probe_tree; std::shared_ptr _probe_dataKD; + + typedef nanoflann::KDTreeSingleIndexAdaptor, PBC_adaptor, + 2 /* dim */> + my_2d_kd_tree_t; + + std::shared_ptr _probe_mercator_tree; + std::shared_ptr _probe_mercator_dataKD; + std::vector> _probe_positions; - std::vector> _probe_positions_spherical_coodrinates; + std::vector> _probe_positions_spherical_coordinates; std::vector> _probe_positions_mercator; - std::vector _mercator_bounds; + std::array _mercator_bounds; std::array _center; }; From 02178b96c15890145e16ac59138419743a7a5f2f Mon Sep 17 00:00:00 2001 From: rauts Date: Mon, 24 Oct 2022 12:27:58 +0200 Subject: [PATCH 46/47] put probe level depth as template param --- plugins/probe/include/probe/CallKDTree.h | 2 +- plugins/probe/include/probe/ProbeCalls.h | 4 ++-- plugins/probe/include/probe/ProbeCollection.h | 7 +++++-- plugins/probe/src/DualMeshProbeSampling.h | 2 +- plugins/probe/src/ElementSampling.cpp | 2 +- plugins/probe/src/ElementSampling.h | 2 +- plugins/probe/src/ExtractProbeGeometry.h | 2 +- plugins/probe/src/FilterProbes.cpp | 2 +- plugins/probe/src/FilterProbes.h | 2 +- plugins/probe/src/PlaceProbes.cpp | 4 ++-- plugins/probe/src/PlaceProbes.h | 2 +- plugins/probe/src/ProbeClustering.h | 2 +- plugins/probe/src/SampleAlongProbes.h | 2 +- plugins/probe/src/TableToProbes.cpp | 4 ++-- plugins/probe/src/TableToProbes.h | 2 +- 15 files changed, 22 insertions(+), 19 deletions(-) diff --git a/plugins/probe/include/probe/CallKDTree.h b/plugins/probe/include/probe/CallKDTree.h index 8fc6070f3c..b32f2ac63a 100644 --- a/plugins/probe/include/probe/CallKDTree.h +++ b/plugins/probe/include/probe/CallKDTree.h @@ -45,7 +45,7 @@ struct kd_adaptor { return false; } -}; // end of PointCloudAdaptor +}; typedef kd_adaptor>> data2KD; typedef nanoflann::KDTreeSingleIndexAdaptor, data2KD, 3 /* dim */> diff --git a/plugins/probe/include/probe/ProbeCalls.h b/plugins/probe/include/probe/ProbeCalls.h index d5a83d5893..28727a17e7 100644 --- a/plugins/probe/include/probe/ProbeCalls.h +++ b/plugins/probe/include/probe/ProbeCalls.h @@ -14,9 +14,9 @@ namespace megamol { namespace probe { -class CallProbes : public core::GenericVersionedCall, core::Spatial3DMetaData> { +class CallProbes : public core::GenericVersionedCall, core::Spatial3DMetaData> { public: - inline CallProbes() : GenericVersionedCall, core::Spatial3DMetaData>() {} + inline CallProbes() : GenericVersionedCall, core::Spatial3DMetaData>() {} ~CallProbes() = default; static const char* ClassName(void) { diff --git a/plugins/probe/include/probe/ProbeCollection.h b/plugins/probe/include/probe/ProbeCollection.h index e13a30151f..1c94490044 100644 --- a/plugins/probe/include/probe/ProbeCollection.h +++ b/plugins/probe/include/probe/ProbeCollection.h @@ -161,6 +161,7 @@ struct Vec4Probe : public BaseProbe { using GenericProbe = std::variant; using GenericMinMax = std::variant, std::array, std::array>; +template class ProbeCollection { public: struct ProbeLevel { @@ -300,12 +301,14 @@ class ProbeCollection { private: - std::array lod_collection; - int max_level = 3; + std::array lod_collection; + int max_level = NUM_LEVELS - 1; GenericMinMax m_global_min_max; }; +typedef ProbeCollection<> ProbeCol; + } // namespace probe } // namespace megamol diff --git a/plugins/probe/src/DualMeshProbeSampling.h b/plugins/probe/src/DualMeshProbeSampling.h index 8b44bb038f..e3b6d94761 100644 --- a/plugins/probe/src/DualMeshProbeSampling.h +++ b/plugins/probe/src/DualMeshProbeSampling.h @@ -119,7 +119,7 @@ class DualMeshProbeSampling : public core::Module { bool getParticleMetaData(core::Call& call); bool getParticleData(core::Call& call); - std::shared_ptr _probes; + std::shared_ptr _probes; size_t _old_datahash; size_t _old_volume_datahash; diff --git a/plugins/probe/src/ElementSampling.cpp b/plugins/probe/src/ElementSampling.cpp index 9590869d81..60a85655f1 100644 --- a/plugins/probe/src/ElementSampling.cpp +++ b/plugins/probe/src/ElementSampling.cpp @@ -78,7 +78,7 @@ ElementSampling::~ElementSampling() { } bool ElementSampling::create() { - _probes = std::make_shared(); + _probes = std::make_shared(); return true; } diff --git a/plugins/probe/src/ElementSampling.h b/plugins/probe/src/ElementSampling.h index 5b0f809b4c..48821cfa1a 100644 --- a/plugins/probe/src/ElementSampling.h +++ b/plugins/probe/src/ElementSampling.h @@ -99,7 +99,7 @@ class ElementSampling : public core::Module { void do_triangulation(Surface_mesh& mesh_); void placeProbes(const std::vector>& elements); - std::shared_ptr _probes; + std::shared_ptr _probes; size_t _old_datahash; bool _trigger_recalc; diff --git a/plugins/probe/src/ExtractProbeGeometry.h b/plugins/probe/src/ExtractProbeGeometry.h index 833e575aef..db563f0ea6 100644 --- a/plugins/probe/src/ExtractProbeGeometry.h +++ b/plugins/probe/src/ExtractProbeGeometry.h @@ -67,7 +67,7 @@ class ExtractProbeGeometry : public core::Module { uint32_t _version; - std::shared_ptr _probes; + std::shared_ptr _probes; std::shared_ptr _line; std::vector> _line_attribs; diff --git a/plugins/probe/src/FilterProbes.cpp b/plugins/probe/src/FilterProbes.cpp index cf6bfb0365..d79939e410 100644 --- a/plugins/probe/src/FilterProbes.cpp +++ b/plugins/probe/src/FilterProbes.cpp @@ -64,7 +64,7 @@ bool FilterProbes::getData(core::Call& call) { if (rhs_dirty || _recalc) { ++_version; _recalc = false; - _filtered_probe_collection = std::make_shared(); + _filtered_probe_collection = std::make_shared(); auto const probe_count = rhsProbesCall->getData()->getProbeCount(); auto const probes = rhsProbesCall->getData(); diff --git a/plugins/probe/src/FilterProbes.h b/plugins/probe/src/FilterProbes.h index 0d2fd2cf7a..f900de5b2f 100644 --- a/plugins/probe/src/FilterProbes.h +++ b/plugins/probe/src/FilterProbes.h @@ -80,7 +80,7 @@ class FilterProbes : public core::Module { float getDistance(std::array const& point1, std::array const& point2); bool newPosDir(int const id_filtered, int const id_all); - std::shared_ptr _filtered_probe_collection; + std::shared_ptr _filtered_probe_collection; bool _recalc; }; diff --git a/plugins/probe/src/PlaceProbes.cpp b/plugins/probe/src/PlaceProbes.cpp index 09bc0887f9..a4d52abf5c 100644 --- a/plugins/probe/src/PlaceProbes.cpp +++ b/plugins/probe/src/PlaceProbes.cpp @@ -89,7 +89,7 @@ megamol::probe::PlaceProbes::PlaceProbes() this->MakeSlotAvailable(&this->_skip_edges_corers_slot); /* Feasibility test */ - _probes = std::make_shared(); + _probes = std::make_shared(); _probes->addProbe(FloatProbe()); auto retrieved_probe = _probes->getProbe(0); @@ -649,7 +649,7 @@ void PlaceProbes::faceNormalSampling(mesh::MeshDataAccessCollection::VertexAttri bool megamol::probe::PlaceProbes::placeProbes() { - _probes = std::make_shared(); + _probes = std::make_shared(); //assert(_mesh->accessMeshes().size() == 1); diff --git a/plugins/probe/src/PlaceProbes.h b/plugins/probe/src/PlaceProbes.h index 45931a37a1..cd8cd19e04 100644 --- a/plugins/probe/src/PlaceProbes.h +++ b/plugins/probe/src/PlaceProbes.h @@ -109,7 +109,7 @@ class PlaceProbes : public core::Module { uint32_t _longest_edge_index; - std::shared_ptr _probes; + std::shared_ptr _probes; std::shared_ptr _mesh; std::shared_ptr _centerline; std::array _whd; diff --git a/plugins/probe/src/ProbeClustering.h b/plugins/probe/src/ProbeClustering.h index c606c86d48..c32bd196b8 100644 --- a/plugins/probe/src/ProbeClustering.h +++ b/plugins/probe/src/ProbeClustering.h @@ -142,7 +142,7 @@ class ProbeClustering : public core::Module { std::shared_ptr> _kd_tree; - std::shared_ptr _probes = nullptr; + std::shared_ptr _probes = nullptr; float const* _sim_matrix = nullptr; diff --git a/plugins/probe/src/SampleAlongProbes.h b/plugins/probe/src/SampleAlongProbes.h index d769648adb..4b487505cb 100644 --- a/plugins/probe/src/SampleAlongProbes.h +++ b/plugins/probe/src/SampleAlongProbes.h @@ -127,7 +127,7 @@ class SampleAlongPobes : public core::Module { bool getMetaData(core::Call& call); - std::shared_ptr _probes; + std::shared_ptr _probes; const geocalls::VolumetricDataCall::Metadata* _vol_metadata; diff --git a/plugins/probe/src/TableToProbes.cpp b/plugins/probe/src/TableToProbes.cpp index a838ae3b3d..b35ddce51e 100644 --- a/plugins/probe/src/TableToProbes.cpp +++ b/plugins/probe/src/TableToProbes.cpp @@ -33,7 +33,7 @@ megamol::probe::TableToProbes::TableToProbes() this->MakeSlotAvailable(&this->_accumulate_clustered_slot); /* Feasibility test */ - _probes = std::make_shared(); + _probes = std::make_shared(); _probes->addProbe(FloatProbe()); auto retrieved_probe = _probes->getProbe(0); @@ -119,7 +119,7 @@ bool megamol::probe::TableToProbes::getMetaData(core::Call& call) { bool megamol::probe::TableToProbes::generateProbes() { - _probes = std::make_shared(); + _probes = std::make_shared(); assert(_table != nullptr); diff --git a/plugins/probe/src/TableToProbes.h b/plugins/probe/src/TableToProbes.h index 3d1fe99edc..fa39e25154 100644 --- a/plugins/probe/src/TableToProbes.h +++ b/plugins/probe/src/TableToProbes.h @@ -77,7 +77,7 @@ class TableToProbes : public core::Module { const datatools::table::TableDataCall::ColumnInfo* _col_info; uint32_t _num_cols; uint32_t _num_rows; - std::shared_ptr _probes; + std::shared_ptr _probes; std::array _whd; core::BoundingBoxes_2 _bbox; From a6156fa1a77b37a93b7e79c74df4719fa8b89adb Mon Sep 17 00:00:00 2001 From: rauts Date: Mon, 24 Oct 2022 12:34:26 +0200 Subject: [PATCH 47/47] added sub probes to first level --- plugins/probe/src/GenerateProbeLevels.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/probe/src/GenerateProbeLevels.cpp b/plugins/probe/src/GenerateProbeLevels.cpp index 1af001dcec..665aafec53 100644 --- a/plugins/probe/src/GenerateProbeLevels.cpp +++ b/plugins/probe/src/GenerateProbeLevels.cpp @@ -345,6 +345,7 @@ bool GenerateProbeLevels::calcLevels(std::shared_ptr inputProbes) { level.probes.emplace_back(probe); level.level_index = 0; + level.sub_probes = level_by_id; } else { // Vector distribution probe