diff --git a/cmake/recipes/tests/wmtk_data.cmake b/cmake/recipes/tests/wmtk_data.cmake index 1a0c746724..b82212ca0a 100644 --- a/cmake/recipes/tests/wmtk_data.cmake +++ b/cmake/recipes/tests/wmtk_data.cmake @@ -16,7 +16,7 @@ ExternalProject_Add( SOURCE_DIR ${WMTK_DATA_ROOT} GIT_REPOSITORY https://github.com/wildmeshing/data.git - GIT_TAG b9c1a6e86538556bdf1395c2d9941a2b9aa009ec + GIT_TAG 696fe0f17523a711ded54515dd036116da7fefd4 CONFIGURE_COMMAND "" BUILD_COMMAND "" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 8ad115d730..d75c1d9dda 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -55,6 +55,8 @@ add_component(${WMTK_COMPONENT_PREFIX} "wildmeshing") add_component(${WMTK_COMPONENT_PREFIX} "get_all_meshes") add_component(${WMTK_COMPONENT_PREFIX} "procedural") add_component(${WMTK_COMPONENT_PREFIX} "fusion") +add_component(${WMTK_COMPONENT_PREFIX} "triangle_insertion") +add_component(${WMTK_COMPONENT_PREFIX} "to_points") string(LENGTH ${json_components} json_components_length) math(EXPR json_components_length "${json_components_length}-2") diff --git a/components/tests/integration_test_list.txt b/components/tests/integration_test_list.txt index d51743c1fe..42ab7c81ae 100644 --- a/components/tests/integration_test_list.txt +++ b/components/tests/integration_test_list.txt @@ -1,4 +1,7 @@ unit_test/input.json +unit_test/to_points.json +unit_test/delaunay.json +unit_test/insertion.json unit_test/multimesh.json unit_test/multimesh_boundary_2d.json unit_test/multimesh_boundary_3d.json diff --git a/components/tests/test_component_to_points.cpp b/components/tests/test_component_to_points.cpp new file mode 100644 index 0000000000..0ffdd02fcb --- /dev/null +++ b/components/tests/test_component_to_points.cpp @@ -0,0 +1 @@ +// TODO \ No newline at end of file diff --git a/components/tests/test_component_triangle_insertion.cpp b/components/tests/test_component_triangle_insertion.cpp new file mode 100644 index 0000000000..0ffdd02fcb --- /dev/null +++ b/components/tests/test_component_triangle_insertion.cpp @@ -0,0 +1 @@ +// TODO \ No newline at end of file diff --git a/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay.cpp b/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay.cpp index 8c64c6eb19..1f27a275e6 100644 --- a/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay.cpp +++ b/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay.cpp @@ -13,9 +13,9 @@ namespace wmtk::components { template -RowVectors points_to_rowvectors(PointMesh& point_cloud) +RowVectors points_to_rowvectors(const std::string& position, PointMesh& point_cloud) { - auto pts_attr = point_cloud.get_attribute_handle("vertices", PrimitiveType::Vertex); + auto pts_attr = point_cloud.get_attribute_handle(position, PrimitiveType::Vertex); auto pts_acc = point_cloud.create_accessor(pts_attr); const auto vertices = point_cloud.get_all(PrimitiveType::Vertex); @@ -51,7 +51,8 @@ void delaunay_exec(const internal::DelaunayOptions& options, io::Cache& cache) // make sure dimensions fit { - auto pts_attr = point_cloud.get_attribute_handle("vertices", PrimitiveType::Vertex); + auto pts_attr = + point_cloud.get_attribute_handle(options.position, PrimitiveType::Vertex); auto pts_acc = point_cloud.create_accessor(pts_attr); assert(pts_acc.dimension() == options.cell_dimension); } @@ -63,7 +64,7 @@ void delaunay_exec(const internal::DelaunayOptions& options, io::Cache& cache) MeshT mesh; Eigen::MatrixXd vertices; Eigen::MatrixXi faces; - const auto pts_vec = points_to_rowvectors(point_cloud); + const auto pts_vec = points_to_rowvectors(options.position, point_cloud); if constexpr (D == 2) { std::tie(vertices, faces) = internal::delaunay_2d(pts_vec); } else if constexpr (D == 3) { @@ -73,7 +74,7 @@ void delaunay_exec(const internal::DelaunayOptions& options, io::Cache& cache) } mesh.initialize(faces.cast()); - mesh_utils::set_matrix_attribute(vertices, "vertices", PrimitiveType::Vertex, mesh); + mesh_utils::set_matrix_attribute(vertices, options.position, PrimitiveType::Vertex, mesh); cache.write_mesh(mesh, options.output); } diff --git a/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay_spec.json b/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay_spec.json index b56397d653..3f92ed2168 100644 --- a/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay_spec.json +++ b/components/wmtk_components/delaunay/wmtk/components/delaunay/delaunay_spec.json @@ -4,6 +4,7 @@ "type": "object", "required": [ "input", + "position", "output", "cell_dimension" ] @@ -13,6 +14,11 @@ "type": "string", "doc": "input mesh" }, + { + "pointer": "/position", + "type": "string", + "doc": "position" + }, { "pointer": "/output", "type": "string", diff --git a/components/wmtk_components/delaunay/wmtk/components/delaunay/internal/DelaunayOptions.hpp b/components/wmtk_components/delaunay/wmtk/components/delaunay/internal/DelaunayOptions.hpp index 78576bd2aa..86aba807a2 100644 --- a/components/wmtk_components/delaunay/wmtk/components/delaunay/internal/DelaunayOptions.hpp +++ b/components/wmtk_components/delaunay/wmtk/components/delaunay/internal/DelaunayOptions.hpp @@ -9,11 +9,12 @@ namespace internal { struct DelaunayOptions { std::string input; + std::string position; std::string output; int64_t cell_dimension; }; -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DelaunayOptions, input, output, cell_dimension); +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DelaunayOptions, input, output, position, cell_dimension); } // namespace internal } // namespace components diff --git a/components/wmtk_components/to_points/wmtk/components/to_points/CMakeLists.txt b/components/wmtk_components/to_points/wmtk/components/to_points/CMakeLists.txt new file mode 100644 index 0000000000..774cf180bf --- /dev/null +++ b/components/wmtk_components/to_points/wmtk/components/to_points/CMakeLists.txt @@ -0,0 +1,9 @@ + +set(SRC_FILES + ToPtsOptions.hpp + to_points.hpp + to_points.cpp) + + +#CURRENT_COMPONENT_LIB_NAME is set from the main cmake +target_sources(${CURRENT_COMPONENT_LIB_NAME} PRIVATE ${SRC_FILES}) \ No newline at end of file diff --git a/components/wmtk_components/to_points/wmtk/components/to_points/ToPtsOptions.hpp b/components/wmtk_components/to_points/wmtk/components/to_points/ToPtsOptions.hpp new file mode 100644 index 0000000000..e442caf457 --- /dev/null +++ b/components/wmtk_components/to_points/wmtk/components/to_points/ToPtsOptions.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace wmtk::components { + + +struct ToPtsOptions +{ + std::string input; + std::string position; + std::string name; + bool add_box; + double box_scale; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ToPtsOptions, input, position, name, add_box, box_scale); + +} // namespace wmtk::components diff --git a/components/wmtk_components/to_points/wmtk/components/to_points/to_points.cpp b/components/wmtk_components/to_points/wmtk/components/to_points/to_points.cpp new file mode 100644 index 0000000000..e67f0e1a06 --- /dev/null +++ b/components/wmtk_components/to_points/wmtk/components/to_points/to_points.cpp @@ -0,0 +1,62 @@ +#include "to_points.hpp" + + +#include "ToPtsOptions.hpp" + +#include + +#include +#include +#include + +namespace wmtk::components { + +void to_points(const base::Paths& paths, const nlohmann::json& j, io::Cache& cache) +{ + ToPtsOptions options = j.get(); + + const std::shared_ptr mesh_in = cache.read_mesh(options.input); + const Mesh& mesh = *mesh_in; + + const auto pts_attr = + mesh.get_attribute_handle(options.position, PrimitiveType::Vertex); + const auto pts_acc = mesh.create_const_accessor(pts_attr); + const auto vs = mesh.get_all(PrimitiveType::Vertex); + + Eigen::AlignedBox bbox(pts_acc.dimension()); + + int64_t box_size = std::pow(2, pts_acc.dimension()); + + + Eigen::MatrixXd pts(vs.size() + (options.add_box ? box_size : 0), pts_acc.dimension()); + int64_t index = 0; + for (const auto& v : vs) { + pts.row(index) << pts_acc.const_vector_attribute(v).transpose(); + bbox.extend(pts.row(index).transpose()); + ++index; + } + + if (options.add_box) { + auto center = bbox.center(); + auto r = bbox.diagonal() / 2.; + + bbox.min() = center - options.box_scale * r; + bbox.max() = center + options.box_scale * r; + + for (int64_t d = 0; d < box_size; ++d) { + std::bitset<32> bits = d; + for (int64_t i = 0; i < pts.cols(); ++i) { + pts(index, i) = bits[i] == 0 ? bbox.min()[i] : bbox.max()[i]; + } + ++index; + } + } + + PointMesh pts_mesh(pts.rows()); + + mesh_utils::set_matrix_attribute(pts, options.position, PrimitiveType::Vertex, pts_mesh); + + cache.write_mesh(pts_mesh, options.name); +} + +} // namespace wmtk::components \ No newline at end of file diff --git a/components/wmtk_components/to_points/wmtk/components/to_points/to_points.hpp b/components/wmtk_components/to_points/wmtk/components/to_points/to_points.hpp new file mode 100644 index 0000000000..2b4a9e3892 --- /dev/null +++ b/components/wmtk_components/to_points/wmtk/components/to_points/to_points.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#include + +namespace wmtk::components { + +void to_points(const base::Paths& paths, const nlohmann::json& j, io::Cache& cache); + +} // namespace wmtk::components diff --git a/components/wmtk_components/to_points/wmtk/components/to_points/to_points_spec.json b/components/wmtk_components/to_points/wmtk/components/to_points/to_points_spec.json new file mode 100644 index 0000000000..aae87c2631 --- /dev/null +++ b/components/wmtk_components/to_points/wmtk/components/to_points/to_points_spec.json @@ -0,0 +1,37 @@ +[ + { + "pointer": "/", + "type": "object", + "required": [ + "input", + "position", + "name" + ], + "optional": [ + "add_box", + "box_scale" + ] + }, + { + "pointer": "/input", + "type": "string" + }, + { + "pointer": "/position", + "type": "string" + }, + { + "pointer": "/name", + "type": "string" + }, + { + "pointer": "/add_box", + "type": "bool", + "default": false + }, + { + "pointer": "/box_scale", + "type": "float", + "default": 1 + } +] \ No newline at end of file diff --git a/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/CMakeLists.txt b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/CMakeLists.txt new file mode 100644 index 0000000000..4f9a126be9 --- /dev/null +++ b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/CMakeLists.txt @@ -0,0 +1,9 @@ + +set(SRC_FILES + TriInsOptions.hpp + triangle_insertion.hpp + triangle_insertion.cpp) + + +#CURRENT_COMPONENT_LIB_NAME is set from the main cmake +target_sources(${CURRENT_COMPONENT_LIB_NAME} PRIVATE ${SRC_FILES}) \ No newline at end of file diff --git a/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/TriInsOptions.hpp b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/TriInsOptions.hpp new file mode 100644 index 0000000000..d2f78dc20d --- /dev/null +++ b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/TriInsOptions.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace wmtk::components { +struct TriInsOptions +{ + std::string input; + std::string input_position; + std::string background; + std::string background_position; + std::string name; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( + TriInsOptions, + input, + input_position, + background, + background_position, + name); + +} // namespace wmtk::components diff --git a/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion.cpp b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion.cpp new file mode 100644 index 0000000000..d4e0b6f1d4 --- /dev/null +++ b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion.cpp @@ -0,0 +1,71 @@ +#include "triangle_insertion.hpp" + +#include "TriInsOptions.hpp" + +#include +#include +#include + + +#include +#include +#include + +namespace wmtk::components { + +void triangle_insertion(const base::Paths& paths, const nlohmann::json& j, io::Cache& cache) +{ + TriInsOptions options = j.get(); + + std::shared_ptr mesh_in = cache.read_mesh(options.input); + std::shared_ptr bg_mesh = cache.read_mesh(options.background); + + if (mesh_in->top_simplex_type() != PrimitiveType::Face) + log_and_throw_error("triangle_insertion supports only triangle meshes"); + if (bg_mesh->top_simplex_type() != PrimitiveType::Tetrahedron) + log_and_throw_error("triangle_insertion supports only bg tet meshes"); + + + wmtk::utils::EigenMatrixWriter writer; + mesh_in->serialize(writer); + + + wmtk::utils::EigenMatrixWriter writer_bg; + bg_mesh->serialize(writer_bg); + + Eigen::MatrixXd V; + writer.get_double_matrix(options.input_position, PrimitiveType::Vertex, V); + + Eigen::MatrixX F; + writer.get_FV_matrix(F); + + + Eigen::MatrixXd Vbg; + writer_bg.get_double_matrix(options.background_position, PrimitiveType::Vertex, Vbg); + + Eigen::MatrixX Fbg; + writer_bg.get_TV_matrix(Fbg); + + auto [tetmesh, facemesh] = + utils::generate_raw_tetmesh_with_surface_from_input(V, F, 0.1, Vbg, Fbg); + auto pt_attribute = + tetmesh->get_attribute_handle(options.input_position, PrimitiveType::Vertex); + auto child_position_handle = facemesh->register_attribute( + options.input_position, + PrimitiveType::Vertex, + tetmesh->get_attribute_dimension(pt_attribute.as())); + + auto propagate_to_child_position = [](const Eigen::MatrixXd& P) -> Eigen::VectorXd { + return P; + }; + auto update_child_positon = + std::make_shared>( + child_position_handle, + pt_attribute, + propagate_to_child_position); + update_child_positon->run_on_all(); + + cache.write_mesh(*tetmesh, options.name); +} + +} // namespace wmtk::components \ No newline at end of file diff --git a/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion.hpp b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion.hpp new file mode 100644 index 0000000000..8573f02d62 --- /dev/null +++ b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include + +namespace wmtk { +namespace components { + +void triangle_insertion(const base::Paths& paths, const nlohmann::json& j, io::Cache& cache); + +} // namespace components +} // namespace wmtk \ No newline at end of file diff --git a/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion_spec.json b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion_spec.json new file mode 100644 index 0000000000..c4c0cf8c6b --- /dev/null +++ b/components/wmtk_components/triangle_insertion/wmtk/components/triangle_insertion/triangle_insertion_spec.json @@ -0,0 +1,33 @@ +[ + { + "pointer": "/", + "type": "object", + "required": [ + "input", + "input_position", + "background", + "background_position", + "name" + ] + }, + { + "pointer": "/input", + "type": "string" + }, + { + "pointer": "/input_position", + "type": "string" + }, + { + "pointer": "/background", + "type": "string" + }, + { + "pointer": "/background_position", + "type": "string" + }, + { + "pointer": "/name", + "type": "string" + } +] \ No newline at end of file diff --git a/src/wmtk/utils/VolumeRemesherTriangleInsertion.cpp b/src/wmtk/utils/VolumeRemesherTriangleInsertion.cpp index bc31c59a3c..b755f40ce0 100644 --- a/src/wmtk/utils/VolumeRemesherTriangleInsertion.cpp +++ b/src/wmtk/utils/VolumeRemesherTriangleInsertion.cpp @@ -133,7 +133,9 @@ std::tuple, std::vector>> generate_raw_tetmesh_from_input_surface( const RowVectors3d& V, const RowVectors3l& F, - const double eps_target) + const double eps_target, + const RowVectors3d& bgV, + const RowVectors4l& bgT) { // for predicates exactinit(); @@ -157,13 +159,20 @@ generate_raw_tetmesh_from_input_surface( // generate background mesh RowVectors4l background_TV; RowVectors3d background_V; - generate_background_mesh(bbox_min, bbox_max, resolution, background_TV, background_V); + if (bgV.size() == 0) { + generate_background_mesh(bbox_min, bbox_max, resolution, background_TV, background_V); + + wmtk::logger().info( + "generated background mesh with resolution {} {} {}", + resolution[0], + resolution[1], + resolution[2]); + } else { + assert(bgT.size() != 0); + background_TV = bgT; + background_V = bgV; + } - wmtk::logger().info( - "generated background mesh with resolution {} {} {}", - resolution[0], - resolution[1], - resolution[2]); // prepare data for volume remesher // inputs @@ -387,7 +396,22 @@ generate_raw_tetmesh_from_input_surface( v_coords[tetra[1]].data(), v_coords[tetra[2]].data(), v_coords[tetra[3]].data()) <= 0) { - throw std::runtime_error("flipped tet crash"); + Eigen::Matrix3d tmp; + tmp.col(0) = v_coords[tetra[1]] - v_coords[tetra[0]]; + tmp.col(1) = v_coords[tetra[2]] - v_coords[tetra[0]]; + tmp.col(2) = v_coords[tetra[3]] - v_coords[tetra[0]]; + log_and_throw_error( + "flipped tet=({},{},{},{}) crash vol={} orient={}", + tetra[0], + tetra[1], + tetra[2], + tetra[3], + tmp.determinant(), + orient3d( + v_coords[tetra[0]].data(), + v_coords[tetra[1]].data(), + v_coords[tetra[2]].data(), + v_coords[tetra[3]].data())); } // push the tet to final queue; @@ -467,7 +491,27 @@ generate_raw_tetmesh_from_input_surface( v_coords[tetra[1]].data(), v_coords[tetra[2]].data(), v_coords[tetra[3]].data()) <= 0) { - throw std::runtime_error("flipped tet crash"); + Eigen::Matrix3d tmp; + tmp.col(0) = v_coords[tetra[1]] - v_coords[tetra[0]]; + tmp.col(1) = v_coords[tetra[2]] - v_coords[tetra[0]]; + tmp.col(2) = v_coords[tetra[3]] - v_coords[tetra[0]]; + log_and_throw_error( + "flipped for poly tet=({},{},{},{}) crash vol={} orient={}. Coords {} {} " + "{} {}", + tetra[0], + tetra[1], + tetra[2], + tetra[3], + tmp.determinant(), + orient3d( + v_coords[tetra[0]].data(), + v_coords[tetra[1]].data(), + v_coords[tetra[2]].data(), + v_coords[tetra[3]].data()), + v_coords[tetra[0]].transpose(), + v_coords[tetra[1]].transpose(), + v_coords[tetra[2]].transpose(), + v_coords[tetra[3]].transpose()); } tets_final.push_back(tetra); @@ -533,7 +577,9 @@ std::tuple, std::shared_ptr> generate_raw_tetmesh_with_surface_from_input( const RowVectors3d& V, const RowVectors3l& F, - const double eps_target) + const double eps_target, + const RowVectors3d& bgV, + const RowVectors4l& bgF) { constexpr static PrimitiveType PV = PrimitiveType::Vertex; constexpr static PrimitiveType PE = PrimitiveType::Edge; @@ -541,7 +587,7 @@ generate_raw_tetmesh_with_surface_from_input( constexpr static PrimitiveType PT = PrimitiveType::Tetrahedron; auto [tetmesh, tet_face_on_input_surface] = - generate_raw_tetmesh_from_input_surface(V, F, eps_target); + generate_raw_tetmesh_from_input_surface(V, F, eps_target, bgV, bgF); auto surface_handle = tetmesh->register_attribute("surface", PrimitiveType::Face, 1); auto surface_accessor = tetmesh->create_accessor(surface_handle); diff --git a/src/wmtk/utils/VolumeRemesherTriangleInsertion.hpp b/src/wmtk/utils/VolumeRemesherTriangleInsertion.hpp index b109503586..adccde18fe 100644 --- a/src/wmtk/utils/VolumeRemesherTriangleInsertion.hpp +++ b/src/wmtk/utils/VolumeRemesherTriangleInsertion.hpp @@ -15,7 +15,9 @@ std::tuple, std::shared_ptr> generate_raw_tetmesh_with_surface_from_input( const RowVectors3d& V, const RowVectors3l& F, - const double eps_target); + const double eps_target, + const RowVectors3d& bgV = RowVectors3d(), + const RowVectors4l& bgF = RowVectors4l()); /** * @brief input a triangle surface mesh, embed it into a regular grid and generate a tetmesh, @@ -31,7 +33,9 @@ std::tuple, std::vector>> generate_raw_tetmesh_from_input_surface( const RowVectors3d& V, const RowVectors3l& F, - const double eps_target); + const double eps_target, + const RowVectors3d& bgV = RowVectors3d(), + const RowVectors4l& bgF = RowVectors4l()); } // namespace wmtk::utils