├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── TODO.md ├── core ├── CMakeLists.txt ├── include │ └── HMP │ │ ├── Actions │ │ ├── Delete.hpp │ │ ├── DeleteSome.hpp │ │ ├── Extrude.hpp │ │ ├── ExtrudeUtils.hpp │ │ ├── FitCircle.hpp │ │ ├── MakeConforming.hpp │ │ ├── Pad.hpp │ │ ├── Paste.hpp │ │ ├── Project.hpp │ │ ├── Refine.hpp │ │ ├── RefineSome.hpp │ │ ├── Root.hpp │ │ ├── Smooth.hpp │ │ ├── SplitPlane.hpp │ │ ├── SubdivideAll.hpp │ │ └── Transform.hpp │ │ ├── Commander.hpp │ │ ├── Dag │ │ ├── Delete.hpp │ │ ├── Element.hpp │ │ ├── Extrude.hpp │ │ ├── Node.hpp │ │ ├── Node.tpp │ │ ├── NodeHandle.hpp │ │ ├── NodeHandle.tpp │ │ ├── NodeSet.hpp │ │ ├── NodeSet.tpp │ │ ├── Operation.hpp │ │ ├── Refine.hpp │ │ └── Utils.hpp │ │ ├── Meshing │ │ ├── Mesher.hpp │ │ ├── Utils.hpp │ │ ├── Utils.tpp │ │ └── types.hpp │ │ ├── Project.hpp │ │ ├── Projection │ │ ├── Match.hpp │ │ ├── Utils.hpp │ │ ├── Utils.tpp │ │ ├── altProject.hpp │ │ ├── fill.hpp │ │ ├── jacobianAdvance.hpp │ │ ├── percentileAdvance.hpp │ │ ├── project.hpp │ │ └── smooth.hpp │ │ ├── Refinement │ │ ├── Scheme.hpp │ │ ├── Schemes.hpp │ │ ├── Sub3x3AdapterCandidate.hpp │ │ ├── Sub3x3AdapterCandidateSet.hpp │ │ └── Utils.hpp │ │ └── Utils │ │ ├── DerefRanged.hpp │ │ ├── MapRanged.hpp │ │ └── Serialization.hpp └── src │ ├── Actions │ ├── Delete.cpp │ ├── DeleteSome.cpp │ ├── Extrude.cpp │ ├── ExtrudeUtils.cpp │ ├── FitCircle.cpp │ ├── MakeConforming.cpp │ ├── Pad.cpp │ ├── Paste.cpp │ ├── Project.cpp │ ├── Refine.cpp │ ├── RefineSome.cpp │ ├── Root.cpp │ ├── Smooth.cpp │ ├── SplitPlane.cpp │ ├── SubdivideAll.cpp │ └── Transform.cpp │ ├── Commander.cpp │ ├── Dag │ ├── Delete.cpp │ ├── Element.cpp │ ├── Extrude.cpp │ ├── Node.cpp │ ├── NodeSet.cpp │ ├── Operation.cpp │ ├── Refine.cpp │ └── Utils.cpp │ ├── Meshing │ ├── Mesher.cpp │ └── Utils.cpp │ ├── Project.cpp │ ├── Projection │ ├── Match.cpp │ ├── Utils.cpp │ ├── altProject.cpp │ ├── fill.cpp │ ├── jacobianAdvance.cpp │ ├── percentileAdvance.cpp │ ├── project.cpp │ └── smooth.cpp │ ├── Refinement │ ├── Scheme.cpp │ ├── Schemes.cpp │ ├── Sub3x3AdapterCandidate.cpp │ ├── Sub3x3AdapterCandidateSet.cpp │ └── Utils.cpp │ └── Utils │ └── Serialization.cpp ├── gui ├── CMakeLists.txt ├── include │ └── HMP │ │ └── Gui │ │ ├── App.hpp │ │ ├── DagViewer │ │ ├── Layout.hpp │ │ ├── Widget.hpp │ │ └── createLayout.hpp │ │ ├── SidebarWidget.hpp │ │ ├── Utils │ │ ├── Controls.hpp │ │ ├── Controls.tpp │ │ ├── Drawing.hpp │ │ ├── FilePicking.hpp │ │ ├── HrDescriptions.hpp │ │ ├── Theme.hpp │ │ ├── Themer.hpp │ │ └── Transform.hpp │ │ ├── Widget.hpp │ │ ├── Widgets │ │ ├── Actions.hpp │ │ ├── Ae3d2ShapeExporter.hpp │ │ ├── Axes.hpp │ │ ├── Commander.hpp │ │ ├── Debug.hpp │ │ ├── DirectVertEdit.hpp │ │ ├── Highlight.hpp │ │ ├── Pad.hpp │ │ ├── Projection.hpp │ │ ├── Projection.tpp │ │ ├── Save.hpp │ │ ├── Smooth.hpp │ │ ├── Target.hpp │ │ └── VertEdit.hpp │ │ └── themer.hpp └── src │ ├── App.cpp │ ├── DagViewer │ ├── Layout.cpp │ ├── Widget.cpp │ └── createLayout.cpp │ ├── SidebarWidget.cpp │ ├── Utils │ ├── Controls.cpp │ ├── Drawing.cpp │ ├── FilePicking.cpp │ ├── HrDescriptions.cpp │ ├── Theme.cpp │ ├── Themer.cpp │ └── Transform.cpp │ ├── Widget.cpp │ ├── Widgets │ ├── Actions.cpp │ ├── Ae3d2ShapeExporter.cpp │ ├── Axes.cpp │ ├── Commander.cpp │ ├── Debug.cpp │ ├── DirectVertEdit.cpp │ ├── Highlight.cpp │ ├── Pad.cpp │ ├── Projection.cpp │ ├── Save.cpp │ ├── Smooth.cpp │ ├── Target.cpp │ └── VertEdit.cpp │ ├── main.cpp │ └── themer.cpp ├── models.zip ├── models ├── Fig1 │ └── Cow.mesh ├── Fig12 │ ├── CAD10.mesh │ ├── CAD11.mesh │ ├── CAD2.mesh │ ├── CAD3.mesh │ ├── CAD4.mesh │ ├── CAD6.mesh │ ├── CAD9.mesh │ ├── Cogwheel2.mesh │ ├── Curve.mesh │ ├── Cylinders1.mesh │ └── Rocket.mesh ├── Fig13 │ ├── Block.mesh │ ├── CAD1.mesh │ ├── CAD5.mesh │ ├── CAD7.mesh │ ├── CAD8.mesh │ ├── Cactus.mesh │ ├── Cylinders2.mesh │ ├── Ghost.mesh │ ├── Indorelax.mesh │ ├── Knob.mesh │ ├── Torus.mesh │ └── Vertebra.mesh ├── Fig14 │ ├── Hollow-sphere.mesh │ └── Tic-tac-toe.mesh ├── Fig15 │ └── SGP.mesh ├── Fig17 │ └── Cogwheel1.mesh └── Fig2 │ ├── hole.mesh │ ├── twisting.mesh │ ├── val11.mesh │ ├── val3.mesh │ └── val5.mesh ├── schemes ├── adapter2FacesSubdivide3x3.rse ├── adapterEdgeSubdivide3x3.rse ├── adapterFaceSubdivide3x3.rse ├── inset.rse ├── planeSplit ├── subdivide2x2.rse └── subdivide3x3.rse ├── tutorials.md └── videos.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2 | .vs/ 3 | CMakePresets.json 4 | CMakeSettings.json 5 | cmake-build-debug 6 | .idea 7 | 8 | # Visual Studio Code 9 | .vscode/ 10 | 11 | # MacOS 12 | .DS_Store 13 | 14 | # CMake output 15 | out/ 16 | build/ 17 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.14) 2 | 3 | include (FetchContent) 4 | set (FETCHCONTENT_QUIET FALSE) 5 | 6 | project ("HexBox" VERSION 0.3) 7 | 8 | add_compile_definitions(HMP_NAME=\"${CMAKE_PROJECT_NAME}\") 9 | add_compile_definitions(HMP_VERSION=\"${CMAKE_PROJECT_VERSION}\") 10 | 11 | option (HMP_GUI_ENABLE_DAG_VIEWER "Enable dag viewer widget" OFF) 12 | option (HMP_GUI_ENABLE_AE3D2SHAPE_EXPORTER "Enable ae-3d2shape exporter" OFF) 13 | option (HMP_ENABLE_ALT_PROJ "Enable alternative projection" ON) 14 | option (HMP_AGGRESSIVE_DEBUG "Enable ASAN and debug libc" OFF) 15 | option (HMP_AGGRESSIVE_WARNINGS "Enable a lot of warnings" OFF) 16 | option (HMP_GUI_CAPTURE "Setup for recording modeling sessions" OFF) 17 | 18 | # cinolib 19 | set (CINOLIB_HEADER_ONLY OFF) 20 | set (CINOLIB_USES_OPENGL_GLFW_IMGUI ON) 21 | FetchContent_Declare ( 22 | cinolib 23 | GIT_REPOSITORY "https://github.com/francescozoccheddu/cinolib.git" 24 | GIT_TAG "ad8f8ca2884b56de958b237ff28eb47b0646daf3" 25 | GIT_SHALLOW TRUE 26 | GIT_PROGRESS TRUE 27 | ) 28 | FetchContent_MakeAvailable (cinolib) 29 | 30 | # ogdf 31 | if (HMP_GUI_ENABLE_DAG_VIEWER) 32 | FetchContent_Declare ( 33 | ogdf 34 | GIT_REPOSITORY "https://github.com/ogdf/ogdf.git" 35 | GIT_TAG "dogwood-202202" 36 | GIT_SHALLOW TRUE 37 | GIT_PROGRESS TRUE 38 | ) 39 | FetchContent_MakeAvailable (ogdf) 40 | endif() 41 | 42 | # fprotais/hexsmoothing 43 | if (HMP_ENABLE_ALT_PROJ) 44 | add_compile_definitions(HMP_ENABLE_ALT_PROJ) 45 | FetchContent_Declare ( 46 | fprotais 47 | GIT_REPOSITORY "https://github.com/fprotais/hexsmoothing" 48 | GIT_TAG "b538f7270d91a5e8baaa25287c06ab4a5c5d4cfb" 49 | GIT_SHALLOW FALSE 50 | GIT_PROGRESS TRUE 51 | ) 52 | FetchContent_MakeAvailable (fprotais) 53 | endif() 54 | 55 | # updatable_priority_queue 56 | FetchContent_Declare ( 57 | updatable_priority_queue 58 | GIT_REPOSITORY "https://github.com/Ten0/updatable_priority_queue.git" 59 | GIT_TAG "8a7facc90855f64ad463d7edd393eff0fc6d97af" 60 | GIT_PROGRESS TRUE 61 | ) 62 | FetchContent_MakeAvailable (updatable_priority_queue) 63 | 64 | # cpputils 65 | FetchContent_Declare ( 66 | cpputils 67 | GIT_REPOSITORY "https://github.com/francescozoccheddu/cpputils.git" 68 | GIT_TAG "56414519fe56d47413def942ecd29073d1c5be8e" 69 | GIT_SHALLOW FALSE 70 | GIT_PROGRESS TRUE 71 | ) 72 | FetchContent_MakeAvailable (cpputils) 73 | 74 | # hexa-modeling-prototype 75 | add_subdirectory ("core") 76 | add_subdirectory ("gui") 77 | 78 | # compile options 79 | 80 | if (HMP_AGGRESSIVE_DEBUG) 81 | add_compile_definitions(_GLIBCXX_DEBUG HMP_AGGRESSIVE_DEBUG) 82 | add_compile_options(-fsanitize=address) 83 | add_link_options(-fsanitize=address) 84 | endif() 85 | 86 | if (HMP_AGGRESSIVE_WARNINGS) 87 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 88 | target_compile_options(core PRIVATE -Wall -Wextra -Wpedantic -Wconversion -Wunused) 89 | target_compile_options(gui PRIVATE -Wall -Wextra -Wpedantic -Wconversion -Wunused) 90 | elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 91 | target_compile_options(core PRIVATE /W4) 92 | target_compile_options(gui PRIVATE /W4) 93 | endif() 94 | endif() 95 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 4 | F. Zoccheddu, E. Gobbetti, M. Livesu, N. Pietroni, G. Cherchi 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HexBox: Interactive Box Modeling of Hexahedral Meshes 2 | 3 | > **Note**
4 | > We are preparing an amazing tutorial on how to use HexBox. Stay tuned :wink: 5 | 6 |

7 | 8 | HexBox is an intuitive modeling method and interactive tool for creating and editing hexahedral meshes. 9 | Hexbox brings the major and widely validated surface modeling paradigm of surface box modeling into the world of hex meshing. 10 | This is the reference implementation of the paper 11 | 12 | [***HexBox: Interactive Box Modeling of Hexahedral Meshes***](https://www.gianmarcocherchi.com/pdf/hexbox.pdf)
13 | F. Zoccheddu, [E. Gobbetti](https://www.crs4.it/peopledetails/8/enrico-gobbetti/), [M. Livesu](http://pers.ge.imati.cnr.it/livesu/), [N. Pietroni](https://www.nicopietroni.com), [G. Cherchi](http://www.gianmarcocherchi.com)
14 | _Computer Graphics Forum (SGP 2023)_ 15 | 16 | ## Setup 17 | 18 | 1. Clone this repository: 19 | 20 | ```Shell 21 | git clone https://github.com/cg3hci/HexBox.git 22 | cd HexBox 23 | ``` 24 | 25 | 2. Generate the build system: 26 | 27 | ```Shell 28 | mkdir build 29 | cd build 30 | cmake .. 31 | ``` 32 | 33 | 3. Build: 34 | 35 | ```Shell 36 | cmake --build . 37 | ``` 38 | 39 | 4. Run the `gui` executable. 40 | 41 | 5. Enjoy! 😉 42 | 43 | > **Note** 44 | > We are preparing a tutorial on how to use HexBox. Meanwhile, we print the list of commands and shortcuts in the terminal. 45 | 46 | ## Compatibility 47 | 48 | HexBox requires [CMake](https://cmake.org/) 3.14+, a modern C++20 compiler, and OpenGL 2.0. As of today, it has been successfully tested on MSVC v143 on Windows 11, GCC 10 and Clang 14 on Ubuntu 22.10 and Clang 14 on MacOS. 49 | 50 | ## Videos, Tutorials and Models 51 | 52 | HexBox is meant to be a live project. On [this](videos.md) page you can find the video examples that were originally attached to the SGP submission. We are operating to create additional tutorials and tips & tricks to build a community around our tool, helping users to make the best of it. 53 | 54 | **[Tutorials](tutorials.md)** 55 | 56 | **[Here](models.zip)** you can find the models we shown in the paper, produced with our tool. 57 | 58 | ## Acknowledgement 59 | 60 | If you use HexBox on your projects, please consider citing our paper using the following BibTeX entry: 61 | 62 | ```bibtex 63 | @article{hexbox2023, 64 | title = {HexBox: Interactive Box Modeling of Hexahedral Meshes}, 65 | author = {Zoccheddu, F. and Gobbetti, E. and Livesu, M. and Pietroni, N. and Cherchi, G.}, 66 | journal = {Computer Graphics Forum}, 67 | volume = {42}, 68 | number = {5}, 69 | year = {2023}, 70 | issn = {1467-8659}, 71 | doi = {10.1111/cgf.14899} 72 | } 73 | ``` 74 | 75 | 76 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Issues and possible improvements 2 | Sorted by priority: 3 | - **\[IMPROVEMENT\]** Revert `HMP::Actions::ExtrudeUtils::apply` new vertex creation to the old method. 4 | - **\[IMPROVEMENT\]** `HMP::Projection::jacobianAdvance` is too defensive. Try working on one vertex at a time somehow. 5 | - **\[FEATURE\]** Add a negative weight factor for elements with multiple faces on surface in `HMP::Projection::smoothInternal`. 6 | - **\[BUG\]** `HMP::Dag::Extrude` and `HMP::Dag::Refine` relative fis and vis are cloned incorrectly during a paste operation, so I am recalculating them from scratch in `HMP::Actions::Paste::fixAdjacencies_TEMP_NAIVE`. This implies that: 7 | 1. The otherwise flawless "*Paste-the-same-way-to-get-the-same-result*" principle is violated (not a big deal; GUI helps a lot here); 8 | 2. I cannot profit from `HMP::Refinement::Scheme::facesSurfVisIs` until this is fixed. 9 | - **\[BUG\]** `HMP::Actions::Root::~Root()` leads to `HMP::Dag::Node` double free on app exit (I think the `HMP::Dag::Node` detachment system is broken). 10 | - **\[IMPROVEMENT\]** `HMP::Refinement::Utils::apply` should use `HMP::Refinement::Scheme::facesSurfVisIs` in place of `HMP::Refinement::Utils::weldAdjacencies_TEMP_NAIVE` (how do I rotate the scheme vertices and match the adjacent faces?). 11 | - **\[IMPROVEMENT\]** Improve `HMP::Actions::MakeConforming` either by implementing a balancing preprocessing phase, or by defining more adapter schemes. 12 | - **\[FEATURE\]** The extrude operation could automatically determine the number of parents, or at least give the user a warning in case of unintentionally duplicate vertices. 13 | - **\[IMPROVEMENT\]** `HMP::Actions::MakeConforming` performance can be improved a lot by keeping a queue of non-conforming refinements. 14 | - **\[FEATURE\]** Perhaps pasting a subtree should not preserve the source size (or maybe the choice could be left to the user). 15 | - **\[REFACTOR\]** `HMP::Meshing::Utils` is a dumpsite full of duplicated code. Keep the few essential primitives and throw everything else away. 16 | - **\[IMPROVEMENT\]** `OGDF` is overkill for what I need. Consider replacing it with a lighter implementation of the Sugiyama layout algorithm. 17 | - **\[IMPROVEMENT\]** The `HMP::Gui::Widgets::DirectVertEdit` scale and rotation implementation is a bit janky. (Also, a global axis-aligned translation feature would be welcome). 18 | - **\[FEATURE\]** Add a command to select all the vertices in a subtree. 19 | - **\[FEATURE\]** Allow the user to change the transform origin when editing vertices (or add a command to lock the origin in the current location). 20 | - **\[FEATURE\]** Add As-Rigid-As-Possible vertex editing support. 21 | - **\[REFACTOR\]** All the `HMP::Meshing::Actions` could be replaced with a set of more primitive actions (`MoveVert`, `ShowElement`, `AddElements`, `WeldElements` and `ActionSequence` maybe?). 22 | - **\[IMPROVEMENT\]** The `HMP::Gui::DagViewer::Widget` view should try to remain stable on layout change. 23 | - **\[IMPROVEMENT\]** The camera pan speed could be adjusted depending on the relative mesh position (as I do in the `HMP::Gui::Widgets::DirectVertEdit` translation operation). 24 | -------------------------------------------------------------------------------- /core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.14) 2 | 3 | add_library (core STATIC 4 | "src/Actions/Delete.cpp" 5 | "src/Actions/DeleteSome.cpp" 6 | "src/Actions/FitCircle.cpp" 7 | "src/Actions/Extrude.cpp" 8 | "src/Actions/Root.cpp" 9 | "src/Actions/MakeConforming.cpp" 10 | "src/Actions/Paste.cpp" 11 | "src/Actions/Project.cpp" 12 | "src/Actions/Refine.cpp" 13 | "src/Actions/RefineSome.cpp" 14 | "src/Actions/Transform.cpp" 15 | "src/Actions/ExtrudeUtils.cpp" 16 | "src/Actions/Pad.cpp" 17 | "src/Actions/Smooth.cpp" 18 | "src/Actions/SubdivideAll.cpp" 19 | "src/Actions/SplitPlane.cpp" 20 | "src/Dag/Delete.cpp" 21 | "src/Dag/Element.cpp" 22 | "src/Dag/Extrude.cpp" 23 | "src/Dag/Node.cpp" 24 | "src/Dag/NodeSet.cpp" 25 | "src/Dag/Operation.cpp" 26 | "src/Dag/Refine.cpp" 27 | "src/Dag/Utils.cpp" 28 | "src/Meshing/Mesher.cpp" 29 | "src/Meshing/Utils.cpp" 30 | "src/Refinement/Scheme.cpp" 31 | "src/Refinement/Schemes.cpp" 32 | "src/Refinement/Utils.cpp" 33 | "src/Refinement/Sub3x3AdapterCandidate.cpp" 34 | "src/Refinement/Sub3x3AdapterCandidateSet.cpp" 35 | "src/Projection/project.cpp" 36 | "src/Projection/Utils.cpp" 37 | "src/Projection/fill.cpp" 38 | "src/Projection/smooth.cpp" 39 | "src/Projection/percentileAdvance.cpp" 40 | "src/Projection/jacobianAdvance.cpp" 41 | "src/Projection/Match.cpp" 42 | "src/Utils/Serialization.cpp" 43 | "src/Commander.cpp" 44 | "src/Project.cpp" 45 | ) 46 | 47 | set_target_properties (core PROPERTIES 48 | CXX_STANDARD 20 49 | CXX_EXTENSIONS OFF 50 | CXX_STANDARD_REQUIRED ON 51 | ) 52 | 53 | if (MSVC AND CINOLIB_HEADER_ONLY) 54 | target_compile_options (core PRIVATE /bigobj) 55 | endif() 56 | 57 | target_include_directories (core 58 | PUBLIC "include" 59 | PRIVATE ${updatable_priority_queue_SOURCE_DIR} 60 | ) 61 | 62 | target_link_libraries (core 63 | PUBLIC cinolib 64 | PUBLIC cpputils 65 | ) 66 | 67 | if (HMP_ENABLE_ALT_PROJ) 68 | 69 | target_sources(core 70 | PRIVATE "src/Projection/altProject.cpp" 71 | ) 72 | 73 | target_link_libraries(core 74 | PUBLIC libhexsmoothing 75 | ) 76 | 77 | endif() 78 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Delete.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Actions 9 | { 10 | 11 | class Delete final: public Commander::Action 12 | { 13 | 14 | private: 15 | 16 | Dag::Element& m_element; 17 | const Dag::NodeHandle m_operation; 18 | 19 | void apply() override; 20 | void unapply() override; 21 | 22 | public: 23 | 24 | Delete(Dag::Element& _element); 25 | 26 | const Dag::Element& element() const; 27 | const Dag::Delete& operation() const; 28 | 29 | }; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/DeleteSome.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Actions 13 | { 14 | 15 | class DeleteSome final : public Commander::Action 16 | { 17 | 18 | private: 19 | 20 | 21 | static std::pair dereferenceOperation(const std::pair, Dag::Element*>& _pair); 22 | 23 | const std::vector, Dag::Element* const>> m_operations; 24 | 25 | void apply() override; 26 | void unapply() override; 27 | 28 | public: 29 | 30 | using Operations = decltype(cpputils::range::ofc(m_operations).map(&dereferenceOperation)); 31 | 32 | DeleteSome(const std::vector& _elements); 33 | 34 | Operations operations() const; 35 | 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Extrude.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Actions 12 | { 13 | 14 | class Extrude final: public Commander::Action 15 | { 16 | 17 | private: 18 | 19 | const cpputils::collections::FixedVector m_elements; 20 | const Dag::NodeHandle m_operation; 21 | Meshing::Mesher::State m_oldState; 22 | 23 | void apply() override; 24 | void unapply() override; 25 | 26 | 27 | public: 28 | 29 | using Elements = decltype(cpputils::range::ofc(m_elements).dereference().immutable()); 30 | 31 | Extrude(const cpputils::collections::FixedVector& _elements, const cpputils::collections::FixedVector& _fis, I _firstVi, bool _clockwise); 32 | 33 | Elements elements() const; 34 | 35 | const Dag::Extrude& operation() const; 36 | 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/ExtrudeUtils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Actions::ExtrudeUtils 12 | { 13 | 14 | HexVertIds apply(const Meshing::Mesher& _mesher, const Dag::Extrude& _extrude, std::vector& _newVerts); 15 | 16 | Dag::Extrude& prepare(const cpputils::collections::FixedVector& _fis, I _firstVi, bool _clockwise); 17 | 18 | } -------------------------------------------------------------------------------- /core/include/HMP/Actions/FitCircle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Actions 8 | { 9 | 10 | class FitCircle final : public Commander::Action 11 | { 12 | 13 | private: 14 | 15 | std::vector m_vids; 16 | std::vector m_otherVerts; 17 | bool m_prepared; 18 | 19 | void apply() override; 20 | void unapply() override; 21 | 22 | public: 23 | 24 | FitCircle(const std::vector& _vids); 25 | 26 | const std::vector& vids() const; 27 | 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/MakeConforming.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace HMP::Actions 15 | { 16 | 17 | class MakeConforming final: public Commander::Action 18 | { 19 | 20 | private: 21 | 22 | static std::pair dereferenceOperation(const std::pair, Dag::Element*>& _pair); 23 | 24 | std::vector, Dag::Element* const>> m_operations; 25 | Meshing::Mesher::State m_oldState; 26 | bool m_prepared; 27 | 28 | void apply() override; 29 | void unapply() override; 30 | 31 | void installSub3x3Adapters(); 32 | 33 | public: 34 | 35 | using Operations = decltype(cpputils::range::ofc(m_operations).map(&dereferenceOperation)); 36 | 37 | MakeConforming(); 38 | 39 | Operations operations() const; 40 | 41 | }; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Pad.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Actions 11 | { 12 | 13 | class Pad final: public Commander::Action 14 | { 15 | 16 | private: 17 | 18 | static std::pair dereferenceOperation(const std::pair>& _pair); 19 | 20 | const Real m_length; 21 | const I m_smoothIterations; 22 | const Real m_smoothSurfVertWeight; 23 | const Real m_cornerShrinkFactor; 24 | std::vector>> m_operations; 25 | std::vector m_otherVerts; 26 | std::vector m_newVerts; 27 | Meshing::Mesher::State m_oldState; 28 | bool m_prepared; 29 | 30 | void swapVerts(); 31 | void apply() override; 32 | void unapply() override; 33 | 34 | public: 35 | 36 | using Operations = decltype(cpputils::range::ofc(m_operations).map(&dereferenceOperation)); 37 | 38 | Pad(Real _length, I _smoothIterations = 1, Real _smoothSurfVertWeight = 1.0, Real _cornerShrinkFactor = 0.5); 39 | 40 | const Real length() const; 41 | 42 | const I smoothIterations() const; 43 | 44 | const Real smoothSurfVertWeight() const; 45 | 46 | const Real cornerShrinkFactor() const; 47 | 48 | Operations operations() const; 49 | 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Paste.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Actions 11 | { 12 | 13 | class Paste final: public Commander::Action 14 | { 15 | 16 | private: 17 | 18 | const cpputils::collections::FixedVector m_elements; 19 | const Dag::Extrude& m_sourceOperation; 20 | const cpputils::collections::FixedVector& m_fis; 21 | const I m_firstVi; 22 | const bool m_clockwise; 23 | Dag::NodeHandle m_operation; 24 | Meshing::Mesher::State m_oldState; 25 | bool m_prepared{ false }; 26 | std::vector m_newVerts; 27 | 28 | void apply() override; 29 | 30 | void unapply() override; 31 | 32 | public: 33 | 34 | using Elements = decltype(cpputils::range::ofc(m_elements).dereference().immutable()); 35 | 36 | Paste(const cpputils::collections::FixedVector& _elements, const cpputils::collections::FixedVector& _fis, I _firstVi, bool _clockwise, const Dag::Extrude& _source); 37 | 38 | Elements elements() const; 39 | 40 | const Dag::Extrude& operation() const; 41 | 42 | }; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Project.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Actions 11 | { 12 | 13 | class Project final: public Commander::Action 14 | { 15 | 16 | public: 17 | 18 | using TargetMesh = cinolib::Polygonmesh<>; 19 | 20 | private: 21 | 22 | const TargetMesh m_target; 23 | const std::vector m_pointFeats; 24 | const std::vector m_pathFeats; 25 | const Projection::Options m_options; 26 | std::vector m_otherVerts; 27 | bool m_prepared; 28 | 29 | void apply() override; 30 | void unapply() override; 31 | 32 | public: 33 | 34 | Project(TargetMesh&& _target, const std::vector& _pointFeats, const std::vector& _pathFeats, const Projection::Options& _options); 35 | Project(const TargetMesh& _target, const std::vector& _pointFeats, const std::vector& _pathFeats, const Projection::Options& _options); 36 | 37 | const TargetMesh& target() const; 38 | 39 | const Projection::Options options() const; 40 | 41 | }; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Refine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Actions 12 | { 13 | 14 | class Refine final: public Commander::Action 15 | { 16 | 17 | private: 18 | 19 | const std::vector>> m_operations; 20 | const I m_depth; 21 | Meshing::Mesher::State m_oldState; 22 | 23 | void apply() override; 24 | void unapply() override; 25 | 26 | public: 27 | 28 | Refine(Dag::Element& _element, I _forwardFi, I _firstVi, Refinement::EScheme _scheme, I _depth = 1); 29 | 30 | const Dag::Element& element() const; 31 | const Dag::Refine& operation() const; 32 | I depth() const; 33 | 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/RefineSome.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Actions 13 | { 14 | 15 | class RefineSome final : public Commander::Action 16 | { 17 | 18 | private: 19 | 20 | 21 | static std::pair dereferenceOperation(const std::pair, Dag::Element*>& _pair); 22 | 23 | const std::vector, Dag::Element* const>> m_operations; 24 | Meshing::Mesher::State m_oldState; 25 | 26 | void apply() override; 27 | void unapply() override; 28 | 29 | public: 30 | 31 | using Operations = decltype(cpputils::range::ofc(m_operations).map(&dereferenceOperation)); 32 | 33 | RefineSome(const std::vector& _elements); 34 | 35 | Operations operations() const; 36 | 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Root.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Actions 9 | { 10 | 11 | class Root final: public Commander::Action 12 | { 13 | 14 | private: 15 | 16 | Dag::Element& m_newRoot; 17 | const std::vector m_newVerts; 18 | Dag::NodeHandle m_otherRoot; 19 | std::vector m_otherVerts; 20 | 21 | void apply() override; 22 | void unapply() override; 23 | 24 | public: 25 | 26 | Root(Dag::Element& _root, const std::vector& _verts); 27 | 28 | const Dag::Element& newRoot() const; 29 | 30 | const std::vector& newVerts() const; 31 | 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Smooth.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Actions 9 | { 10 | 11 | class Smooth final: public Commander::Action 12 | { 13 | 14 | private: 15 | 16 | const I m_surfIterations, m_internalIterations; 17 | const Real m_surfVertWeight; 18 | std::vector m_otherVerts; 19 | bool m_prepared; 20 | 21 | void apply() override; 22 | void unapply() override; 23 | 24 | public: 25 | 26 | Smooth(I _surfaceIterations, I _internalIterations, Real _surfVertWeight = 1.0); 27 | 28 | const I surfaceIterations() const; 29 | 30 | const I internalIterations() const; 31 | 32 | const Real surfVertWeight() const; 33 | 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/SplitPlane.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Actions 13 | { 14 | 15 | class SplitPlane final : public Commander::Action 16 | { 17 | 18 | private: 19 | 20 | static std::pair dereferenceOperation(const std::pair, Dag::Element*>& _pair); 21 | 22 | std::vector, Dag::Element* const>> m_operations; 23 | Id m_eid; 24 | bool m_prepared; 25 | Meshing::Mesher::State m_oldState; 26 | 27 | void apply() override; 28 | void unapply() override; 29 | 30 | public: 31 | 32 | using Operations = decltype(cpputils::range::ofc(m_operations).map(&dereferenceOperation)); 33 | 34 | SplitPlane(Id _eid); 35 | 36 | Id eid() const; 37 | 38 | Operations operations() const; 39 | 40 | }; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/SubdivideAll.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP::Actions 10 | { 11 | 12 | class SubdivideAll final: public Commander::Action 13 | { 14 | 15 | private: 16 | 17 | static std::pair dereferenceOperation(const std::pair>& _pair); 18 | 19 | std::vector>> m_operations; 20 | Meshing::Mesher::State m_oldState; 21 | std::vector m_newVerts; 22 | bool m_prepared; 23 | 24 | void apply() override; 25 | void unapply() override; 26 | 27 | public: 28 | 29 | using Operations = decltype(cpputils::range::ofc(m_operations).map(&dereferenceOperation)); 30 | 31 | SubdivideAll(); 32 | 33 | Operations operations() const; 34 | 35 | }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/include/HMP/Actions/Transform.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Actions 11 | { 12 | 13 | class Transform final: public Commander::Action 14 | { 15 | 16 | private: 17 | 18 | const Mat4 m_transform; 19 | const std::optional> m_vids; 20 | std::vector m_otherVerts; 21 | bool m_prepared; 22 | 23 | void apply() override; 24 | void unapply() override; 25 | 26 | public: 27 | 28 | Transform(const Mat4& _transform, const std::optional>& _vids = std::nullopt); 29 | 30 | const Mat4& transform() const; 31 | 32 | const std::optional>& vids() const; 33 | 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/include/HMP/Commander.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP 10 | { 11 | 12 | class Project; 13 | 14 | class Commander final: public cpputils::mixins::ReferenceClass 15 | { 16 | 17 | public: 18 | 19 | class Action; 20 | 21 | class ActionBase: public cpputils::mixins::ReferenceClass 22 | { 23 | 24 | private: 25 | 26 | friend class Action; 27 | 28 | Commander* m_commander; 29 | bool m_applied; 30 | 31 | ActionBase(); 32 | 33 | void attach(Commander& _commander); 34 | 35 | void prepareAndApply(); 36 | void prepareAndUnapply(); 37 | 38 | protected: 39 | 40 | virtual ~ActionBase() = default; 41 | 42 | Meshing::Mesher& mesher(); 43 | const Meshing::Mesher& mesher() const; 44 | 45 | Dag::NodeHandle& root(); 46 | const Dag::Element* root() const; 47 | 48 | virtual void apply() = 0; 49 | virtual void unapply() = 0; 50 | 51 | public: 52 | 53 | bool attached() const; 54 | bool applied() const; 55 | 56 | }; 57 | 58 | class Stack; 59 | 60 | class StackBase: public cpputils::mixins::ReferenceClass, public HMP::Utils::ConstDerefRanged> 61 | { 62 | 63 | private: 64 | 65 | friend class Stack; 66 | 67 | std::deque m_data; 68 | I m_limit; 69 | 70 | StackBase(); 71 | 72 | Action& pop(); 73 | void push(Action& _action); 74 | 75 | public: 76 | 77 | I limit() const; 78 | void limit(I _count); 79 | void removeOldest(I _count); 80 | void keepLatest(I _count); 81 | void clear(); 82 | 83 | }; 84 | 85 | class Action: public ActionBase 86 | { 87 | 88 | private: 89 | 90 | friend class Commander; 91 | 92 | using ActionBase::attach; 93 | using ActionBase::prepareAndApply; 94 | using ActionBase::prepareAndUnapply; 95 | 96 | public: 97 | 98 | using ActionBase::ActionBase; 99 | 100 | }; 101 | 102 | class Stack final: public StackBase 103 | { 104 | 105 | private: 106 | 107 | friend class Commander; 108 | 109 | using StackBase::StackBase; 110 | using StackBase::pop; 111 | using StackBase::push; 112 | 113 | }; 114 | 115 | private: 116 | 117 | Project& m_project; 118 | Stack m_applied, m_unapplied; 119 | 120 | public: 121 | 122 | Commander(Project& _project); 123 | ~Commander(); 124 | 125 | void apply(Action& _action); 126 | 127 | void undo(); 128 | void redo(); 129 | 130 | bool canUndo() const; 131 | bool canRedo() const; 132 | 133 | Stack& unapplied(); 134 | const Stack& unapplied() const; 135 | 136 | Stack& applied(); 137 | const Stack& applied() const; 138 | 139 | 140 | }; 141 | 142 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/Delete.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HMP::Dag 6 | { 7 | 8 | class Delete final : public Operation 9 | { 10 | 11 | public: 12 | 13 | Delete(); 14 | 15 | }; 16 | 17 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/Element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Dag 7 | { 8 | 9 | class Element final: public Node 10 | { 11 | 12 | public: 13 | 14 | using Set = NodeSet; 15 | 16 | private: 17 | 18 | using Node::isElement; 19 | using Node::isOperation; 20 | using Node::element; 21 | using Node::operation; 22 | 23 | public: 24 | 25 | Element(); 26 | 27 | Set parents, children; 28 | HexVertIds vids; 29 | Id pid; 30 | 31 | Set& forward(bool _descending); 32 | const Set& forward(bool _descending) const; 33 | Set& back(bool _descending); 34 | const Set& back(bool _descending) const; 35 | 36 | }; 37 | 38 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/Extrude.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Dag 8 | { 9 | 10 | class Extrude final: public Operation 11 | { 12 | 13 | public: 14 | 15 | enum class ESource 16 | { 17 | Face, Edge, Vertex 18 | }; 19 | 20 | static ESource sourceByParentCount(I _parentCount); 21 | 22 | Extrude(); 23 | 24 | I firstVi; 25 | cpputils::collections::FixedVector fis; 26 | ESource source; 27 | bool clockwise; 28 | 29 | }; 30 | 31 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/Node.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Dag 11 | { 12 | 13 | template , bool TDescending = true> 14 | class NodeHandle; 15 | 16 | class Element; 17 | class Operation; 18 | 19 | class Node : public cpputils::mixins::ReferenceClass 20 | { 21 | 22 | private: 23 | 24 | static I s_allocatedNodeCount; 25 | 26 | public: 27 | 28 | static I allocatedNodeCount(); 29 | 30 | public: 31 | 32 | using Set = NodeSet; 33 | 34 | enum class EType 35 | { 36 | Element, Operation 37 | }; 38 | 39 | private: 40 | 41 | template , bool> 42 | friend class NodeHandle; 43 | 44 | Internal::NodeSetData m_parentsImpl, m_childrenImpl; 45 | 46 | I m_handles; 47 | 48 | static void deleteDangling(std::queue& _dangling, bool _descending); 49 | bool onAttach(Node& _node, bool _descending); 50 | bool onDetach(Node& _node, bool _deleteDangling, bool _descending); 51 | bool onDetachAll(bool _deleteDangling, bool _descending); 52 | 53 | bool onParentAttach(Node& _parent); 54 | bool onParentDetach(Node& _parent, bool _deleteDangling); 55 | bool onParentsDetachAll(bool _deleteDangling); 56 | bool onChildAttach(Node& _child); 57 | bool onChildDetach(Node& _child, bool _deleteDangling); 58 | bool onChildrenDetachAll(bool _deleteDangling); 59 | 60 | protected: 61 | 62 | Node(EType _type); 63 | virtual ~Node(); 64 | 65 | virtual void onParentAttaching(Node& _parent) const; 66 | virtual void onChildAttaching(Node& _child) const; 67 | 68 | Internal::NodeSetHandle& parentsHandle(); 69 | Internal::NodeSetHandle& childrenHandle(); 70 | 71 | public: 72 | 73 | const EType type; 74 | Set parents, children; 75 | 76 | bool isElement() const; 77 | bool isOperation() const; 78 | 79 | bool isRoot() const; 80 | bool isLeaf() const; 81 | 82 | Element& element(); 83 | const Element& element() const; 84 | Operation& operation(); 85 | const Operation& operation() const; 86 | 87 | template TNode> 88 | TNode& as(); 89 | 90 | template TNode> 91 | const TNode& as() const; 92 | 93 | Set& forward(bool _descending); 94 | const Set& forward(bool _descending) const; 95 | Set& back(bool _descending); 96 | const Set& back(bool _descending) const; 97 | 98 | }; 99 | 100 | } 101 | 102 | #define HMP_DAG_NODE_IMPL 103 | #include 104 | #undef HMP_DAG_NODE_IMPL 105 | 106 | #include 107 | #include 108 | -------------------------------------------------------------------------------- /core/include/HMP/Dag/Node.tpp: -------------------------------------------------------------------------------- 1 | #ifndef HMP_DAG_NODE_IMPL 2 | #error __FILE__ should not be directly included 3 | #endif 4 | 5 | #include 6 | 7 | namespace HMP::Dag 8 | { 9 | 10 | template TNode> 11 | TNode& Node::as() 12 | { 13 | return static_cast(*this); 14 | } 15 | 16 | template TNode> 17 | const TNode& Node::as() const 18 | { 19 | return static_cast(*this); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/NodeHandle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Dag 7 | { 8 | 9 | template TNode, bool TDescending> 10 | class NodeHandle final 11 | { 12 | 13 | private: 14 | 15 | TNode* m_node; 16 | 17 | void attach(TNode* _node); 18 | void detach(); 19 | 20 | public: 21 | 22 | NodeHandle(TNode* _node = nullptr); 23 | NodeHandle(TNode& _node); 24 | NodeHandle(const NodeHandle& _copy); 25 | NodeHandle(NodeHandle&& _moved); 26 | 27 | ~NodeHandle(); 28 | 29 | NodeHandle& operator=(TNode* _node); 30 | NodeHandle& operator=(TNode& _node); 31 | NodeHandle& operator=(const NodeHandle& _copy); 32 | NodeHandle& operator=(NodeHandle&& _moved); 33 | 34 | template TOtherNode, bool TOtherDescending> 35 | bool operator==(const NodeHandle& _other) const; 36 | 37 | TNode& operator*() const; 38 | TNode* operator->() const; 39 | operator TNode* () const; 40 | 41 | void free(); 42 | 43 | }; 44 | 45 | } 46 | 47 | #define HMP_DAG_NODEHANDLE_IMPL 48 | #include 49 | #undef HMP_DAG_NODEHANDLE_IMPL -------------------------------------------------------------------------------- /core/include/HMP/Dag/NodeHandle.tpp: -------------------------------------------------------------------------------- 1 | #ifndef HMP_DAG_NODEHANDLE_IMPL 2 | #error __FILE__ should not be directly included 3 | #endif 4 | 5 | #include 6 | 7 | namespace HMP::Dag 8 | { 9 | 10 | template TNode, bool TDescending> 11 | void NodeHandle::attach(TNode* _node) 12 | { 13 | detach(); 14 | m_node = _node; 15 | if (m_node) 16 | { 17 | m_node->m_handles++; 18 | } 19 | } 20 | 21 | template TNode, bool TDescending> 22 | void NodeHandle::detach() 23 | { 24 | if (m_node) 25 | { 26 | m_node->m_handles--; 27 | if (!m_node->m_handles && m_node->back(TDescending).empty()) 28 | { 29 | m_node->forward(TDescending).detachAll(true); 30 | delete m_node; 31 | } 32 | m_node = nullptr; 33 | } 34 | } 35 | 36 | template TNode, bool TDescending> 37 | NodeHandle::NodeHandle(TNode* _node) 38 | : m_node{} 39 | { 40 | attach(_node); 41 | } 42 | 43 | template TNode, bool TDescending> 44 | NodeHandle::NodeHandle(TNode& _node) 45 | : m_node{} 46 | { 47 | attach(&_node); 48 | } 49 | 50 | template TNode, bool TDescending> 51 | NodeHandle::NodeHandle(const NodeHandle& _copy) 52 | : m_node{} 53 | { 54 | attach(_copy.m_node); 55 | } 56 | 57 | template TNode, bool TDescending> 58 | NodeHandle::NodeHandle(NodeHandle&& _moved) 59 | : m_node{} 60 | { 61 | attach(_moved.m_node); 62 | _moved.detach(); 63 | } 64 | 65 | template TNode, bool TDescending> 66 | NodeHandle::~NodeHandle() 67 | { 68 | detach(); 69 | } 70 | 71 | template TNode, bool TDescending> 72 | NodeHandle& NodeHandle::operator=(TNode* _node) 73 | { 74 | attach(_node); 75 | return *this; 76 | } 77 | 78 | template TNode, bool TDescending> 79 | NodeHandle& NodeHandle::operator=(TNode& _node) 80 | { 81 | attach(&_node); 82 | return *this; 83 | } 84 | 85 | template TNode, bool TDescending> 86 | NodeHandle& NodeHandle::operator=(const NodeHandle& _copy) 87 | { 88 | attach(_copy.m_node); 89 | return *this; 90 | } 91 | 92 | template TNode, bool TDescending> 93 | NodeHandle& NodeHandle::operator=(NodeHandle&& _moved) 94 | { 95 | attach(_moved.m_node); 96 | _moved.detach(); 97 | return *this; 98 | } 99 | 100 | template TNode, bool TDescending> 101 | template TOtherNode, bool TOtherDescending> 102 | bool NodeHandle::operator==(const NodeHandle& _other) const 103 | { 104 | return _other.m_node == m_node; 105 | } 106 | 107 | template TNode, bool TDescending> 108 | TNode& NodeHandle::operator*() const 109 | { 110 | return *m_node; 111 | } 112 | 113 | template TNode, bool TDescending> 114 | TNode* NodeHandle::operator->() const 115 | { 116 | return m_node; 117 | } 118 | 119 | template TNode, bool TDescending> 120 | NodeHandle::operator TNode* () const 121 | { 122 | return m_node; 123 | } 124 | 125 | template TNode, bool TDescending> 126 | void NodeHandle::free() 127 | { 128 | if (m_node) 129 | { 130 | m_node->m_handles--; 131 | m_node = nullptr; 132 | } 133 | } 134 | 135 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/NodeSet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Dag 12 | { 13 | 14 | class Node; 15 | 16 | template 17 | class NodeSet; 18 | 19 | namespace Internal 20 | { 21 | 22 | template 23 | class NodeSetBase; 24 | 25 | class NodeSetData final: public cpputils::mixins::ReferenceClass 26 | { 27 | 28 | private: 29 | 30 | template 31 | friend class NodeSetBase; 32 | 33 | std::unordered_map::iterator> m_map{}; 34 | std::list m_list{}; 35 | 36 | public: 37 | 38 | bool add(Node& _node); 39 | bool remove(Node& _node); 40 | bool clear(); 41 | 42 | }; 43 | 44 | class NodeSetHandle final: public cpputils::mixins::ReferenceClass 45 | { 46 | 47 | private: 48 | 49 | template 50 | friend class NodeSetBase; 51 | 52 | template 53 | friend class Dag::NodeSet; 54 | 55 | NodeSetData& m_data; 56 | const std::function m_onAttach; 57 | const std::function m_onDetach; 58 | const std::function m_onDetachAll; 59 | 60 | NodeSetHandle(Internal::NodeSetData& _data, std::function _onAttach, std::function _onDetach, std::function _onDetachAll); 61 | 62 | }; 63 | 64 | template 65 | constexpr TNode& nonConstNodeMapper(Node* _node) { return *reinterpret_cast(_node); } 66 | 67 | template 68 | constexpr const TNode& constNodeMapper(Node* _node) { return *reinterpret_cast(_node); } 69 | 70 | template 71 | using NonConstNodeRange = decltype(cpputils::range::ofc(std::declval>()).map(&nonConstNodeMapper)); 72 | 73 | template 74 | using ConstNodeRange = decltype(cpputils::range::ofc(std::declval>()).map(&constNodeMapper)); 75 | 76 | template 77 | class NodeSetBase: public cpputils::mixins::ReferenceClass, public cpputils::range::Ranged::Iterator, typename NonConstNodeRange::Iterator> 78 | { 79 | 80 | private: 81 | 82 | template 83 | friend class Dag::NodeSet; 84 | 85 | NodeSetHandle& m_handle; 86 | const bool m_owner; 87 | 88 | NodeSetBase(NodeSetHandle& _NodeSetHandle, bool _owner); 89 | 90 | ~NodeSetBase(); 91 | 92 | NonConstNodeRange range() override; 93 | 94 | ConstNodeRange range() const override; 95 | 96 | public: 97 | 98 | bool attach(TNode& _node); 99 | bool detach(TNode& _node, bool _deleteDangling = false); 100 | bool detachAll(bool _deleteDangling = false); 101 | 102 | bool has(const TNode& _node) const; 103 | 104 | }; 105 | 106 | } 107 | 108 | template 109 | class NodeSet final: public Internal::NodeSetBase 110 | { 111 | 112 | private: 113 | 114 | friend class Node; 115 | 116 | NodeSet(Internal::NodeSetData& _data, std::function _onAttach, std::function _onDetach, std::function _onDetachAll); 117 | 118 | Internal::NodeSetHandle& handle(); 119 | Internal::NodeSetData& data(); 120 | const Internal::NodeSetData& data() const; 121 | 122 | public: 123 | 124 | NodeSet(Internal::NodeSetHandle& _NodeSetHandle); 125 | 126 | }; 127 | 128 | } 129 | 130 | #define HMP_DAG_NODESET_IMPL 131 | #include 132 | #undef HMP_DAG_NODESET_IMPL 133 | -------------------------------------------------------------------------------- /core/include/HMP/Dag/NodeSet.tpp: -------------------------------------------------------------------------------- 1 | #ifndef HMP_DAG_NODESET_IMPL 2 | #error __FILE__ should not be directly included 3 | #endif 4 | 5 | #include 6 | 7 | namespace HMP::Dag 8 | { 9 | 10 | namespace Internal 11 | { 12 | 13 | // NodeSetBase 14 | 15 | template 16 | NodeSetBase::NodeSetBase(NodeSetHandle& _handle, bool _owner) 17 | : m_handle{ _handle }, m_owner{ _owner } 18 | {} 19 | 20 | template 21 | NodeSetBase::~NodeSetBase() 22 | { 23 | if (m_owner) 24 | { 25 | delete& m_handle; 26 | } 27 | } 28 | 29 | template 30 | bool NodeSetBase::attach(TNode& _node) 31 | { 32 | return m_handle.m_onAttach(_node); 33 | } 34 | 35 | template 36 | bool NodeSetBase::detach(TNode& _node, bool _deleteDangling) 37 | { 38 | return m_handle.m_onDetach(_node, _deleteDangling); 39 | } 40 | 41 | template 42 | bool NodeSetBase::detachAll(bool _deleteDangling) 43 | { 44 | return m_handle.m_onDetachAll(_deleteDangling); 45 | } 46 | 47 | template 48 | bool NodeSetBase::has(const TNode& _node) const 49 | { 50 | return m_handle.m_data.m_map.contains(const_cast(&_node)); 51 | } 52 | 53 | template 54 | NonConstNodeRange NodeSetBase::range() 55 | { 56 | return cpputils::range::ofc(m_handle.m_data.m_list).map(&nonConstNodeMapper); 57 | } 58 | 59 | template 60 | ConstNodeRange NodeSetBase::range() const 61 | { 62 | return cpputils::range::ofc(m_handle.m_data.m_list).map(&constNodeMapper); 63 | } 64 | 65 | } 66 | 67 | // NodeSet 68 | 69 | template 70 | NodeSet::NodeSet(Internal::NodeSetData& _data, std::function _onAttach, std::function _onDetach, std::function _onDetachAll) 71 | : Internal::NodeSetBase{ *new Internal::NodeSetHandle{ _data, _onAttach, _onDetach, _onDetachAll }, true } 72 | {} 73 | 74 | template 75 | Internal::NodeSetHandle& NodeSet::handle() 76 | { 77 | return Internal::NodeSetBase::m_handle; 78 | } 79 | 80 | template 81 | Internal::NodeSetData& NodeSet::data() 82 | { 83 | return Internal::NodeSetBase::m_handle.m_data; 84 | } 85 | 86 | template 87 | const Internal::NodeSetData& NodeSet::data() const 88 | { 89 | return Internal::NodeSetBase::m_handle.m_data; 90 | } 91 | 92 | template 93 | NodeSet::NodeSet(Internal::NodeSetHandle& _handle) 94 | : Internal::NodeSetBase{ _handle, false } 95 | {} 96 | 97 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/Operation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Dag 8 | { 9 | 10 | class Operation: public Node 11 | { 12 | 13 | public: 14 | 15 | using Set = NodeSet; 16 | 17 | enum class EPrimitive 18 | { 19 | Refine, Extrude, Delete 20 | }; 21 | 22 | private: 23 | 24 | using Node::isElement; 25 | using Node::isOperation; 26 | using Node::element; 27 | using Node::operation; 28 | 29 | protected: 30 | 31 | explicit Operation(EPrimitive _primitive); 32 | 33 | public: 34 | 35 | const EPrimitive primitive; 36 | Set parents, children; 37 | 38 | Set& forward(bool _descending); 39 | const Set& forward(bool _descending) const; 40 | Set& back(bool _descending); 41 | const Set& back(bool _descending) const; 42 | 43 | }; 44 | 45 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/Refine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Dag 9 | { 10 | 11 | class Refine final: public Operation 12 | { 13 | 14 | public: 15 | 16 | Refine(); 17 | 18 | Refinement::EScheme scheme; 19 | std::vector surfVids; 20 | I forwardFi; 21 | I firstVi; 22 | 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /core/include/HMP/Dag/Utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Dag::Utils 13 | { 14 | 15 | std::vector descendants(Node& _node, std::function _branchSelector = [](const Node&) { return true; }); 16 | std::vector descendants(const Node& _node, std::function _branchSelector = [](const Node&) { return true; }); 17 | 18 | void serialize(HMP::Utils::Serialization::Serializer& _serializer, const Node& _node); 19 | Node& deserialize(HMP::Utils::Serialization::Deserializer& _deserializer); 20 | 21 | Node& clone(const Node& _node); 22 | 23 | } -------------------------------------------------------------------------------- /core/include/HMP/Meshing/Mesher.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace HMP::Meshing 16 | { 17 | 18 | class Mesher final : public cpputils::mixins::ReferenceClass 19 | { 20 | 21 | public: 22 | 23 | class PolyAttributes final : public cinolib::Polyhedron_std_attributes 24 | { 25 | 26 | private: 27 | 28 | friend class Mesher; 29 | 30 | Dag::Element* m_element{}; 31 | 32 | }; 33 | 34 | class State final 35 | { 36 | 37 | private: 38 | 39 | friend class Mesher; 40 | 41 | Id m_pids, m_fids, m_eids, m_vids; 42 | 43 | State(Id _pids, Id _fids, Id _eids, Id _vids); 44 | 45 | public: 46 | 47 | State(); 48 | 49 | Id pidsCount() const; 50 | Id fidsCount() const; 51 | Id eidsCount() const; 52 | Id vidsCount() const; 53 | Id lastPid() const; 54 | Id lastFid() const; 55 | Id lastEid() const; 56 | Id lastVid() const; 57 | 58 | bool operator==(const State& _other) const = default; 59 | 60 | }; 61 | 62 | using Mesh = cinolib::DrawableHexmesh; 63 | 64 | private: 65 | 66 | static constexpr Real c_maxVertDistance{ 1e-3 }; 67 | 68 | Mesh m_mesh; 69 | cinolib::Octree m_octree; 70 | std::vector m_fidVisibleTriId, m_eidVisibleEid; 71 | bool m_dirty; 72 | 73 | void updateOctree(); 74 | 75 | public: 76 | 77 | cinolib::Color faceColor, edgeColor; 78 | 79 | Mesher(); 80 | 81 | mutable cpputils::collections::Event onAdded; 82 | mutable cpputils::collections::Event onRestored; 83 | mutable cpputils::collections::Event onElementVisibilityChanged; 84 | mutable cpputils::collections::Event onUpdated; 85 | 86 | const Mesh& mesh() const; 87 | 88 | bool has(const Dag::Element& _element) const; 89 | Dag::Element& element(Id _pid); 90 | const Dag::Element& element(Id _pid) const; 91 | void moveVert(Id _vid, const Vec& _position); 92 | void add(const std::vector _elements, const std::vector& _verts = {}); 93 | void restore(const State& _state); 94 | State state() const; 95 | void show(Id _pid, bool _visible); 96 | void show(Dag::Element& _element, bool _visible); 97 | bool shown(Id _pid) const; 98 | bool vidShown(Id _vid) const; 99 | bool shown(const Dag::Element& _element) const; 100 | 101 | void updateColors(bool _poly = true, bool _edge = true); 102 | void setEdgeThickness(float _edgeThickness); 103 | float edgeThickness() const; 104 | 105 | void updateMesh(); 106 | void updateMeshTemp(const std::unordered_set& _changedVids); 107 | 108 | bool pick(const Vec& _from, const Vec& _dir, Id& _pid, Id& _fid, Id& _eid, Id& _vid, bool _allowBehind = false) const; 109 | 110 | }; 111 | 112 | } -------------------------------------------------------------------------------- /core/include/HMP/Meshing/Utils.tpp: -------------------------------------------------------------------------------- 1 | #ifndef HMP_MESHING_UTILS_IMPL 2 | #error __FILE__ should not be directly included 3 | #endif 4 | 5 | #include 6 | 7 | namespace HMP::Meshing::Utils 8 | { 9 | 10 | template 11 | std::array index(const std::array& _source, const std::array& _is) 12 | { 13 | std::array out; 14 | for (I i{}; i < _is.size(); i++) 15 | { 16 | out[i] = _source[_is[i]]; 17 | } 18 | return out; 19 | } 20 | 21 | template 22 | std::array verts(const Meshing::Mesher::Mesh& _mesh, const std::array& _vids, const std::vector& _newVerts) 23 | { 24 | return cpputils::range::of(_vids).map([&](const Id _vid) { 25 | return _vid >= _mesh.num_verts() ? _newVerts[toI(_vid - _mesh.num_verts())] : _mesh.vert(_vid); 26 | }).toArray(); 27 | } 28 | 29 | template 30 | Vec centroid(const std::array& _verts) 31 | { 32 | Vec sum{}; 33 | for (const Vec& vert : _verts) { sum += vert; } 34 | return sum / static_cast(TSize); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /core/include/HMP/Meshing/types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP 8 | { 9 | 10 | using Id = unsigned int; 11 | using I = std::size_t; 12 | using Real = double; 13 | 14 | using IVec = cinolib::vec<3, I>; 15 | using IVec2 = cinolib::vec<2, I>; 16 | 17 | using Vec = cinolib::vec<3, Real>; 18 | using Vec2 = cinolib::vec<2, Real>; 19 | using Vec4 = cinolib::vec<4, Real>; 20 | using Mat4 = cinolib::mat4d; 21 | using Mat3 = cinolib::mat3d; 22 | 23 | constexpr Id noId{ static_cast(-1) }; 24 | 25 | inline constexpr Id toId(I _i) { return static_cast(_i); } 26 | inline constexpr I toI(Id _id) { return static_cast(_id); } 27 | 28 | template 29 | using HexFaceData = std::array; 30 | 31 | template 32 | using HexEdgeData = std::array; 33 | 34 | template 35 | using HexVertData = std::array; 36 | 37 | template 38 | using QuadVertData = std::array; 39 | 40 | template 41 | using QuadEdgeData = std::array; 42 | 43 | template 44 | using EdgeVertData = std::array; 45 | 46 | using HexVerts = HexVertData; 47 | using HexVertIds = HexVertData; 48 | using HexVertIs = HexVertData; 49 | using HexFaceIds = HexFaceData; 50 | using HexFaceIs = HexFaceData; 51 | using HexEdgeIds = HexEdgeData; 52 | using HexEdgeIs = HexEdgeData; 53 | using QuadVerts = QuadVertData; 54 | using QuadVertIds = QuadVertData; 55 | using QuadVertIs = QuadVertData; 56 | using QuadEdgeIds = QuadEdgeData; 57 | using QuadEdgeIs = QuadEdgeData; 58 | using EdgeVerts = EdgeVertData; 59 | using EdgeVertIds = EdgeVertData; 60 | using EdgeVertIs = EdgeVertData; 61 | 62 | } -------------------------------------------------------------------------------- /core/include/HMP/Project.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP 10 | { 11 | 12 | class Project: public cpputils::mixins::ReferenceClass 13 | { 14 | 15 | private: 16 | 17 | Meshing::Mesher m_mesher; 18 | Commander m_commander; 19 | Dag::NodeHandle m_root; 20 | 21 | public: 22 | 23 | Project(); 24 | 25 | Commander& commander(); 26 | const Commander& commander() const; 27 | 28 | Dag::NodeHandle& root(); 29 | const Dag::Element* root() const; 30 | 31 | Meshing::Mesher& mesher(); 32 | const Meshing::Mesher& mesher() const; 33 | 34 | }; 35 | 36 | } -------------------------------------------------------------------------------- /core/include/HMP/Projection/Match.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP::Projection::Match 10 | { 11 | 12 | struct SourceToTargetVid final 13 | { 14 | Vec pos; 15 | Id targetVid; 16 | }; 17 | 18 | std::vector> matchSurfaceFid(const cinolib::AbstractPolygonMesh<>& _source, const cinolib::AbstractPolygonMesh<>& _target); 19 | 20 | std::unordered_map> matchPathEid(const cinolib::AbstractPolygonMesh<>& _source, const cinolib::AbstractPolygonMesh<>& _target, const std::vector& _sourceEidsPath, const std::vector& _targetVidsPath); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/include/HMP/Projection/altProject.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HMP::Projection 6 | { 7 | 8 | std::vector altProject(const Meshing::Mesher::Mesh& _source, const cinolib::AbstractPolygonMesh<>& _target, const std::vector& _pointFeats, const std::vector& _pathFeats, const Options& _options = {}); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /core/include/HMP/Projection/fill.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Projection 11 | { 12 | 13 | void fill(const cinolib::AbstractPolygonMesh<>& _mesh, const std::vector>& _newVerts, const Utils::Tweak& _distWeightTweak, std::vector& _out); 14 | 15 | void fillPath(const cinolib::AbstractPolygonMesh<>& _mesh, const std::vector>& _newPathVerts, const Utils::Tweak& _distWeightTweak, const std::vector& _vidsPath, std::vector& _out); 16 | 17 | std::vector fill(const cinolib::AbstractPolygonMesh<>& _mesh, const std::vector>& _newVerts, const Utils::Tweak& _distWeightTweak); 18 | 19 | std::vector fillPath(const cinolib::AbstractPolygonMesh<>& _mesh, const std::vector>& _newPathVerts, const Utils::Tweak& _distWeightTweak, const std::vector& _vidsPath); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /core/include/HMP/Projection/jacobianAdvance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Projection 8 | { 9 | 10 | enum class EJacobianAdvanceMode 11 | { 12 | Length, Lerp 13 | }; 14 | 15 | void jacobianAdvance(Meshing::Mesher::Mesh& _mesh, const std::vector& _from, EJacobianAdvanceMode _mode = EJacobianAdvanceMode::Length, I _maxTests = 7, Real _stopThreshold = 0.1); 16 | 17 | void jacobianAdvance(Meshing::Mesher::Mesh& _mesh, const std::vector& _from, const std::vector& _vids, EJacobianAdvanceMode _mode = EJacobianAdvanceMode::Length, I _maxTests = 7, Real _stopThreshold = 0.1); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /core/include/HMP/Projection/percentileAdvance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Projection 8 | { 9 | 10 | std::vector percentileAdvance(const std::vector& _from, const std::vector& _to, const double _percentile = 0.5); 11 | 12 | void percentileAdvance(const std::vector& _from, const std::vector& _to, std::vector& _out, const double _percentile = 0.5); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/include/HMP/Projection/project.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Projection 12 | { 13 | 14 | enum class EBaseWeightMode 15 | { 16 | Distance, BarycentricCoords 17 | }; 18 | 19 | enum class EDisplaceMode 20 | { 21 | NormDirAvgAndDirNormAvg, NormDirAvgAndDirAvg, DirAvg, VertAvg 22 | }; 23 | 24 | enum class EJacobianCheckMode 25 | { 26 | None, Surface, All 27 | }; 28 | 29 | struct Options final 30 | { 31 | 32 | EBaseWeightMode baseWeightMode{ EBaseWeightMode::Distance }; 33 | EDisplaceMode displaceMode{ EDisplaceMode::DirAvg }; 34 | EJacobianCheckMode jacobianCheckMode{ EJacobianCheckMode::All }; 35 | EJacobianAdvanceMode jacobianAdvanceMode{ EJacobianAdvanceMode::Length }; 36 | I jacobianAdvanceMaxTests{ 7 }; 37 | I smoothInternalIterations{ 1 }; 38 | I smoothSurfaceIterations{ true }; 39 | Real smoothInternalDoneWeight{ 1.0 }; 40 | Real jacobianAdvanceStopThreshold{ 0.1 }; 41 | Utils::Tweak baseWeightTweak{ 0.0, 1.0 }; 42 | Utils::Tweak normalDotTweak{ -1.0, 0.0 }; 43 | Utils::Tweak unsetVertsDistWeightTweak{ 0.0, 0.0 }; 44 | double distanceWeight{ 0.0 }; 45 | double distanceWeightPower{ 1.0 }; 46 | double advancePercentile{ 0.5 }; 47 | std::optional> vertexMask{std::nullopt}; 48 | I iterations{ 5 }; 49 | #ifdef HMP_ENABLE_ALT_PROJ 50 | bool alternativeMethod{ false }; 51 | #else 52 | static constexpr bool alternativeMethod{ false }; 53 | #endif 54 | 55 | }; 56 | 57 | std::vector project(const Meshing::Mesher::Mesh& _source, const cinolib::AbstractPolygonMesh<>& _target, const std::vector& _pointFeats, const std::vector& _pathFeats, const Options& _options = {}); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /core/include/HMP/Projection/smooth.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP::Projection 10 | { 11 | 12 | void smooth(const cinolib::AbstractPolygonMesh<>& _mesh, std::vector& _out); 13 | 14 | void smoothPath(const cinolib::AbstractPolygonMesh<>& _mesh, const std::vector& _vids, std::vector& _out); 15 | 16 | void smoothInternal(const Meshing::Mesher::Mesh& _mesh, std::vector& _out, Real _doneWeight = 2.0); 17 | 18 | void smoothInternal(const Meshing::Mesher::Mesh& _mesh, const std::vector& _surfaceVids, Real _doneWeight, std::vector& _out); 19 | 20 | std::vector smooth(const cinolib::AbstractPolygonMesh<>& _mesh); 21 | 22 | std::vector smoothPath(const cinolib::AbstractPolygonMesh<>& _mesh, const std::vector& _vids); 23 | 24 | std::vector smoothInternal(const Meshing::Mesher::Mesh& _mesh, Real _doneWeight = 2.0); 25 | 26 | std::vector smoothInternal(const Meshing::Mesher::Mesh& _mesh, const std::vector& _surfaceVids, Real _doneWeight = 2.0); 27 | 28 | } -------------------------------------------------------------------------------- /core/include/HMP/Refinement/Scheme.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP::Refinement 10 | { 11 | 12 | class Scheme final: public cpputils::mixins::ReferenceClass 13 | { 14 | 15 | private: 16 | 17 | static bool compareIVec2(const IVec2& _a, const IVec2& _b); 18 | 19 | public: 20 | 21 | using FaceSurfVisMap = std::map; 22 | 23 | private: 24 | 25 | std::vector findSurfVis() const; 26 | std::vector findCornerVis() const; 27 | FaceSurfVisMap findFacesSurfVisIs(Id _dim, bool _polarity) const; 28 | HexFaceData findFacesSurfVisIs() const; 29 | 30 | const HexVertData m_vidCorners; 31 | 32 | public: 33 | 34 | const I gridSize; 35 | const std::vector verts; 36 | const std::vector polys; 37 | const std::vector surfVis; 38 | const std::vector cornerVis; 39 | const HexFaceData facesSurfVisIs; 40 | 41 | explicit Scheme(I _gridSize, const std::vector& _verts, const std::vector& _polys); 42 | 43 | bool isMin(I _comp) const; 44 | 45 | bool isMax(I _comp) const; 46 | 47 | bool isExtreme(I _comp) const; 48 | 49 | bool isOnSurf(const IVec& _vert) const; 50 | 51 | bool isCorner(const IVec& _vert) const; 52 | 53 | I cornerVi(const IVec& _corner) const; 54 | 55 | }; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /core/include/HMP/Refinement/Schemes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Refinement 8 | { 9 | 10 | enum class EScheme 11 | { 12 | Subdivide3x3, AdapterFaceSubdivide3x3, Adapter2FacesSubdivide3x3, AdapterEdgeSubdivide3x3, Inset, Subdivide2x2, Test, PlaneSplit 13 | }; 14 | 15 | extern const std::unordered_map schemes; 16 | 17 | namespace Schemes 18 | { 19 | 20 | extern const Scheme subdivide3x3; 21 | extern const Scheme adapterFaceSubdivide3x3; 22 | extern const Scheme adapter2FacesSubdivide3x3; 23 | extern const Scheme adapterEdgeSubdivide3x3; 24 | extern const Scheme inset; 25 | extern const Scheme subdivide2x2; 26 | extern const Scheme test; 27 | extern const Scheme planeSplit; 28 | 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /core/include/HMP/Refinement/Sub3x3AdapterCandidate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Refinement 12 | { 13 | 14 | class Sub3x3AdapterCandidate final 15 | { 16 | 17 | private: 18 | 19 | Dag::Element* m_element; 20 | std::optional m_scheme; 21 | std::vector m_adjacentEids, m_adjacentFids; 22 | I m_forwardFi, m_firstVi; 23 | 24 | void setup3x3Subdivide(const Meshing::Mesher& _mesher); 25 | 26 | void findRightAdapter(const Meshing::Mesher& _mesher); 27 | 28 | public: 29 | 30 | Sub3x3AdapterCandidate(Dag::Element& _element); 31 | 32 | Dag::Element& element() const; 33 | 34 | EScheme scheme() const; 35 | 36 | void addAdjacency(const Meshing::Mesher& _mesher, const Dag::Element& _refined, bool _edge); 37 | 38 | Dag::Refine& prepareAdapter() const; 39 | 40 | }; 41 | 42 | } -------------------------------------------------------------------------------- /core/include/HMP/Refinement/Sub3x3AdapterCandidateSet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Refinement 11 | { 12 | 13 | class Sub3x3AdapterCandidateSet final 14 | { 15 | 16 | private: 17 | 18 | using Map = std::unordered_map; 19 | 20 | Map m_sub3x3Map{}; // candidates that will be refined as a new Subdivide3x3 (they need to be processed first) 21 | Map m_nonSub3x3Map{}; // other candidates (they must be processed only after) 22 | 23 | void addAdjacency(const Meshing::Mesher& _mesher, Dag::Element& _candidate, const Dag::Element& _refined, bool _edge); 24 | 25 | public: 26 | 27 | void addAdjacency(Meshing::Mesher& _mesher, Dag::Refine& _refine); 28 | 29 | Sub3x3AdapterCandidate pop(); 30 | 31 | bool empty() const; 32 | 33 | }; 34 | 35 | } -------------------------------------------------------------------------------- /core/include/HMP/Refinement/Utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace HMP::Refinement::Utils 16 | { 17 | 18 | extern Real weldEpsFactor; 19 | extern Real weldEps; 20 | extern bool absWeldEps; 21 | 22 | Dag::Refine& prepare(I _forwardFi, I _firstVi, Refinement::EScheme _scheme); 23 | void apply(Meshing::Mesher& _mesher, Dag::Refine& _refine); 24 | 25 | } -------------------------------------------------------------------------------- /core/include/HMP/Utils/DerefRanged.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HMP::Utils 6 | { 7 | 8 | namespace Internal 9 | { 10 | 11 | template 12 | using NonConstIteratorDereference = decltype(*std::declval&>()); 13 | 14 | template 15 | using ConstIteratorDereference = decltype(*std::declval&>()); 16 | 17 | template 18 | constexpr NonConstIteratorDereference nonConstIteratorDereference(const NonConstIteratorReference& _reference) 19 | { 20 | return *_reference; 21 | } 22 | 23 | template 24 | constexpr ConstIteratorDereference constIteratorDereference(const ConstIteratorReference& _reference) 25 | { 26 | return *_reference; 27 | } 28 | 29 | } 30 | 31 | template 32 | class ConstDerefRanged: public ConstMapRanged< 33 | TIterable, 34 | Internal::ConstIteratorDereference, 35 | Internal::constIteratorDereference 36 | > 37 | { 38 | 39 | protected: 40 | 41 | using ConstMapRanged, Internal::constIteratorDereference>::ConstMapRanged; 42 | 43 | }; 44 | 45 | template 46 | class NonConstDerefRanged: public NonConstMapRanged< 47 | TIterable, 48 | Internal::NonConstIteratorDereference, 49 | Internal::nonConstIteratorDereference 50 | > 51 | { 52 | 53 | protected: 54 | 55 | using NonConstMapRanged, Internal::nonConstIteratorDereference>::NonConstMapRanged; 56 | 57 | }; 58 | 59 | template 60 | class ConstAndNonConstDerefRanged: public ConstAndNonConstMapRanged< 61 | TIterable, 62 | Internal::ConstIteratorDereference, 63 | Internal::constIteratorDereference, 64 | Internal::NonConstIteratorDereference, 65 | Internal::nonConstIteratorDereference 66 | > 67 | { 68 | 69 | protected: 70 | 71 | using ConstAndNonConstMapRanged< 72 | TIterable, 73 | Internal::ConstIteratorDereference, 74 | Internal::constIteratorDereference, 75 | Internal::NonConstIteratorDereference, 76 | Internal::nonConstIteratorDereference 77 | >::ConstAndNonConstMapRanged; 78 | 79 | }; 80 | 81 | } -------------------------------------------------------------------------------- /core/include/HMP/Utils/Serialization.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP::Utils::Serialization 10 | { 11 | 12 | namespace Internal 13 | { 14 | 15 | class SerializerWorker final : public cpputils::serialization::SerializerWorker 16 | { 17 | 18 | public: 19 | 20 | using cpputils::serialization::SerializerWorker::SerializerWorker; 21 | using cpputils::serialization::SerializerWorker::operator<<; 22 | 23 | void operator<<(const Vec& _data); 24 | 25 | }; 26 | 27 | class DeserializerWorker final : public cpputils::serialization::DeserializerWorker 28 | { 29 | 30 | public: 31 | 32 | using cpputils::serialization::DeserializerWorker::DeserializerWorker; 33 | using cpputils::serialization::DeserializerWorker::operator>>; 34 | 35 | void operator>>(Vec& _data); 36 | 37 | }; 38 | 39 | } 40 | 41 | using Serializer = cpputils::serialization::Serializer; 42 | using Deserializer = cpputils::serialization::Deserializer; 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /core/src/Actions/Delete.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Actions 4 | { 5 | 6 | void Delete::apply() 7 | { 8 | assert(mesher().shown(m_element)); 9 | m_operation->parents.attach(m_element); 10 | mesher().show(m_element, false); 11 | mesher().updateMesh(); 12 | } 13 | 14 | void Delete::unapply() 15 | { 16 | m_operation->parents.detachAll(false); 17 | mesher().show(m_element, true); 18 | mesher().updateMesh(); 19 | } 20 | 21 | Delete::Delete(Dag::Element& _element) 22 | : m_element{ _element }, m_operation{ *new Dag::Delete{} } 23 | {} 24 | 25 | const Dag::Element& Delete::element() const 26 | { 27 | return m_element; 28 | } 29 | 30 | const Dag::Delete& Delete::operation() const 31 | { 32 | return *m_operation; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /core/src/Actions/DeleteSome.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Actions 8 | { 9 | 10 | static std::vector, Dag::Element* const>> prepare(const std::vector& _elements) 11 | { 12 | return cpputils::range::of(_elements) 13 | .map([](Dag::Element* _el) 14 | { 15 | return std::pair, Dag::Element* const>{ Dag::NodeHandle{ *new Dag::Delete() }, _el }; 16 | }) 17 | .toVector(); 18 | } 19 | 20 | void DeleteSome::apply() 21 | { 22 | for (auto [operation, element] : m_operations) 23 | { 24 | operation->parents.attach(*element); 25 | mesher().show(*element, false); 26 | } 27 | mesher().updateMesh(); 28 | } 29 | 30 | void DeleteSome::unapply() 31 | { 32 | for (auto& [op, el] : cpputils::range::of(m_operations).reverse()) 33 | { 34 | mesher().show(*el, true); 35 | op->parents.detachAll(false); 36 | } 37 | mesher().updateMesh(); 38 | } 39 | 40 | DeleteSome::DeleteSome(const std::vector& _elements) 41 | : m_operations{ prepare(_elements) } 42 | {} 43 | 44 | std::pair DeleteSome::dereferenceOperation(const std::pair, Dag::Element*>& _pair) 45 | { 46 | const auto& [del, element] { _pair }; 47 | return { *del, *element }; 48 | } 49 | 50 | DeleteSome::Operations DeleteSome::operations() const 51 | { 52 | return cpputils::range::ofc(m_operations).map(&dereferenceOperation); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /core/src/Actions/Extrude.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP::Actions 10 | { 11 | 12 | void Extrude::apply() 13 | { 14 | m_oldState = mesher().state(); 15 | for (Dag::Element* parent : m_elements) 16 | { 17 | m_operation->parents.attach(*parent); 18 | } 19 | Dag::Element& child{ m_operation->children.single() }; 20 | std::vector newVerts; 21 | child.vids = ExtrudeUtils::apply(mesher(), *m_operation, newVerts); 22 | mesher().add({ &child }, newVerts); 23 | mesher().updateMesh(); 24 | } 25 | 26 | void Extrude::unapply() 27 | { 28 | m_operation->parents.detachAll(false); 29 | mesher().restore(m_oldState); 30 | mesher().updateMesh(); 31 | } 32 | 33 | Extrude::Extrude(const cpputils::collections::FixedVector& _elements, const cpputils::collections::FixedVector& _fis, I _firstVi, bool _clockwise) 34 | : m_elements{ _elements }, m_operation{ ExtrudeUtils::prepare(_fis, _firstVi, _clockwise) } 35 | { 36 | assert(_elements.size() == _fis.size()); 37 | assert(_firstVi < 8); 38 | } 39 | 40 | Extrude::Elements Extrude::elements() const 41 | { 42 | return cpputils::range::ofc(m_elements).dereference().immutable(); 43 | } 44 | 45 | const Dag::Extrude& Extrude::operation() const 46 | { 47 | return *m_operation; 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /core/src/Actions/FitCircle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Actions 13 | { 14 | 15 | void FitCircle::apply() 16 | { 17 | const Meshing::Mesher::Mesh& mesh{ mesher().mesh() }; 18 | std::vector oldVerts{}; 19 | oldVerts.reserve(m_vids.size()); 20 | for (const Id vid : m_vids) 21 | { 22 | oldVerts.push_back(mesh.vert(vid)); 23 | } 24 | if (!m_prepared) 25 | { 26 | m_prepared = true; 27 | const cinolib::Plane plane{ oldVerts }; 28 | const Real radius{ cpputils::range::of(oldVerts).map([&](const Vec& _v) { return _v.dist(plane.p); }).avg() }; 29 | const Vec baseY{ (oldVerts[0] - plane.p).cross(plane.n).normalized() }; 30 | const Vec baseX{ plane.n.cross(baseY).normalized() }; 31 | std::vector> isAndAs{ 32 | cpputils::range::enumerate(oldVerts) 33 | .map([&](const std::tuple& _e) 34 | { 35 | const auto& [i, v] { _e }; 36 | const Real x{ baseX.dot(v - plane.p) }; 37 | const Real y{ baseY.dot(v - plane.p) }; 38 | const Real a{ std::atan2(y, x) }; 39 | return std::pair{i, a}; 40 | }) 41 | .toVector() 42 | }; 43 | std::sort(isAndAs.begin(), isAndAs.end(), [](const std::pair& _a, const std::pair& _b) 44 | { 45 | return _a.second < _b.second; 46 | }); 47 | I firstI{}; 48 | for (const auto& [i, e] : cpputils::range::enumerate(isAndAs)) 49 | { 50 | if (e.first == 0) 51 | { 52 | firstI = i; 53 | break; 54 | } 55 | } 56 | std::vector is{ cpputils::range::of(isAndAs).map([](const std::pair& _e) { return _e.first; }).toVector() }; 57 | std::rotate(is.begin(), is.begin() + firstI, is.end()); 58 | for (I i{}; i < is.size(); i++) 59 | { 60 | const Real angle{ 2 * M_PI * static_cast(i) / static_cast(is.size()) }; 61 | m_otherVerts[is[i]] = plane.p + (baseX * std::cos(angle) + baseY * std::sin(angle)) * radius; 62 | } 63 | } 64 | for (const auto& [vid, pos] : cpputils::range::zip(m_vids, m_otherVerts)) 65 | { 66 | mesher().moveVert(vid, pos); 67 | } 68 | m_otherVerts.swap(oldVerts); 69 | mesher().updateMesh(); 70 | } 71 | 72 | void FitCircle::unapply() 73 | { 74 | apply(); 75 | } 76 | 77 | FitCircle::FitCircle(const std::vector& _vids) 78 | : m_vids{ _vids }, m_prepared{ false }, m_otherVerts(_vids.size()) 79 | { 80 | assert(m_vids.size() > 2); 81 | } 82 | 83 | const std::vector& FitCircle::vids() const 84 | { 85 | return m_vids; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /core/src/Actions/MakeConforming.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace HMP::Actions 16 | { 17 | 18 | void MakeConforming::installSub3x3Adapters() 19 | { 20 | Meshing::Mesher& mesher{ this->mesher() }; 21 | std::vector refines{}; 22 | for (Dag::Node* node : Dag::Utils::descendants(*root())) 23 | { 24 | if (node->isOperation() && node->operation().primitive == Dag::Operation::EPrimitive::Refine) 25 | { 26 | Dag::Refine& refine{ node->as() }; 27 | if (refine.scheme == Refinement::EScheme::Subdivide3x3) 28 | { 29 | refines.push_back(&refine); 30 | } 31 | } 32 | } 33 | bool didSomething{ false }; 34 | do 35 | { 36 | Refinement::Sub3x3AdapterCandidateSet set{}; 37 | // build a set of candidates based on the source refinements 38 | for (Dag::Refine* refine : refines) 39 | { 40 | set.addAdjacency(mesher, *refine); 41 | } 42 | didSomething = !set.empty(); 43 | // while there is a candidate 44 | while (!set.empty()) 45 | { 46 | // prepare and apply its refinement 47 | const Refinement::Sub3x3AdapterCandidate candidate{ set.pop() }; 48 | Dag::Refine& adapterRefine{ candidate.prepareAdapter() }; 49 | adapterRefine.parents.attach(candidate.element()); 50 | Refinement::Utils::apply(mesher, adapterRefine); 51 | m_operations.push_back({ &adapterRefine, &candidate.element() }); 52 | // if the refinement is a new Subdivide3x3, then add it to the set 53 | if (candidate.scheme() == Refinement::EScheme::Subdivide3x3) 54 | { 55 | set.addAdjacency(mesher, adapterRefine); 56 | refines.push_back(&adapterRefine); 57 | } 58 | } 59 | } 60 | while (didSomething); 61 | } 62 | 63 | void MakeConforming::apply() 64 | { 65 | m_oldState = mesher().state(); 66 | if (m_prepared) 67 | { 68 | for (auto [operation, element] : m_operations) 69 | { 70 | operation->parents.attach(*element); 71 | Refinement::Utils::apply(mesher(), *operation); 72 | } 73 | } 74 | else 75 | { 76 | m_prepared = true; 77 | installSub3x3Adapters(); 78 | } 79 | mesher().updateMesh(); 80 | } 81 | 82 | void MakeConforming::unapply() 83 | { 84 | for (auto& [op, el] : cpputils::range::of(m_operations).reverse()) 85 | { 86 | mesher().show(*el, true); 87 | op->parents.detachAll(false); 88 | } 89 | mesher().restore(m_oldState); 90 | mesher().updateMesh(); 91 | } 92 | 93 | MakeConforming::MakeConforming(): m_operations{}, m_prepared{ false } 94 | {} 95 | 96 | std::pair MakeConforming::dereferenceOperation(const std::pair, Dag::Element*>& _pair) 97 | { 98 | const auto& [refine, element] {_pair}; 99 | return { *refine, *element }; 100 | } 101 | 102 | MakeConforming::Operations MakeConforming::operations() const 103 | { 104 | return cpputils::range::ofc(m_operations).map(&dereferenceOperation); 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /core/src/Actions/Project.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace HMP::Actions 6 | { 7 | 8 | void Project::apply() 9 | { 10 | if (!m_prepared) 11 | { 12 | m_prepared = true; 13 | m_otherVerts = Projection::project(mesher().mesh(), m_target, m_pointFeats, m_pathFeats, m_options); 14 | if (m_options.vertexMask) 15 | { 16 | const std::vector& mask{*m_options.vertexMask}; 17 | const std::vector& oldVerts{mesher().mesh().vector_verts()}; 18 | for (I vi{}; vi < m_otherVerts.size(); vi++) 19 | { 20 | if (!mask[vi]) 21 | { 22 | m_otherVerts[vi] = oldVerts[vi]; 23 | } 24 | } 25 | } 26 | } 27 | std::vector oldVerts{ mesher().mesh().vector_verts() }; 28 | for (I vi{}; vi < m_otherVerts.size(); vi++) 29 | { 30 | mesher().moveVert(toId(vi), m_otherVerts[vi]); 31 | } 32 | m_otherVerts.swap(oldVerts); 33 | mesher().updateMesh(); 34 | } 35 | 36 | void Project::unapply() 37 | { 38 | apply(); 39 | } 40 | 41 | Project::Project(TargetMesh&& _target, const std::vector& _pointFeats, const std::vector& _pathFeats, const Projection::Options& _options) 42 | : m_target{ std::move(_target) }, m_pointFeats{ _pointFeats }, m_pathFeats{ _pathFeats }, m_options{ _options }, m_prepared{ false } 43 | {} 44 | 45 | Project::Project(const TargetMesh& _target, const std::vector& _pointFeats, const std::vector& _pathFeats, const Projection::Options& _options) 46 | : m_target{ _target }, m_pointFeats{ _pointFeats }, m_pathFeats{ _pathFeats }, m_options{ _options }, m_prepared{ false } 47 | {} 48 | 49 | const Project::TargetMesh& Project::target() const 50 | { 51 | return m_target; 52 | } 53 | 54 | const Projection::Options Project::options() const 55 | { 56 | return m_options; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /core/src/Actions/Refine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Actions 9 | { 10 | 11 | std::vector>> prepareRecursive(Dag::Element& _element, I _forwardFi, I _firstVi, Refinement::EScheme _scheme, I _depth) 12 | { 13 | assert(_depth >= 1 && _depth <= 3); 14 | Dag::Refine& refine{ Refinement::Utils::prepare(_forwardFi, _firstVi, _scheme) }; 15 | std::vector>> refines{ {&_element, refine} }; 16 | if (_depth > 1) 17 | { 18 | const I childDepth{ _depth - 1 }; 19 | for (Dag::Element& child : refine.children) 20 | { 21 | std::vector>> childRefines{ prepareRecursive(child, _forwardFi, _firstVi, _scheme, childDepth) }; 22 | refines.reserve(refines.size() + childRefines.size()); 23 | for (const auto& [el, op] : childRefines) 24 | { 25 | refines.emplace_back(el, op); 26 | } 27 | } 28 | } 29 | return refines; 30 | } 31 | 32 | void Refine::apply() 33 | { 34 | assert(mesher().shown(element())); 35 | m_oldState = mesher().state(); 36 | for (const auto& [element, operation] : m_operations) 37 | { 38 | operation->parents.attach(*element); 39 | Refinement::Utils::apply(mesher(), *operation); 40 | } 41 | mesher().updateMesh(); 42 | } 43 | 44 | void Refine::unapply() 45 | { 46 | for (const auto& [element, operation] : cpputils::range::of(m_operations).reverse()) 47 | { 48 | operation->parents.detachAll(false); 49 | mesher().show(*element, true); 50 | } 51 | mesher().restore(m_oldState); 52 | mesher().updateMesh(); 53 | } 54 | 55 | Refine::Refine(Dag::Element& _element, I _forwardFi, I _firstVi, Refinement::EScheme _scheme, I _depth) 56 | : m_operations{ prepareRecursive(_element, _forwardFi, _firstVi, _scheme, _depth) }, m_depth{ _depth } 57 | { 58 | assert(_depth >= 1 && _depth <= 3); 59 | assert(_forwardFi < 6); 60 | assert(_firstVi < 8); 61 | assert(Refinement::schemes.contains(_scheme)); 62 | } 63 | 64 | const Dag::Element& Refine::element() const 65 | { 66 | return *m_operations.front().first; 67 | } 68 | 69 | const Dag::Refine& Refine::operation() const 70 | { 71 | return *m_operations.front().second; 72 | } 73 | 74 | I Refine::depth() const 75 | { 76 | return m_depth; 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /core/src/Actions/RefineSome.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Actions 9 | { 10 | 11 | static std::vector, Dag::Element* const>> prepare(const std::vector& _elements) 12 | { 13 | return cpputils::range::of(_elements) 14 | .map([](Dag::Element* _el) 15 | { 16 | Dag::Refine& refine{ Refinement::Utils::prepare(0, 0, HMP::Refinement::EScheme::Subdivide3x3) }; 17 | return std::pair, Dag::Element* const>{ Dag::NodeHandle{ refine }, _el }; 18 | }) 19 | .toVector(); 20 | } 21 | 22 | void RefineSome::apply() 23 | { 24 | m_oldState = mesher().state(); 25 | for (auto [operation, element] : m_operations) 26 | { 27 | operation->parents.attach(*element); 28 | Refinement::Utils::apply(mesher(), *operation); 29 | } 30 | mesher().updateMesh(); 31 | } 32 | 33 | void RefineSome::unapply() 34 | { 35 | for (auto& [op, el] : cpputils::range::of(m_operations).reverse()) 36 | { 37 | mesher().show(*el, true); 38 | op->parents.detachAll(false); 39 | } 40 | mesher().restore(m_oldState); 41 | mesher().updateMesh(); 42 | } 43 | 44 | RefineSome::RefineSome(const std::vector& _elements) 45 | : m_operations{ prepare(_elements) } 46 | {} 47 | 48 | std::pair RefineSome::dereferenceOperation(const std::pair, Dag::Element*>& _pair) 49 | { 50 | const auto& [refine, element] { _pair }; 51 | return { *refine, *element }; 52 | } 53 | 54 | RefineSome::Operations RefineSome::operations() const 55 | { 56 | return cpputils::range::ofc(m_operations).map(&dereferenceOperation); 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /core/src/Actions/Root.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Actions 7 | { 8 | 9 | void Root::apply() 10 | { 11 | std::vector verts{ mesher().mesh().vector_verts() }; 12 | std::swap(m_otherRoot, root()); 13 | m_otherVerts.swap(verts); 14 | mesher().restore({}); 15 | Meshing::Utils::addTree(mesher(), *root(), verts); 16 | mesher().updateMesh(); 17 | } 18 | 19 | void Root::unapply() 20 | { 21 | apply(); 22 | } 23 | 24 | Root::Root(Dag::Element& _root, const std::vector& _verts) 25 | : m_newRoot{ _root }, m_newVerts{ _verts }, m_otherRoot{ &_root }, m_otherVerts{ _verts } 26 | {} 27 | 28 | const Dag::Element& Root::newRoot() const 29 | { 30 | return m_newRoot; 31 | } 32 | 33 | const std::vector& Root::newVerts() const 34 | { 35 | return m_otherVerts; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /core/src/Actions/Smooth.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Actions 12 | { 13 | 14 | void Smooth::apply() 15 | { 16 | if (!m_prepared) 17 | { 18 | m_prepared = true; 19 | cinolib::Polygonmesh<> surf; 20 | std::unordered_map surf2vol, vol2surf; 21 | cinolib::export_surface(mesher().mesh(), surf, vol2surf, surf2vol, false); 22 | const std::vector surfVids{ cpputils::range::of(surf2vol).map([](const auto& _it) { 23 | return std::get<1>(_it); 24 | }).toVector() }; 25 | m_otherVerts = mesher().mesh().vector_verts(); 26 | for (I i{}; i < m_surfIterations; ++i) 27 | { 28 | const std::vector& newSurfVerts{ Projection::smooth(surf) }; 29 | for (const auto& [vi, vert] : cpputils::range::enumerate(newSurfVerts)) 30 | { 31 | m_otherVerts[surf2vol.at(toId(vi))] = vert; 32 | } 33 | } 34 | for (I i{}; i < m_internalIterations; ++i) 35 | { 36 | m_otherVerts = Projection::smoothInternal(mesher().mesh(), surfVids, m_surfVertWeight); 37 | } 38 | } 39 | for (I vi{}; vi < m_otherVerts.size(); vi++) 40 | { 41 | const Vec oldVert{ mesher().mesh().vert(toId(vi)) }; 42 | mesher().moveVert(toId(vi), m_otherVerts[vi]); 43 | m_otherVerts[vi] = oldVert; 44 | } 45 | mesher().updateMesh(); 46 | } 47 | 48 | void Smooth::unapply() 49 | { 50 | apply(); 51 | } 52 | 53 | Smooth::Smooth(I _surfaceIterations, I _internalIterations, Real _surfVertWeight) 54 | : m_surfIterations{ _surfaceIterations }, m_internalIterations{ _internalIterations }, m_surfVertWeight{_surfVertWeight}, m_prepared{ false } 55 | {} 56 | 57 | const I Smooth::surfaceIterations() const 58 | { 59 | return m_surfIterations; 60 | } 61 | 62 | const I Smooth::internalIterations() const 63 | { 64 | return m_internalIterations; 65 | } 66 | 67 | const Real Smooth::surfVertWeight() const 68 | { 69 | return m_surfVertWeight; 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /core/src/Actions/SplitPlane.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Actions 12 | { 13 | 14 | void SplitPlane::apply() 15 | { 16 | m_oldState = mesher().state(); 17 | if (!m_prepared) 18 | { 19 | m_prepared = true; 20 | const Meshing::Mesher::Mesh& mesh{ mesher().mesh() }; 21 | std::unordered_set visitedEids; 22 | std::unordered_set visitedPids; 23 | std::queue toVisitEids; 24 | toVisitEids.push(m_eid); 25 | visitedEids.insert(m_eid); 26 | while (!toVisitEids.empty()) 27 | { 28 | const Id currEid{ toVisitEids.front() }; 29 | toVisitEids.pop(); 30 | for (const Id adjPid : mesh.adj_e2p(currEid)) 31 | { 32 | if (mesher().shown(adjPid) && !visitedPids.contains(adjPid)) 33 | { 34 | visitedPids.insert(adjPid); 35 | Id fid; 36 | for (const Id adjFid : mesh.adj_p2f(adjPid)) 37 | { 38 | if (mesh.face_contains_edge(adjFid, currEid)) 39 | { 40 | fid = adjFid; 41 | break; 42 | } 43 | } 44 | const I fi{ Meshing::Utils::fi(mesher().element(adjPid).vids, Meshing::Utils::fidVids(mesh, fid)) }; 45 | const I ei{ Meshing::Utils::ei(mesher().element(adjPid).vids, Meshing::Utils::eidVids(mesh, currEid)) }; 46 | const I vi = Meshing::Utils::firstFiVi(fi, ei); 47 | m_operations.emplace_back( 48 | Dag::NodeHandle{ Refinement::Utils::prepare(fi, vi, HMP::Refinement::EScheme::PlaneSplit) }, 49 | & mesher().element(adjPid) 50 | ); 51 | } 52 | } 53 | for (const Id adjFid : mesh.adj_e2f(currEid)) 54 | { 55 | for (const Id fidEid : mesh.adj_f2e(adjFid)) 56 | { 57 | if (fidEid != currEid && !mesh.edges_are_adjacent(currEid, fidEid)) 58 | { 59 | if (!visitedEids.contains(fidEid)) 60 | { 61 | visitedEids.insert(fidEid); 62 | toVisitEids.push(fidEid); 63 | } 64 | break; 65 | } 66 | } 67 | } 68 | } 69 | } 70 | for (auto [operation, element] : m_operations) 71 | { 72 | operation->parents.attach(*element); 73 | Refinement::Utils::apply(mesher(), *operation); 74 | } 75 | mesher().updateMesh(); 76 | } 77 | 78 | void SplitPlane::unapply() 79 | { 80 | for (auto& [op, el] : cpputils::range::of(m_operations).reverse()) 81 | { 82 | mesher().show(*el, true); 83 | op->parents.detachAll(false); 84 | } 85 | mesher().restore(m_oldState); 86 | mesher().updateMesh(); 87 | } 88 | 89 | SplitPlane::SplitPlane(Id _eid) 90 | : m_prepared{ false }, m_eid{ _eid } 91 | {} 92 | 93 | Id SplitPlane::eid() const 94 | { 95 | return m_eid; 96 | } 97 | 98 | std::pair SplitPlane::dereferenceOperation(const std::pair, Dag::Element*>& _pair) 99 | { 100 | const auto& [refine, element] { _pair }; 101 | return { *refine, *element }; 102 | } 103 | 104 | SplitPlane::Operations SplitPlane::operations() const 105 | { 106 | return cpputils::range::ofc(m_operations).map(&dereferenceOperation); 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /core/src/Actions/SubdivideAll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Actions 7 | { 8 | 9 | std::pair SubdivideAll::dereferenceOperation(const std::pair>& _pair) 10 | { 11 | const auto& [el, op] {_pair}; 12 | return { *el, *op }; 13 | } 14 | 15 | void SubdivideAll::apply() 16 | { 17 | if (!m_prepared) 18 | { 19 | const Meshing::Mesher::Mesh& mesh{ mesher().mesh() }; 20 | m_oldState = mesher().state(); 21 | m_prepared = true; 22 | for (Id pid{}; pid < mesh.num_polys(); pid++) 23 | { 24 | if (mesher().shown(pid)) 25 | { 26 | Dag::Refine& refine{ Refinement::Utils::prepare(0, Meshing::Utils::hexFiVis[0][0], Refinement::EScheme::Subdivide2x2) }; 27 | m_operations.emplace_back(&mesher().element(pid), Dag::NodeHandle{ refine }); 28 | } 29 | } 30 | } 31 | for (const auto& [parent, op] : m_operations) 32 | { 33 | op->parents.attach(*parent); 34 | Refinement::Utils::apply(mesher(), *op); 35 | } 36 | mesher().updateMesh(); 37 | } 38 | 39 | void SubdivideAll::unapply() 40 | { 41 | for (const auto& [parent, op] : m_operations) 42 | { 43 | mesher().show(*parent, true); 44 | op->parents.detachAll(false); 45 | } 46 | mesher().restore(m_oldState); 47 | mesher().updateMesh(); 48 | } 49 | 50 | SubdivideAll::SubdivideAll() 51 | : m_prepared{ false } 52 | {} 53 | 54 | SubdivideAll::Operations SubdivideAll::operations() const 55 | { 56 | return cpputils::range::ofc(m_operations).map(&dereferenceOperation); 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /core/src/Actions/Transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Actions 13 | { 14 | 15 | void Transform::apply() 16 | { 17 | const Meshing::Mesher::Mesh& mesh{ mesher().mesh() }; 18 | if (!m_prepared) 19 | { 20 | m_prepared = true; 21 | if (m_vids) 22 | { 23 | m_otherVerts.reserve(m_vids->size()); 24 | for (const Id vid : *m_vids) 25 | { 26 | m_otherVerts.push_back(m_transform * mesh.vert(vid)); 27 | } 28 | } 29 | else 30 | { 31 | m_otherVerts = mesh.vector_verts(); 32 | for (Vec& vert : m_otherVerts) 33 | { 34 | vert = m_transform * vert; 35 | } 36 | } 37 | } 38 | if (m_vids) 39 | { 40 | for (const auto& [vid, vert] : cpputils::range::zip(*m_vids, m_otherVerts)) 41 | { 42 | const Vec oldVert{ mesh.vert(vid) }; 43 | mesher().moveVert(vid, vert); 44 | vert = oldVert; 45 | } 46 | } 47 | else 48 | { 49 | std::vector oldVerts{ mesh.vector_verts() }; 50 | for (I vi{}; vi < oldVerts.size(); vi++) 51 | { 52 | mesher().moveVert(toId(vi), m_otherVerts[vi]); 53 | } 54 | m_otherVerts.swap(oldVerts); 55 | } 56 | mesher().updateMesh(); 57 | } 58 | 59 | void Transform::unapply() 60 | { 61 | apply(); 62 | } 63 | 64 | Transform::Transform(const Mat4& _transform, const std::optional>& _vids) 65 | : m_transform{ _transform }, m_vids{ _vids }, m_otherVerts{}, m_prepared{ false } 66 | {} 67 | 68 | const Mat4& Transform::transform() const 69 | { 70 | return m_transform; 71 | } 72 | 73 | const std::optional>& Transform::vids() const 74 | { 75 | return m_vids; 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /core/src/Commander.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP 8 | { 9 | 10 | // Commander::ActionBase 11 | 12 | Commander::ActionBase::ActionBase() 13 | : m_commander{}, m_applied{ false } 14 | {} 15 | 16 | void Commander::ActionBase::attach(Commander& _commander) 17 | { 18 | assert(!attached()); 19 | m_commander = &_commander; 20 | } 21 | 22 | void Commander::ActionBase::prepareAndApply() 23 | { 24 | assert(attached()); 25 | assert(!m_applied); 26 | m_applied = true; 27 | apply(); 28 | } 29 | 30 | void Commander::ActionBase::prepareAndUnapply() 31 | { 32 | assert(attached()); 33 | assert(m_applied); 34 | m_applied = false; 35 | unapply(); 36 | } 37 | 38 | Meshing::Mesher& Commander::ActionBase::mesher() 39 | { 40 | assert(attached()); 41 | return m_commander->m_project.mesher(); 42 | } 43 | 44 | const Meshing::Mesher& Commander::ActionBase::mesher() const 45 | { 46 | assert(attached()); 47 | return m_commander->m_project.mesher(); 48 | } 49 | 50 | Dag::NodeHandle& Commander::ActionBase::root() 51 | { 52 | assert(attached()); 53 | return m_commander->m_project.root(); 54 | } 55 | 56 | const Dag::Element* Commander::ActionBase::root() const 57 | { 58 | assert(attached()); 59 | return m_commander->m_project.root(); 60 | } 61 | 62 | bool Commander::ActionBase::attached() const 63 | { 64 | return m_commander; 65 | } 66 | 67 | bool Commander::ActionBase::applied() const 68 | { 69 | return m_applied; 70 | } 71 | 72 | // Commander::StackBase 73 | 74 | Commander::StackBase::StackBase() 75 | : HMP::Utils::ConstDerefRanged>{ m_data }, m_data{}, m_limit{ 1000 } 76 | {} 77 | 78 | Commander::Action& Commander::StackBase::pop() 79 | { 80 | assert(!empty()); 81 | Action& action{ *m_data.front() }; 82 | m_data.pop_front(); 83 | return action; 84 | } 85 | 86 | void Commander::StackBase::push(Action& _action) 87 | { 88 | m_data.push_front(&_action); 89 | keepLatest(m_limit); 90 | } 91 | 92 | I Commander::StackBase::limit() const 93 | { 94 | return m_limit; 95 | } 96 | 97 | void Commander::StackBase::limit(I _count) 98 | { 99 | m_limit = _count; 100 | keepLatest(m_limit); 101 | } 102 | 103 | void Commander::StackBase::removeOldest(I _count) 104 | { 105 | while (!m_data.empty() && _count > 0) 106 | { 107 | Action* action{ m_data.back() }; 108 | delete action; 109 | m_data.pop_back(); 110 | _count--; 111 | } 112 | } 113 | 114 | void Commander::StackBase::keepLatest(I _count) 115 | { 116 | while (m_data.size() > _count) 117 | { 118 | Action* action{ m_data.back() }; 119 | delete action; 120 | m_data.pop_back(); 121 | } 122 | } 123 | 124 | void Commander::StackBase::clear() 125 | { 126 | for (Action* action : m_data) 127 | { 128 | delete action; 129 | } 130 | m_data.clear(); 131 | } 132 | 133 | // Commander 134 | 135 | Commander::Commander(Project& _project) 136 | : m_project{ _project }, m_applied{}, m_unapplied{} 137 | {} 138 | 139 | Commander::~Commander() 140 | { 141 | m_unapplied.clear(); 142 | m_applied.clear(); 143 | } 144 | 145 | void Commander::apply(Action& _action) 146 | { 147 | _action.attach(*this); 148 | m_unapplied.clear(); 149 | _action.apply(); 150 | m_applied.push(_action); 151 | } 152 | 153 | void Commander::undo() 154 | { 155 | assert(canUndo()); 156 | Action& action{ m_applied.pop() }; 157 | action.unapply(); 158 | m_unapplied.push(action); 159 | } 160 | 161 | void Commander::redo() 162 | { 163 | assert(canRedo()); 164 | Action& action{ m_unapplied.pop() }; 165 | action.apply(); 166 | m_applied.push(action); 167 | } 168 | 169 | bool Commander::canUndo() const 170 | { 171 | return !m_applied.empty(); 172 | } 173 | 174 | bool Commander::canRedo() const 175 | { 176 | return !m_unapplied.empty(); 177 | } 178 | 179 | 180 | Commander::Stack& Commander::unapplied() 181 | { 182 | return m_unapplied; 183 | } 184 | 185 | const Commander::Stack& Commander::unapplied() const 186 | { 187 | return m_unapplied; 188 | } 189 | 190 | Commander::Stack& Commander::applied() 191 | { 192 | return m_applied; 193 | } 194 | 195 | const Commander::Stack& Commander::applied() const 196 | { 197 | return m_applied; 198 | } 199 | 200 | } -------------------------------------------------------------------------------- /core/src/Dag/Delete.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Dag 4 | { 5 | 6 | Delete::Delete() 7 | : Operation{ EPrimitive::Delete } 8 | {} 9 | 10 | } -------------------------------------------------------------------------------- /core/src/Dag/Element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Dag 4 | { 5 | 6 | Element::Element() 7 | : Node{ EType::Element }, parents{ parentsHandle() }, children{ childrenHandle() }, vids{}, pid{ noId } 8 | { 9 | vids.fill(noId); 10 | } 11 | 12 | Element::Set& Element::forward(bool _descending) 13 | { 14 | return _descending ? children : parents; 15 | } 16 | 17 | const Element::Set& Element::forward(bool _descending) const 18 | { 19 | return const_cast(this)->forward(_descending); 20 | } 21 | 22 | Element::Set& Element::back(bool _descending) 23 | { 24 | return forward(!_descending); 25 | } 26 | 27 | const Element::Set& Element::back(bool _descending) const 28 | { 29 | return const_cast(this)->back(_descending); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /core/src/Dag/Extrude.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace HMP::Dag 6 | { 7 | 8 | Extrude::ESource Extrude::sourceByParentCount(I _parentCount) 9 | { 10 | switch (_parentCount) 11 | { 12 | case 1: 13 | return ESource::Face; 14 | case 2: 15 | return ESource::Edge; 16 | case 3: 17 | return ESource::Vertex; 18 | default: 19 | cpputils::unreachable(); 20 | } 21 | } 22 | 23 | 24 | Extrude::Extrude() 25 | : Operation{ EPrimitive::Extrude } 26 | {} 27 | 28 | } -------------------------------------------------------------------------------- /core/src/Dag/NodeSet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace HMP::Dag 6 | { 7 | 8 | namespace Internal 9 | { 10 | 11 | // NodeSetData 12 | 13 | bool NodeSetData::add(Node& _node) 14 | { 15 | const auto it{ m_map.find(&_node) }; 16 | if (it != m_map.end()) 17 | { 18 | return false; 19 | } 20 | else 21 | { 22 | m_list.push_back(&_node); 23 | m_map.insert(it, { &_node, --m_list.end() }); 24 | return true; 25 | } 26 | } 27 | 28 | bool NodeSetData::remove(Node& _node) 29 | { 30 | const auto it{ m_map.find(&_node) }; 31 | if (it != m_map.end()) 32 | { 33 | m_list.erase(it->second); 34 | m_map.erase(it); 35 | return true; 36 | } 37 | else 38 | { 39 | return false; 40 | } 41 | } 42 | 43 | bool NodeSetData::clear() 44 | { 45 | const bool wasEmpty{ m_map.empty() }; 46 | m_map.clear(); 47 | m_list.clear(); 48 | return !wasEmpty; 49 | } 50 | 51 | // NodeSetHandle 52 | 53 | NodeSetHandle::NodeSetHandle(NodeSetData& _data, std::function _onAttach, std::function _onDetach, std::function _onDetachAll) 54 | : m_data{ _data }, m_onAttach{ _onAttach }, m_onDetach{ _onDetach }, m_onDetachAll{ _onDetachAll } 55 | {} 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /core/src/Dag/Operation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Dag 4 | { 5 | 6 | Operation::Operation(EPrimitive _primitive) 7 | : Node{ EType::Operation }, primitive{ _primitive }, parents{ parentsHandle() }, children{ childrenHandle() } 8 | {} 9 | 10 | Operation::Set& Operation::forward(bool _descending) 11 | { 12 | return _descending ? children : parents; 13 | } 14 | 15 | const Operation::Set& Operation::forward(bool _descending) const 16 | { 17 | return const_cast(this)->forward(_descending); 18 | } 19 | 20 | Operation::Set& Operation::back(bool _descending) 21 | { 22 | return forward(!_descending); 23 | } 24 | 25 | const Operation::Set& Operation::back(bool _descending) const 26 | { 27 | return const_cast(this)->back(_descending); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /core/src/Dag/Refine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Dag 4 | { 5 | 6 | Refine::Refine() 7 | : Operation{ EPrimitive::Refine } 8 | {} 9 | 10 | } -------------------------------------------------------------------------------- /core/src/Project.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP 4 | { 5 | 6 | Project::Project() 7 | : m_mesher{}, m_commander{ *reinterpret_cast(this) }, m_root{ nullptr } 8 | {} 9 | 10 | Commander& Project::commander() 11 | { 12 | return m_commander; 13 | } 14 | 15 | const Commander& Project::commander() const 16 | { 17 | return m_commander; 18 | } 19 | 20 | Dag::NodeHandle& Project::root() 21 | { 22 | return m_root; 23 | } 24 | 25 | const Dag::Element* Project::root() const 26 | { 27 | return m_root; 28 | } 29 | 30 | Meshing::Mesher& Project::mesher() 31 | { 32 | return m_mesher; 33 | } 34 | 35 | const Meshing::Mesher& Project::mesher() const 36 | { 37 | return m_mesher; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /core/src/Projection/percentileAdvance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Projection 8 | { 9 | 10 | static constexpr unsigned int c_minVertsForParallelFor{ 1024 }; 11 | 12 | std::vector percentileAdvance(const std::vector& _from, const std::vector& _to, const double _percentile) 13 | { 14 | std::vector out; 15 | percentileAdvance(_from, _to, out, _percentile); 16 | return out; 17 | } 18 | 19 | void percentileAdvance(const std::vector& _from, const std::vector& _to, std::vector& _out, const double _percentile) 20 | { 21 | _out.resize(_from.size()); 22 | Real maxLength{}; 23 | { 24 | std::vector lengths(_from.size()); 25 | const auto func{ [&](const Id _id) { 26 | const I i{ toI(_id) }; 27 | lengths[i] = (_to[i] - _from[i]).norm(); 28 | } }; 29 | cinolib::PARALLEL_FOR(0, toId(_from.size()), c_minVertsForParallelFor, func); 30 | std::sort(lengths.begin(), lengths.end()); 31 | I medianI{ static_cast(std::round(static_cast(lengths.size() - 1) * _percentile)) }; 32 | if (medianI <= lengths.size()) 33 | { 34 | maxLength = lengths[medianI]; 35 | } 36 | else 37 | { 38 | maxLength = std::numeric_limits::infinity(); 39 | } 40 | } 41 | const auto func{ [&](const Id _id) { 42 | const I i{ toI(_id) }; 43 | const Vec offset{ _to[i] - _from[i] }; 44 | const Vec clampedOffset{ offset.norm() <= maxLength ? offset : (offset.normalized() * maxLength) }; 45 | _out[i] = _from[i] + clampedOffset; 46 | } }; 47 | cinolib::PARALLEL_FOR(0, toId(_from.size()), c_minVertsForParallelFor, func); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /core/src/Refinement/Scheme.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace HMP::Refinement 12 | { 13 | 14 | bool Scheme::compareIVec2(const IVec2& _a, const IVec2& _b) 15 | { 16 | return (_a.x() == _b.x()) 17 | ? (_a.y() < _b.y()) 18 | : (_a.x() < _b.x()); 19 | } 20 | 21 | std::vector Scheme::findSurfVis() const 22 | { 23 | return cpputils::range::of(verts) 24 | .enumerate() 25 | .filter([&](const auto& _vertAndVi) { return isOnSurf(std::get<0>(_vertAndVi)); }) 26 | .map([](const auto& _vertAndVi) { return std::get<1>(_vertAndVi); }) 27 | .toVector(); 28 | } 29 | 30 | std::vector Scheme::findCornerVis() const 31 | { 32 | return cpputils::range::of(surfVis) 33 | .filter([&](const I _vi) { return isCorner(verts[_vi]); }) 34 | .toVector(); 35 | } 36 | 37 | IVec2 removeDim(const IVec& _vert, Id _dim) 38 | { 39 | switch (_dim) 40 | { 41 | case 0: 42 | return { _vert.y(), _vert.z() }; 43 | case 1: 44 | return { _vert.x(), _vert.z() }; 45 | case 2: 46 | return { _vert.x(), _vert.y() }; 47 | default: 48 | cpputils::unreachable(); 49 | } 50 | } 51 | 52 | Scheme::FaceSurfVisMap Scheme::findFacesSurfVisIs(Id _dim, bool _polarity) const 53 | { 54 | FaceSurfVisMap map{ &compareIVec2 }; 55 | for (I surfViI{}; surfViI < surfVis.size(); surfViI++) 56 | { 57 | const I vi{ surfVis[surfViI] }; 58 | const IVec& vert{ verts[vi] }; 59 | { 60 | const I comp{ vert[_dim] }; 61 | if (_polarity ? isMax(comp) : isMin(comp)) 62 | { 63 | if (!isCorner(vert)) 64 | { 65 | map.insert({ removeDim(vert, _dim), surfViI }); 66 | } 67 | } 68 | } 69 | } 70 | return map; 71 | } 72 | 73 | HexFaceData Scheme::findFacesSurfVisIs() const 74 | { 75 | static constexpr HexFaceData> surfaceDimAndPolarity{ { 76 | {2, false}, 77 | {2, true}, 78 | {0, true}, 79 | {0, false}, 80 | {1, false}, 81 | {1, true} 82 | } }; 83 | return cpputils::range::of(surfaceDimAndPolarity) 84 | .map([&](const auto& _dimAndPolarity) { return findFacesSurfVisIs(std::get<0>(_dimAndPolarity), std::get<1>(_dimAndPolarity)); }) 85 | .toArray(); 86 | } 87 | 88 | Scheme::Scheme(I _gridSize, const std::vector& _verts, const std::vector& _polys) 89 | : m_vidCorners{ 90 | IVec{0, 0, 0}, 91 | IVec{_gridSize, 0, 0}, 92 | IVec{_gridSize, _gridSize, 0}, 93 | IVec{0, _gridSize, 0}, 94 | IVec{0, 0, _gridSize}, 95 | IVec{_gridSize, 0, _gridSize}, 96 | IVec{_gridSize, _gridSize, _gridSize}, 97 | IVec{0, _gridSize, _gridSize} 98 | }, 99 | gridSize{ _gridSize }, verts{ _verts }, polys{ _polys }, surfVis{ findSurfVis() }, cornerVis{ findCornerVis() }, facesSurfVisIs{ findFacesSurfVisIs() } 100 | {} 101 | 102 | bool Scheme::isMin(I _comp) const 103 | { 104 | return _comp == 0; 105 | } 106 | 107 | bool Scheme::isMax(I _comp) const 108 | { 109 | return _comp == gridSize; 110 | } 111 | 112 | bool Scheme::isExtreme(I _comp) const 113 | { 114 | return isMin(_comp) || isMax(_comp); 115 | } 116 | 117 | bool Scheme::isOnSurf(const IVec& _vert) const 118 | { 119 | return isExtreme(_vert.x()) || isExtreme(_vert.y()) || isExtreme(_vert.z()); 120 | } 121 | 122 | bool Scheme::isCorner(const IVec& _vert) const 123 | { 124 | return isExtreme(_vert.x()) && isExtreme(_vert.y()) && isExtreme(_vert.z()); 125 | } 126 | 127 | I Scheme::cornerVi(const IVec& _corner) const 128 | { 129 | for (I vi{}; vi < 8; vi++) 130 | { 131 | if (_corner == m_vidCorners[vi]) 132 | { 133 | return vi; 134 | } 135 | } 136 | cpputils::unreachable(); 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /core/src/Refinement/Sub3x3AdapterCandidateSet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Refinement 8 | { 9 | 10 | void Sub3x3AdapterCandidateSet::addAdjacency(const Meshing::Mesher& _mesher, Dag::Element& _candidate, const Dag::Element& _refined, bool _edge) 11 | { 12 | // find the map that contains the candidate (if any) and the iterator 13 | Map* map{ &m_sub3x3Map }; 14 | auto it{ m_sub3x3Map.find(&_candidate) }; 15 | if (it == m_sub3x3Map.end()) 16 | { 17 | it = m_nonSub3x3Map.find(&_candidate); 18 | map = &m_nonSub3x3Map; 19 | } 20 | // get the existing candidate or create a new one 21 | Sub3x3AdapterCandidate candidate{ it == map->end() ? Sub3x3AdapterCandidate{_candidate} : it->second }; 22 | candidate.addAdjacency(_mesher, _refined, _edge); 23 | // remove it from the previous map (if any) and add it again since it changed 24 | if (it != map->end()) 25 | { 26 | map->erase(it); 27 | } 28 | Map& newMap{ (candidate.scheme() == Refinement::EScheme::Subdivide3x3) ? m_sub3x3Map : m_nonSub3x3Map }; 29 | newMap.insert({ &_candidate, candidate }); 30 | } 31 | 32 | void Sub3x3AdapterCandidateSet::addAdjacency(Meshing::Mesher& _mesher, Dag::Refine& _refine) 33 | { 34 | const Meshing::Mesher::Mesh& mesh{ _mesher.mesh() }; 35 | Dag::Element& refEl = _refine.parents.single(); 36 | const Id refPid{ refEl.pid }; 37 | // add face to face adjacent elements 38 | for (const Id candPid : mesh.adj_p2p(refPid)) 39 | { 40 | if (_mesher.shown(candPid)) // skip if deleted or already refined 41 | { 42 | addAdjacency(_mesher, _mesher.element(candPid), refEl, false); 43 | } 44 | } 45 | // add face to edge adjacent elements 46 | for (const Id sharedEid : mesh.adj_p2e(refPid)) // for each adjacent edge sharedEid 47 | { 48 | for (const Id candPid : mesh.adj_e2p(sharedEid)) // for each adjacent element candPid to sharedEid 49 | { 50 | // if candPid is not the refined element, nor is adjacent face to face to it 51 | if (candPid != refPid && static_cast(mesh.poly_shared_face(candPid, refPid)) == noId) 52 | { 53 | if (_mesher.shown(candPid)) // skip if deleted or already refined 54 | { 55 | addAdjacency(_mesher, _mesher.element(candPid), refEl, true); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | Sub3x3AdapterCandidate Sub3x3AdapterCandidateSet::pop() 63 | { 64 | // get the Subdivide3x3 candidates first 65 | Map& map{ m_sub3x3Map.empty() ? m_nonSub3x3Map : m_sub3x3Map }; 66 | const auto it{ map.begin() }; 67 | const Sub3x3AdapterCandidate candidate{ it->second }; 68 | map.erase(it); 69 | return candidate; 70 | } 71 | 72 | bool Sub3x3AdapterCandidateSet::empty() const 73 | { 74 | return m_sub3x3Map.empty() && m_nonSub3x3Map.empty(); 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /core/src/Utils/Serialization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Utils::Serialization 4 | { 5 | 6 | namespace Internal 7 | { 8 | 9 | // SerializerWorker 10 | 11 | void SerializerWorker::operator<<(const Vec& _data) 12 | { 13 | cpputils::serialization::SerializerWorker::operator<<(_data.x()); 14 | cpputils::serialization::SerializerWorker::operator<<(_data.y()); 15 | cpputils::serialization::SerializerWorker::operator<<(_data.z()); 16 | } 17 | 18 | // DeserializerWorker 19 | 20 | void DeserializerWorker::operator>>(Vec& _data) 21 | { 22 | cpputils::serialization::DeserializerWorker::operator>>(_data.x()); 23 | cpputils::serialization::DeserializerWorker::operator>>(_data.y()); 24 | cpputils::serialization::DeserializerWorker::operator>>(_data.z()); 25 | } 26 | 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /gui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.14) 2 | 3 | add_executable (gui 4 | "src/main.cpp" 5 | "src/App.cpp" 6 | "src/Widget.cpp" 7 | "src/SidebarWidget.cpp" 8 | "src/themer.cpp" 9 | "src/Utils/HrDescriptions.cpp" 10 | "src/Utils/Transform.cpp" 11 | "src/Utils/Controls.cpp" 12 | "src/Utils/Drawing.cpp" 13 | "src/Utils/Themer.cpp" 14 | "src/Utils/FilePicking.cpp" 15 | "src/Utils/Theme.cpp" 16 | "src/Widgets/Actions.cpp" 17 | "src/Widgets/Axes.cpp" 18 | "src/Widgets/Highlight.cpp" 19 | "src/Widgets/Pad.cpp" 20 | "src/Widgets/Smooth.cpp" 21 | "src/Widgets/Debug.cpp" 22 | "src/Widgets/Commander.cpp" 23 | "src/Widgets/Target.cpp" 24 | "src/Widgets/VertEdit.cpp" 25 | "src/Widgets/DirectVertEdit.cpp" 26 | "src/Widgets/Projection.cpp" 27 | "src/Widgets/Save.cpp" 28 | ) 29 | 30 | set_target_properties (gui PROPERTIES 31 | CXX_STANDARD 20 32 | CXX_EXTENSIONS OFF 33 | CXX_STANDARD_REQUIRED ON 34 | ) 35 | 36 | target_include_directories (gui 37 | PRIVATE "include" 38 | ) 39 | 40 | target_link_libraries (gui 41 | PRIVATE core 42 | ) 43 | 44 | target_compile_definitions(gui 45 | PUBLIC HMP_GUI_COMPILER_ID=\"${CMAKE_CXX_COMPILER_ID}\" 46 | ) 47 | 48 | if (HMP_GUI_ENABLE_DAG_VIEWER) 49 | 50 | target_sources(gui 51 | PRIVATE "src/DagViewer/createLayout.cpp" 52 | PRIVATE "src/DagViewer/Layout.cpp" 53 | PRIVATE "src/DagViewer/Widget.cpp" 54 | ) 55 | 56 | target_link_libraries (gui 57 | PRIVATE OGDF 58 | ) 59 | 60 | target_compile_definitions(gui 61 | PUBLIC HMP_GUI_ENABLE_DAG_VIEWER 62 | ) 63 | 64 | endif() 65 | 66 | if (HMP_GUI_ENABLE_AE3D2SHAPE_EXPORTER) 67 | 68 | target_sources(gui 69 | PRIVATE "src/Widgets/Ae3d2ShapeExporter.cpp" 70 | ) 71 | 72 | target_compile_definitions(gui 73 | PUBLIC HMP_GUI_ENABLE_AE3D2SHAPE_EXPORTER 74 | ) 75 | 76 | endif() 77 | 78 | if (HMP_GUI_CAPTURE) 79 | 80 | target_compile_definitions(gui 81 | PUBLIC HMP_GUI_CAPTURE 82 | ) 83 | 84 | endif() 85 | -------------------------------------------------------------------------------- /gui/include/HMP/Gui/App.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace HMP::Gui 14 | { 15 | 16 | namespace DagViewer 17 | { 18 | class Widget; 19 | } 20 | 21 | namespace Widgets 22 | { 23 | 24 | class Axes; 25 | class Debug; 26 | class Save; 27 | class Pad; 28 | class VertEdit; 29 | class DirectVertEdit; 30 | class Target; 31 | class Projection; 32 | class Smooth; 33 | class Ae3d2ShapeExporter; 34 | class Commander; 35 | class Actions; 36 | class Highlight; 37 | 38 | } 39 | 40 | class App final : public cpputils::mixins::ReferenceClass 41 | { 42 | 43 | public: 44 | 45 | struct Cursor final 46 | { 47 | Dag::Element* element{}; 48 | I fi{}, vi{}, ei{}; 49 | Id pid{ noId }, fid{ noId }, vid{ noId }, eid{ noId }; 50 | 51 | bool operator==(const Cursor&) const = default; 52 | }; 53 | 54 | private: 55 | 56 | void printUsage() const; 57 | 58 | HMP::Project m_project; 59 | cinolib::GLcanvas m_canvas; 60 | Vec2 m_mouse; 61 | Cursor m_cursor; 62 | 63 | public: 64 | 65 | const cinolib::GLcanvas& canvas; 66 | Meshing::Mesher& mesher; 67 | const Meshing::Mesher::Mesh& mesh; 68 | Commander& commander; 69 | cpputils::collections::SetNamer dagNamer; 70 | const Vec2& mouse; 71 | const Cursor& cursor; 72 | unsigned long long int lastActionDurationMicro{}; 73 | 74 | Widgets::Actions& actionsWidget; 75 | Widgets::Commander& commanderWidget; 76 | Widgets::Axes& axesWidget; 77 | Widgets::Target& targetWidget; 78 | Widgets::VertEdit& vertEditWidget; 79 | Widgets::DirectVertEdit& directVertEditWidget; 80 | Widgets::Save& saveWidget; 81 | Widgets::Projection& projectionWidget; 82 | Widgets::Debug& debugWidget; 83 | Widgets::Pad& padWidget; 84 | Widgets::Smooth& smoothWidget; 85 | Widgets::Highlight& highlightWidget; 86 | 87 | #ifdef HMP_GUI_ENABLE_DAG_VIEWER 88 | DagViewer::Widget& dagViewerWidget; 89 | #endif 90 | 91 | #ifdef HMP_GUI_ENABLE_AE3D2SHAPE_EXPORTER 92 | Widgets::Ae3d2ShapeExporter& ae3d2ShapeExporter; 93 | #endif 94 | 95 | private: 96 | 97 | const std::vector m_widgets; 98 | 99 | // actions 100 | void onActionApplied(); 101 | 102 | // other events 103 | void onThemeChanged(); 104 | 105 | // mesher events 106 | void onMesherRestored(const Meshing::Mesher::State& _state); 107 | 108 | // canvas events 109 | void onCameraChanged(); 110 | bool onMouseLeftClicked(int _modifiers); 111 | bool onMouseRightClicked(int _modifiers); 112 | bool onKeyPressed(int _key, int _modifiers); 113 | bool onMouseMoved(double _x, double _y); 114 | void onFilesDropped(const std::vector& _files); 115 | 116 | void loadTargetMeshOrProjectFile(const std::string& _file); 117 | 118 | int launch(); 119 | 120 | void setCursor(); 121 | 122 | #ifdef HMP_GUI_CAPTURE 123 | void prepareForCapture(); 124 | #endif 125 | 126 | App(); 127 | ~App(); 128 | 129 | public: 130 | 131 | static int run(const std::optional& _file = std::nullopt); 132 | 133 | Dag::Element* copiedElement{}; 134 | std::vector clickedWidgets; 135 | std::vector clickedElements; 136 | std::vector cursorsOfClickedElements; 137 | 138 | const Dag::Element& root() const; 139 | 140 | bool redo(); 141 | void applyAction(Commander::Action& _action); 142 | bool undo(); 143 | 144 | bool updateCursor(); 145 | void refitScene(); 146 | void resetCamera(); 147 | 148 | void serialize(const std::string& _filename) const; 149 | void deserialize(const std::string& _filename); 150 | 151 | }; 152 | 153 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/DagViewer/Layout.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Gui::DagViewer 9 | { 10 | 11 | class Layout final 12 | { 13 | 14 | public: 15 | 16 | class Node final 17 | { 18 | 19 | private: 20 | 21 | Vec2 m_center{}; 22 | const Dag::Node* m_node{}; 23 | 24 | 25 | public: 26 | 27 | Node(const Vec2& _center, const Dag::Node& _node); 28 | 29 | const Vec2& center() const; 30 | const Dag::Node& node() const; 31 | 32 | }; 33 | 34 | private: 35 | 36 | std::vector m_nodes; 37 | std::vector> m_lines; 38 | Real m_lineThickness; 39 | Real m_nodeRadius; 40 | Vec2 m_bottomLeft; 41 | Vec2 m_topRight; 42 | Vec2 m_size; 43 | Real m_aspectRatio; 44 | 45 | void calculateBoundingBox(); 46 | void expandBoundingBox(const Vec2& _center, Real _extent); 47 | 48 | public: 49 | 50 | Layout(); 51 | Layout(const std::vector& _nodes, const std::vector>& _lines, Real _lineThickness, Real _nodeRadius); 52 | Layout(std::vector&& _nodes, std::vector>&& _lines, Real _lineThickness, Real _nodeRadius); 53 | 54 | const std::vector>& lines() const; 55 | const std::vector& nodes() const; 56 | const Vec2& bottomLeft() const; 57 | const Vec2& topRight() const; 58 | const Vec2& size() const; 59 | double aspectRatio() const; 60 | Real lineThickness() const; 61 | Real nodeRadius() const; 62 | 63 | }; 64 | 65 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/DagViewer/Widget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Gui::DagViewer 9 | { 10 | 11 | class Widget final: public SidebarWidget 12 | { 13 | 14 | private: 15 | 16 | Layout m_layout; 17 | bool m_needsLayoutUpdate{ true }; 18 | bool m_tooManyNodes{ false }; 19 | Vec2 m_center_nl{ 0.5, 0.5 }; 20 | Real m_windowHeight_n{ 1.0 }; 21 | bool m_showLayoutPerformanceWarning{ false }; 22 | 23 | void zoom(Real _amount); 24 | void pan(const cinolib::vec2d& _amount); 25 | void clampView(); 26 | 27 | void drawTooltip(const Dag::Node& _node); 28 | 29 | const Dag::Node* m_hovered{}; 30 | 31 | void drawSidebar() override; 32 | 33 | void drawCanvas() override; 34 | 35 | void resetView(); 36 | 37 | void updateLayout(); 38 | 39 | void actionApplied() override; 40 | 41 | std::vector additionalFonts(const std::vector& _fonts) const override; 42 | 43 | public: 44 | 45 | Widget(); 46 | 47 | const Dag::Node* hovered() const; 48 | 49 | }; 50 | 51 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/DagViewer/createLayout.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Gui::DagViewer 7 | { 8 | 9 | Layout createLayout(const Dag::Node& _dag); 10 | 11 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/SidebarWidget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Gui 8 | { 9 | 10 | class App; 11 | 12 | class SidebarWidget : public Widget, private cinolib::SideBarItem 13 | { 14 | 15 | private: 16 | 17 | friend class App; 18 | 19 | void draw() override final; 20 | 21 | protected: 22 | 23 | SidebarWidget(const std::string& _title); 24 | 25 | virtual void drawSidebar() = 0; 26 | 27 | bool open() const; 28 | 29 | }; 30 | 31 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Utils/Controls.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Gui::Utils::Controls 11 | { 12 | 13 | bool dragVec(const char* _label, Vec& _vec, Real _speed, Real _min = -std::numeric_limits::infinity(), Real _max = std::numeric_limits::infinity(), const char* _format = "%.3f"); 14 | 15 | bool dragTranslationVec(const char* _label, Vec& _translation, Real _sceneSize); 16 | 17 | bool dragScaleVec(const char* _label, Vec& _scale, Real _defScale = 1.0); 18 | 19 | bool dragScale(const char* _label, Real& _scale, Real _defScale = 1.0); 20 | 21 | bool dragRotation(const char* _label, Vec& _rotation); 22 | 23 | bool colorButton(const char* _label, cinolib::Color& _color); 24 | 25 | bool sliderI(const char* _label, I& _value, I _min = 0, I _max = 10); 26 | 27 | bool sliderReal(const char* _label, Real& _value, Real _min = 0.0, Real _max = 1.0, bool _logarithmic = false, const char* _format = "%.3f"); 28 | 29 | bool sliderPercentage(const char* _label, Real& _value, Real _min = 0.0, Real _max = 1.0, const char* _format = "%.2f%%"); 30 | 31 | bool sliderPercentage(const char* _label, float& _value, float _min = 0.0, float _max = 1.0, const char* _format = "%.2f%%"); 32 | 33 | template requires std::is_enum_v 34 | bool combo(const char* _label, TEnum& _value, const std::initializer_list& _values); 35 | 36 | bool disabledButton(const char* _label, bool _enabled = false); 37 | 38 | bool disabledSmallButton(const char* _label, bool _enabled = false); 39 | 40 | constexpr ImVec4 toImVec4(const cinolib::Color& _color) 41 | { 42 | return ImVec4{ _color.r(), _color.g(), _color.b(), _color.a() }; 43 | } 44 | 45 | constexpr ImVec2 toImVec2(const Vec2& _vec) 46 | { 47 | return ImVec2{ static_cast(_vec._vec[0]), static_cast(_vec._vec[1]) }; 48 | } 49 | 50 | } 51 | 52 | #define HMP_GUI_UTILS_CONTROLS_IMPL 53 | #include 54 | #undef HMP_GUI_UTILS_CONTROLS_IMPL 55 | -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Utils/Controls.tpp: -------------------------------------------------------------------------------- 1 | #ifndef HMP_GUI_UTILS_CONTROLS_IMPL 2 | #error __FILE__ should not be directly included 3 | #endif 4 | 5 | #include 6 | 7 | namespace HMP::Gui::Utils::Controls 8 | { 9 | 10 | template requires std::is_enum_v 11 | bool combo(const char* _label, TEnum& _value, const std::initializer_list& _values) 12 | { 13 | int value{ static_cast(_value) }; 14 | if (ImGui::Combo(_label, &value, _values.begin(), static_cast(_values.size()))) 15 | { 16 | _value = static_cast(value); 17 | return true; 18 | } 19 | return false; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Utils/FilePicking.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Gui::Utils::FilePicking 7 | { 8 | 9 | std::optional open(); 10 | 11 | std::optional save(const std::string& _extension); 12 | 13 | std::optional save(); 14 | 15 | 16 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Utils/HrDescriptions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace HMP::Gui::Utils::HrDescriptions 30 | { 31 | 32 | using DagNamer = cpputils::collections::Namer; 33 | 34 | std::string name(const HMP::Dag::Node& _node, DagNamer& _dagNamer); 35 | std::string describe(Refinement::EScheme _scheme); 36 | std::string describe(Dag::Extrude::ESource _source); 37 | std::string describe(const Vec& _vec); 38 | std::string describe(const Mat4& _mat); 39 | std::string describe(const std::vector& _is); 40 | std::string describe(const std::vector& _ids); 41 | std::string describe(const std::vector& _flags); 42 | std::string describe(const HMP::Dag::Delete& _operation, const HMP::Dag::Element& _element, DagNamer& _dagNamer); 43 | std::string describe(const HMP::Dag::Extrude& _operation, const cpputils::collections::FixedVector& _elements, DagNamer& _dagNamer); 44 | std::string describe(const HMP::Dag::Refine& _operation, const HMP::Dag::Element& _element, DagNamer& _dagNamer); 45 | std::string describe(const HMP::Dag::Delete& _operation, DagNamer& _dagNamer); 46 | std::string describe(const HMP::Dag::Extrude& _operation, DagNamer& _dagNamer); 47 | std::string describe(const HMP::Dag::Refine& _operation, DagNamer& _dagNamer); 48 | 49 | std::string describe(const Actions::Delete& _action, DagNamer& _dagNamer); 50 | std::string describe(const Actions::Extrude& _action, DagNamer& _dagNamer); 51 | std::string describe(const Actions::Root& _action, DagNamer& _dagNamer); 52 | std::string describe(const Actions::MakeConforming& _action, DagNamer& _dagNamer); 53 | std::string describe(const Actions::Paste& _action, DagNamer& _dagNamer); 54 | std::string describe(const Actions::Project& _action); 55 | std::string describe(const Actions::Refine& _action, DagNamer& _dagNamer); 56 | std::string describe(const Actions::Transform& _action); 57 | std::string describe(const Actions::SubdivideAll& _action); 58 | std::string describe(const Actions::RefineSome& _action); 59 | std::string describe(const Actions::DeleteSome& _action); 60 | std::string describe(const Actions::Pad& _action); 61 | std::string describe(const Actions::Smooth& _action); 62 | std::string describe(const Actions::FitCircle& _action); 63 | std::string describe(const Actions::SplitPlane& _action, DagNamer& _dagNamer); 64 | std::string describe(const Commander::Action& _action, DagNamer& _dagNamer); 65 | 66 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Utils/Theme.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Gui::Utils 7 | { 8 | 9 | struct Theme final 10 | { 11 | 12 | float ovScale; 13 | float sbScale; 14 | float hue; 15 | bool dark; 16 | ImVec4 sbOk; 17 | ImVec4 sbWarn; 18 | ImVec4 sbErr; 19 | cinolib::Color bg; 20 | ImU32 ovHi; 21 | ImU32 ovMut; 22 | ImU32 ovWarn; 23 | ImU32 ovErr; 24 | ImU32 ovPolyHi; 25 | ImU32 ovFaceHi; 26 | cinolib::Color srcFace; 27 | cinolib::Color srcEdge; 28 | cinolib::Color tgtFace; 29 | cinolib::Color tgtEdge; 30 | #ifdef HMP_GUI_ENABLE_DAG_VIEWER 31 | ImU32 dagNodeEl; 32 | ImU32 dagNodeElHi; 33 | ImU32 dagNodeElMut; 34 | ImU32 dagNodeRefine; 35 | ImU32 dagNodeExtrude; 36 | ImU32 dagNodeDelete; 37 | #endif 38 | float ovAxesSat; 39 | float ovAxesVal; 40 | float ovPathSat; 41 | float ovPathVal; 42 | 43 | static Theme makeLight(float _hueDeg = 0.0f, float _scale = 1.0f); 44 | 45 | static Theme makeDark(float _hueDeg = 0.0f, float _scale = 1.0f); 46 | 47 | static Theme make(bool _dark = true, float _hueDeg = 0.0f, float _scale = 1.0f); 48 | 49 | }; 50 | 51 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Utils/Themer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Gui::Utils 8 | { 9 | 10 | class Themer final: public cpputils::mixins::ReferenceClass 11 | { 12 | 13 | private: 14 | 15 | Theme m_theme; 16 | 17 | void applyImGui() const; 18 | 19 | public: 20 | 21 | mutable cpputils::collections::Event onThemeChange{}; 22 | 23 | void setTheme(const Theme& _theme); 24 | 25 | const Theme& operator*() const; 26 | const Theme* operator->() const; 27 | 28 | }; 29 | 30 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Utils/Transform.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HMP::Gui::Utils 6 | { 7 | 8 | class Transform final 9 | { 10 | 11 | public: 12 | 13 | static bool isNull(Real _value, Real epsilon = 1e-6); 14 | static bool isNull(const Vec& _vec, Real epsilon = 1e-6); 15 | static Real wrapAngle(Real _angleDeg); 16 | static Vec wrapAngles(const Vec& _anglesDeg); 17 | static Vec rotationMatToVec(const Mat3& _mat); 18 | static Vec toDeg(const Vec& _rad); 19 | static Vec toRad(const Vec& _deg); 20 | static Mat3 rotationXMat(Real _angleDeg); 21 | static Mat3 rotationYMat(Real _angleDeg); 22 | static Mat3 rotationZMat(Real _angleDeg); 23 | static Mat3 rotationMat(const Vec& _axis, Real _angleDeg); 24 | static Mat3 rotationMat(const Vec& _eulerAnglesDeg); 25 | static Mat3 scaleMat(const Vec& _scale); 26 | static Mat4 translationMat(const Vec& _translation); 27 | static Mat4 homogeneous(const Mat3& _mat); 28 | static Vec2 dir(const Vec2& _from, const Vec2& _to, const Vec2& _else = { 1.0, 0.0 }); 29 | static Real angle(const Vec2& _from, const Vec2& _to); 30 | 31 | Vec origin{}; 32 | Vec translation{}; 33 | Vec scale{ 1.0 }; 34 | Vec rotation{}; 35 | 36 | Mat4 matrix() const; 37 | 38 | Real avgScale() const; 39 | 40 | bool isIdentity(Real epsilon = 1e-6) const; 41 | 42 | }; 43 | 44 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widget.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Gui 13 | { 14 | 15 | class App; 16 | 17 | class Widget: public cpputils::mixins::ReferenceClass, private cinolib::CanvasGuiItem 18 | { 19 | 20 | private: 21 | 22 | friend class App; 23 | 24 | App* m_app; 25 | 26 | void draw(const cinolib::GLcanvas& _canvas) final; 27 | 28 | protected: 29 | 30 | Widget(); 31 | 32 | virtual ~Widget() = default; 33 | 34 | App& app(); 35 | 36 | const App& app() const; 37 | 38 | virtual void printUsage() const; 39 | 40 | virtual void drawCanvas(); 41 | 42 | virtual bool keyPressed(const cinolib::KeyBinding& _binding); 43 | 44 | virtual bool mouseClicked(bool _right); 45 | 46 | virtual bool mouseMoved(const Vec2& _position); 47 | 48 | virtual void cursorChanged(); 49 | 50 | virtual void cameraChanged(); 51 | 52 | virtual void actionApplied(); 53 | 54 | virtual void actionPrepared(); 55 | 56 | virtual void serialize(HMP::Utils::Serialization::Serializer& _serializer) const; 57 | 58 | virtual void deserialize(HMP::Utils::Serialization::Deserializer& _deserializer); 59 | 60 | virtual void attached(); 61 | 62 | virtual std::vector additionalDrawables() const; 63 | 64 | virtual std::vector additionalFonts(const std::vector& _fonts) const; 65 | 66 | }; 67 | 68 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Actions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "HMP/Gui/App.hpp" 10 | 11 | namespace HMP::Gui::Widgets 12 | { 13 | 14 | class Actions final : public Widget 15 | { 16 | 17 | private: 18 | 19 | static constexpr cinolib::KeyBinding c_kbExtrudeFace{ GLFW_KEY_E }; 20 | static constexpr cinolib::KeyBinding c_kbExtrudeEdge{ GLFW_KEY_E, GLFW_MOD_ALT }; 21 | static constexpr cinolib::KeyBinding c_kbExtrudeVertex{ GLFW_KEY_E, GLFW_MOD_ALT | GLFW_MOD_SUPER }; 22 | static constexpr cinolib::KeyBinding c_kbExtrudeSelectedFace{ GLFW_KEY_E, GLFW_MOD_SHIFT }; 23 | static constexpr cinolib::KeyBinding c_kbRefineSelectedElements{ GLFW_KEY_H, GLFW_MOD_SHIFT }; 24 | static constexpr cinolib::KeyBinding c_kbDeleteSelectedElements{ GLFW_KEY_D, GLFW_MOD_SHIFT }; 25 | static constexpr cinolib::KeyBinding c_kbRefine{ GLFW_KEY_H }; 26 | static constexpr cinolib::KeyBinding c_kbDoubleRefine{ GLFW_KEY_H, GLFW_MOD_ALT }; 27 | static constexpr cinolib::KeyBinding c_kbFaceRefine{ GLFW_KEY_F }; 28 | static constexpr cinolib::KeyBinding c_kbDelete{ GLFW_KEY_D }; 29 | static constexpr cinolib::KeyBinding c_kbCopy{ GLFW_KEY_C }; 30 | static constexpr cinolib::KeyBinding c_kbPasteFace{ GLFW_KEY_V }; 31 | static constexpr cinolib::KeyBinding c_kbPasteEdge{ GLFW_KEY_V, GLFW_MOD_ALT }; 32 | static constexpr cinolib::KeyBinding c_kbPasteVertex{ GLFW_KEY_V, GLFW_MOD_ALT | GLFW_MOD_CONTROL }; 33 | static constexpr cinolib::KeyBinding c_kbMakeConforming{ GLFW_KEY_Q }; 34 | static constexpr cinolib::KeyBinding c_kbClear{ GLFW_KEY_N, GLFW_MOD_CONTROL }; 35 | static constexpr cinolib::KeyBinding c_kbSubdivideAll{ GLFW_KEY_0, GLFW_MOD_CONTROL }; 36 | static constexpr cinolib::KeyBinding c_kbSplitPlane{ GLFW_KEY_J }; 37 | static constexpr cinolib::KeyBinding c_kbFitCircle{ GLFW_KEY_G }; 38 | 39 | bool keyPressed(const cinolib::KeyBinding& _key) override; 40 | 41 | void printUsage() const override; 42 | 43 | bool hoveredExtrudeElements(Dag::Extrude::ESource _source, cpputils::collections::FixedVector& _elements, cpputils::collections::FixedVector& _fis, I& _firstVi, bool& _clockwise); 44 | bool clickedExtrudeElements(Dag::Extrude::ESource _source, cpputils::collections::FixedVector &_elements, cpputils::collections::FixedVector &_fis, I &_firstVi, bool &_clockwise, Dag::Element *element, App::Cursor cursor); 45 | bool clickedExtrudeEdgeElements(Dag::Extrude::ESource _source, cpputils::collections::FixedVector &_elements, cpputils::collections::FixedVector &_fis, I &_firstVi, bool &_clockwise, Dag::Element *element, App::Cursor cursor); 46 | bool clickedExtrudeVertexElements(Dag::Extrude::ESource _source, cpputils::collections::FixedVector &_elements, cpputils::collections::FixedVector &_fis, I &_firstVi, bool &_clockwise, Dag::Element *element, App::Cursor cursor); 47 | std::optional getEdgeInCommon(std::vector clickedElements); 48 | std::optional getVertexInCommon(std::vector clickedElements); 49 | std::vector> getClickedElementsFids(const std::vector& cursorsOfClickedElements); 50 | bool checkIfClickedExtrudeIsPossible(); 51 | void onExtrude(Dag::Extrude::ESource _source); 52 | void onExtrudeSelectedFace(); 53 | void onCopy(); 54 | void onPaste(Dag::Extrude::ESource _source); 55 | void onRefineElement(bool _twice); 56 | void onDelete(); 57 | void onRefineFace(); 58 | void onMakeConformant(); 59 | void onClear(); 60 | void onSubdivideAll(); 61 | void onRefineSelectedElements(); 62 | void onDeleteSelectedElements(); 63 | void onFitCircle(); 64 | void onSplitPlane(); 65 | 66 | std::vector selectedElements(); 67 | 68 | public: 69 | 70 | void clear(); 71 | 72 | bool compareByAdjacentFaces(App::Cursor a, App::Cursor b); 73 | }; 74 | 75 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Ae3d2ShapeExporter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Gui::Widgets 11 | { 12 | 13 | class Ae3d2ShapeExporter final: public SidebarWidget 14 | { 15 | 16 | private: 17 | 18 | struct Polygon final 19 | { 20 | std::vector vertices; 21 | Real quality; 22 | }; 23 | 24 | struct Keyframe final 25 | { 26 | std::vector polygons{}; 27 | cinolib::FreeCamera camera{}; 28 | Real qualityFactor; 29 | }; 30 | 31 | std::vector m_keyframes; 32 | std::optional m_sampleError; 33 | bool m_includeFrameSize{ false }; 34 | Real m_qualityFactor{ 0.0 }; 35 | 36 | bool exportKeyframes(const std::vector& _keyframes) const; 37 | 38 | bool requestExport() const; 39 | 40 | bool requestTargetExport() const; 41 | 42 | bool requestSample(); 43 | 44 | void clear(); 45 | 46 | I keyframeCount() const; 47 | 48 | bool empty() const; 49 | 50 | void drawSidebar() override; 51 | 52 | public: 53 | 54 | Ae3d2ShapeExporter(); 55 | 56 | }; 57 | 58 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Axes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HMP::Gui::Widgets 6 | { 7 | 8 | class Axes final: public Widget 9 | { 10 | 11 | private: 12 | 13 | void drawCanvas() override; 14 | 15 | }; 16 | 17 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Commander.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Gui::Widgets 8 | { 9 | 10 | class Commander final: public SidebarWidget 11 | { 12 | 13 | private: 14 | 15 | static constexpr cinolib::KeyBinding c_kbUndo{ GLFW_KEY_Z, GLFW_MOD_CONTROL }; 16 | static constexpr cinolib::KeyBinding c_kbRedo{ GLFW_KEY_Z, GLFW_MOD_CONTROL | GLFW_MOD_SHIFT }; 17 | 18 | void drawSidebar() override; 19 | 20 | bool keyPressed(const cinolib::KeyBinding& _key) override; 21 | 22 | void printUsage() const override; 23 | 24 | public: 25 | 26 | Commander(); 27 | 28 | }; 29 | 30 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Debug.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HMP::Gui::Widgets 11 | { 12 | 13 | class Debug final : public SidebarWidget 14 | { 15 | 16 | private: 17 | 18 | cinolib::DrawableSegmentSoup m_sectionSoup; 19 | 20 | unsigned int m_negJacTestRes{}, m_closeVertsTestRes{}; 21 | 22 | Real sectionValue() const; 23 | 24 | bool sectionExports{ false }; 25 | bool sectionExportsInv{ false }; 26 | Real testEps{ 1e-9 }; 27 | float fontBuildSize{ 13.0f }; 28 | float namesFontScale{ 1.0f }; 29 | Real sectionFactor{ 0.0 }; 30 | int sectionDim{ 1 }; 31 | float sectionLineThickness{ 1.0f }; 32 | bool exportColors{ false }; 33 | I fi{}, fiVi{}; 34 | Refinement::EScheme refineSingleScheme{ Refinement::EScheme::Test }; 35 | Real weldAbsEpsExp{ -6 }, weldEpsFactorExp{ -1 }; 36 | bool showElements{ false }, showVids{ false }, showEids{ false }, showFids{ false }, showPids{ false }; 37 | 38 | void selectCloseVerts(); 39 | 40 | void selectNegJacobianHexes(); 41 | 42 | void refineSingle(); 43 | 44 | void exportTarget() const; 45 | 46 | void exportSource(bool _includeInterior) const; 47 | 48 | void updateSection(); 49 | 50 | void drawCanvas() override; 51 | 52 | void drawSidebar() override; 53 | 54 | std::vector additionalDrawables() const override; 55 | 56 | void attached() override; 57 | 58 | static void exportWithColors(const cinolib::Polygonmesh<>& _mesh, const std::vector& _fidQuality, const char* _file); 59 | 60 | Real pidQuality(Id _pid) const; 61 | 62 | void exportQualityList() const; 63 | 64 | public: 65 | 66 | float themeHue{ 32.0f }; 67 | bool themeDark{ true }; 68 | float themeScale{ 1.0f }; 69 | 70 | Debug(); 71 | 72 | void updateTheme() const; 73 | 74 | }; 75 | 76 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/DirectVertEdit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Gui::Widgets 8 | { 9 | 10 | class DirectVertEdit final: public Widget 11 | { 12 | 13 | private: 14 | 15 | static constexpr cinolib::KeyBinding c_kbCancel{ GLFW_KEY_ESCAPE }; 16 | static constexpr cinolib::KeyBinding c_kbTranslate{ GLFW_KEY_T }; 17 | static constexpr cinolib::KeyBinding c_kbScale{ GLFW_KEY_S }; 18 | static constexpr cinolib::KeyBinding c_kbRotate{ GLFW_KEY_R }; 19 | static constexpr int c_kbOnX{ GLFW_KEY_LEFT_CONTROL }; 20 | static constexpr int c_kbOnY{ GLFW_KEY_LEFT_SHIFT }; 21 | static constexpr int c_kbOnZ{ GLFW_KEY_LEFT_ALT }; 22 | 23 | enum class EKind 24 | { 25 | Translation, Rotation, Scale 26 | }; 27 | 28 | bool m_pending; 29 | Vec2 m_centroid; 30 | EKind m_kind; 31 | bool m_onX, m_onY, m_onZ; 32 | Vec2 m_start; 33 | 34 | void printUsage() const override; 35 | 36 | bool mouseMoved(const Vec2& _position) override; 37 | 38 | bool keyPressed(const cinolib::KeyBinding& _key) override; 39 | 40 | void cameraChanged() override; 41 | 42 | bool mouseClicked(bool _right) override; 43 | 44 | void cancel(); 45 | 46 | void apply(); 47 | 48 | void drawCanvas() override; 49 | 50 | void update(); 51 | 52 | void request(EKind _kind); 53 | 54 | void attached() override; 55 | 56 | public: 57 | 58 | float lineThickness{ 1.0f }; 59 | float crossRadius{ 10.0f }; 60 | float textSize{ 20.0f }; 61 | Vec2 textMargin{ 10.0f }; 62 | 63 | DirectVertEdit(); 64 | 65 | bool pending() const; 66 | 67 | }; 68 | 69 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Highlight.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HMP::Gui::Widgets 6 | { 7 | 8 | class Highlight final: public Widget 9 | { 10 | 11 | private: 12 | 13 | void drawCanvas() override; 14 | 15 | bool mouseClicked(bool _right); 16 | }; 17 | 18 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Pad.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Gui::Widgets 7 | { 8 | 9 | class Pad final: public SidebarWidget 10 | { 11 | 12 | private: 13 | 14 | Real m_length{ 0.0 }; 15 | I m_smoothIterations{ 1 }; 16 | Real m_smoothSurfVertWeight{ 1.0 }; 17 | Real m_cornerShrinkFactor{ 0.5 }; 18 | 19 | void requestPad(); 20 | 21 | void drawSidebar() override; 22 | 23 | public: 24 | 25 | Pad(); 26 | 27 | }; 28 | 29 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Projection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace HMP::Gui::Widgets 14 | { 15 | 16 | class Projection final: public SidebarWidget 17 | { 18 | 19 | private: 20 | 21 | static constexpr cinolib::KeyBinding c_kbAddPathEdge{ GLFW_KEY_I, GLFW_MOD_SHIFT }; 22 | static constexpr cinolib::KeyBinding c_kbRemovePathEdge{ GLFW_KEY_I, GLFW_MOD_CONTROL }; 23 | static constexpr cinolib::KeyBinding c_kbClosePath{ GLFW_KEY_I, GLFW_MOD_ALT }; 24 | 25 | using EidsPath = HMP::Projection::Utils::EidsPath; 26 | using Point = HMP::Projection::Utils::Point; 27 | 28 | HMP::Projection::Options m_options; 29 | std::vector m_paths; 30 | cinolib::FeatureNetworkOptions m_featureFinderOptions; 31 | bool m_usePathAsCrease; 32 | float m_featureFinderCreaseAngle; 33 | bool m_showPaths, m_showAllPaths; 34 | I m_currentPath; 35 | bool m_lockSelectedVertices{ false }; 36 | 37 | void attached() override; 38 | 39 | void matchPath(I _i, bool _fromSource); 40 | 41 | void matchPaths(I _first, I _lastEx, bool _fromSource); 42 | 43 | void findPaths(bool _inSource); 44 | 45 | void setSourcePathFromSelection(I _path); 46 | 47 | template 48 | void setPathEdgeAtPoint(const Vec& _point, bool _add, const cinolib::AbstractMesh& _mesh, bool _source); 49 | 50 | ImVec4 pathColor(I _path) const; 51 | 52 | void removePath(I _path); 53 | 54 | const HMP::Projection::Options& options() const; 55 | 56 | void requestProjection(); 57 | 58 | bool canReproject() const; 59 | 60 | void requestReprojection(); 61 | 62 | void setTargetPathEdgeAtPoint(const Vec& _point, bool _add); 63 | 64 | void setSourcePathEdgeAtPoint(const Vec& _point, bool _add); 65 | 66 | void drawSidebar() override; 67 | 68 | void drawCanvas() override; 69 | 70 | void serialize(HMP::Utils::Serialization::Serializer& _serializer) const override; 71 | 72 | void deserialize(HMP::Utils::Serialization::Deserializer& _deserializer) override; 73 | 74 | void printUsage() const override; 75 | 76 | bool keyPressed(const cinolib::KeyBinding& _key) override; 77 | 78 | void closePath(); 79 | 80 | void addOrRemovePathEdge(bool _add); 81 | 82 | public: 83 | 84 | float lineThickness{ 1.5f }; 85 | 86 | Projection(); 87 | 88 | }; 89 | 90 | } 91 | 92 | #define HMP_GUI_WIDGETS_PROJECTION_IMPL 93 | #include 94 | #undef HMP_GUI_WIDGETS_PROJECTION_IMPL -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Save.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Gui::Widgets 9 | { 10 | 11 | class Save final: public SidebarWidget 12 | { 13 | 14 | private: 15 | 16 | static constexpr cinolib::KeyBinding c_kbSave{ GLFW_KEY_S, GLFW_MOD_CONTROL }; 17 | static constexpr cinolib::KeyBinding c_kbSaveNew{ GLFW_KEY_S, GLFW_MOD_CONTROL | GLFW_MOD_SHIFT }; 18 | static constexpr cinolib::KeyBinding c_kbLoad{ GLFW_KEY_O, GLFW_MOD_CONTROL }; 19 | 20 | std::string m_filename; 21 | std::chrono::time_point m_lastTime; 22 | bool m_loaded; 23 | 24 | void apply(bool _load, const std::string& _filename); 25 | 26 | const std::string& filename() const; 27 | 28 | void drawSidebar() override; 29 | 30 | void printUsage() const override; 31 | 32 | bool keyPressed(const cinolib::KeyBinding& _key) override; 33 | 34 | void exportMesh(const std::string& _filename) const; 35 | 36 | public: 37 | 38 | explicit Save(); 39 | 40 | void requestSave(); 41 | 42 | void requestSaveNew(); 43 | 44 | void requestLoad(); 45 | 46 | void requestLoad(const std::string& _filename); 47 | 48 | void requestExportMesh(); 49 | 50 | }; 51 | 52 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Smooth.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Gui::Widgets 7 | { 8 | 9 | class Smooth final: public SidebarWidget 10 | { 11 | 12 | private: 13 | 14 | I m_surfaceIterations{ 1 }; 15 | I m_internalIterations{ 1 }; 16 | Real m_surfVertWeight{ 1.0 }; 17 | 18 | void drawSidebar() override; 19 | 20 | public: 21 | 22 | Smooth(); 23 | 24 | void requestSmooth(); 25 | 26 | }; 27 | 28 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/Target.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace HMP::Gui::Widgets 15 | { 16 | 17 | class Target final: public SidebarWidget 18 | { 19 | 20 | private: 21 | 22 | static constexpr cinolib::KeyBinding c_kbLoad{ GLFW_KEY_L, GLFW_MOD_CONTROL }; 23 | static constexpr cinolib::KeyBinding c_kbToggleVisibility{ GLFW_KEY_U }; 24 | 25 | cinolib::DrawablePolygonmesh<> m_mesh; 26 | std::string m_filename; 27 | bool m_missingMeshFile; 28 | 29 | void drawSidebar() override; 30 | 31 | void serialize(HMP::Utils::Serialization::Serializer& _serializer) const override; 32 | void deserialize(HMP::Utils::Serialization::Deserializer& _deserializer) override; 33 | 34 | bool keyPressed(const cinolib::KeyBinding& _key) override; 35 | 36 | void printUsage() const override; 37 | 38 | std::vector additionalDrawables() const override; 39 | 40 | public: 41 | 42 | cinolib::Color faceColor, edgeColor; 43 | Utils::Transform transform; 44 | bool visible; 45 | float edgeThickness{ 2.0f }; 46 | 47 | Target(); 48 | 49 | mutable cpputils::collections::Event onMeshChanged; 50 | 51 | bool hasMesh() const; 52 | const cinolib::DrawablePolygonmesh<>& meshForDisplay() const; 53 | 54 | cinolib::Polygonmesh<> meshForProjection() const; 55 | 56 | void identity(bool _origin = true, bool _translation = true, bool _rotation = true, bool _scale = true); 57 | void fit(bool _origin = true, bool _translation = true, bool _scale = true); 58 | 59 | void updateTransform(); 60 | void updateVisibility(); 61 | void updateColor(bool _face = true, bool _edge = true); 62 | void updateEdgeThickness(); 63 | 64 | bool load(bool _keepTransform = false); 65 | void load(const std::string& _filename, bool _keepTransform = false); 66 | 67 | void clearMesh(); 68 | void requestApplyTransformToSource(); 69 | 70 | }; 71 | 72 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/Widgets/VertEdit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace HMP::Gui::Widgets 14 | { 15 | 16 | class VertEdit final : public SidebarWidget 17 | { 18 | 19 | private: 20 | 21 | static constexpr cinolib::KeyBinding c_kbSelectVertex{ GLFW_KEY_1 }; 22 | static constexpr cinolib::KeyBinding c_kbSelectEdge{ GLFW_KEY_2 }; 23 | static constexpr cinolib::KeyBinding c_kbSelectUpEdge{ GLFW_KEY_2, GLFW_MOD_ALT }; 24 | static constexpr cinolib::KeyBinding c_kbSelectFace{ GLFW_KEY_3 }; 25 | static constexpr cinolib::KeyBinding c_kbSelectUpFace{ GLFW_KEY_3, GLFW_MOD_ALT }; 26 | static constexpr cinolib::KeyBinding c_kbSelectPoly{ GLFW_KEY_4 }; 27 | static constexpr cinolib::KeyBinding c_kbDeselectAll{ GLFW_KEY_A, GLFW_MOD_CONTROL }; 28 | static constexpr cinolib::KeyBinding c_kbInvertSelection{ GLFW_KEY_A, GLFW_MOD_ALT }; 29 | static constexpr cinolib::KeyBinding c_kbSelectAll{ GLFW_KEY_A, GLFW_MOD_SHIFT }; 30 | static constexpr cinolib::KeyBinding c_kbSelectBox{ GLFW_KEY_K }; 31 | static constexpr int c_kmodSelectAdd{ GLFW_MOD_SHIFT }; 32 | static constexpr int c_kmodSelectRemove{ GLFW_MOD_CONTROL }; 33 | static constexpr int c_kmodSelectIntersect{ GLFW_MOD_ALT }; 34 | 35 | enum class ESelectionSource 36 | { 37 | Vertex, Edge, Face, Poly, UpFace, UpEdge 38 | }; 39 | 40 | enum class ESelectionMode 41 | { 42 | Add, Remove, Set, Intersect 43 | }; 44 | 45 | static constexpr Id vertsToVidsConvert(const std::unordered_map::value_type& _entry) 46 | { 47 | return _entry.first; 48 | } 49 | 50 | std::unordered_map m_verts; 51 | bool m_pendingAction; 52 | Utils::Transform m_unappliedTransform, m_appliedTransform; 53 | Vec m_centroid; 54 | std::optional m_boxSelectionStart{ std::nullopt }; 55 | 56 | bool addOrRemove(const Id* _vids, I _count, bool _add, bool _update); 57 | 58 | bool keyPressed(const cinolib::KeyBinding& _key) override; 59 | 60 | void printUsage() const override; 61 | 62 | void actionApplied() override; 63 | 64 | void actionPrepared() override; 65 | 66 | void onSelect(ESelectionSource _source, ESelectionMode _mode); 67 | 68 | void onSelectAll(bool _selected); 69 | 70 | void onBoxSelect(ESelectionMode _mode); 71 | 72 | void attached() override; 73 | 74 | bool mouseMoved(const Vec2&) override; 75 | 76 | void cameraChanged() override; 77 | 78 | public: 79 | 80 | float radius{ 3.0f }, lineThickness{ 1.5f }; 81 | 82 | using Vids = decltype(cpputils::range::ofc(m_verts).map(&vertsToVidsConvert)); 83 | 84 | cpputils::collections::Event onVidsChanged{}; 85 | 86 | VertEdit(); 87 | 88 | bool add(Id _vid, bool _update = true); 89 | 90 | bool remove(Id _vid, bool _update = true); 91 | 92 | bool add(const std::vector& _vids, bool _update = true); 93 | 94 | bool remove(const std::vector& _vids, bool _update = true); 95 | 96 | bool intersect(const std::vector& _vids, bool _update = true); 97 | 98 | bool has(Id _vid) const; 99 | 100 | Vids vids() const; 101 | 102 | void clear(); 103 | 104 | bool empty() const; 105 | 106 | const Vec& centroid() const; 107 | 108 | Utils::Transform& transform(); 109 | 110 | const Utils::Transform& transform() const; 111 | 112 | void applyTransform(); 113 | 114 | bool pendingAction() const; 115 | 116 | void cancel(); 117 | 118 | void applyAction(); 119 | 120 | void updateCentroid(); 121 | 122 | void drawSidebar() override; 123 | 124 | void drawCanvas() override; 125 | 126 | }; 127 | 128 | } -------------------------------------------------------------------------------- /gui/include/HMP/Gui/themer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HMP::Gui 6 | { 7 | 8 | extern Utils::Themer themer; 9 | 10 | } -------------------------------------------------------------------------------- /gui/src/DagViewer/Layout.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Gui::DagViewer 8 | { 9 | 10 | // Layout::Node 11 | 12 | Layout::Node::Node(const Vec2& _center, const Dag::Node& _node) 13 | : m_center(_center), m_node{ &_node } 14 | {} 15 | 16 | const Vec2& Layout::Node::center() const 17 | { 18 | return m_center; 19 | } 20 | 21 | const Dag::Node& Layout::Node::node() const 22 | { 23 | return *m_node; 24 | } 25 | 26 | // Layout 27 | 28 | void Layout::calculateBoundingBox() 29 | { 30 | if (m_lines.empty() && m_nodes.empty()) 31 | { 32 | m_topRight = m_bottomLeft = Vec2{ 0,0 }; 33 | } 34 | else 35 | { 36 | if (m_nodes.empty()) 37 | { 38 | m_topRight = m_bottomLeft = m_lines[0].first; 39 | } 40 | else 41 | { 42 | m_topRight = m_bottomLeft = m_nodes[0].center(); 43 | } 44 | const Real halfLineThickness = m_lineThickness / 2; 45 | for (const std::pair& line : m_lines) 46 | { 47 | expandBoundingBox(line.first, halfLineThickness); 48 | expandBoundingBox(line.second, halfLineThickness); 49 | } 50 | for (const Node& node : m_nodes) 51 | { 52 | expandBoundingBox(node.center(), m_nodeRadius); 53 | } 54 | } 55 | m_size = m_topRight - m_bottomLeft; 56 | m_aspectRatio = m_size.y() != 0.0 ? m_size.x() / m_size.y() : 1.0; 57 | } 58 | 59 | void Layout::expandBoundingBox(const Vec2& _center, Real _extent) 60 | { 61 | m_bottomLeft.x() = std::min(m_bottomLeft.x(), _center.x() - _extent); 62 | m_bottomLeft.y() = std::min(m_bottomLeft.y(), _center.y() - _extent); 63 | m_topRight.x() = std::max(m_topRight.x(), _center.x() + _extent); 64 | m_topRight.y() = std::max(m_topRight.y(), _center.y() + _extent); 65 | } 66 | 67 | Layout::Layout() 68 | : m_nodes{}, m_lines{}, m_lineThickness{ 0.01 }, m_nodeRadius{ 1 } 69 | { 70 | calculateBoundingBox(); 71 | } 72 | 73 | Layout::Layout(const std::vector& _nodes, const std::vector>& _lines, Real _nodeRadius, Real _lineThickness) 74 | : m_nodes{ _nodes }, m_lines{ _lines }, m_lineThickness{ _lineThickness }, m_nodeRadius{ _nodeRadius } 75 | { 76 | assert(m_nodeRadius > 0.f); 77 | assert(m_lineThickness > 0.f); 78 | calculateBoundingBox(); 79 | } 80 | 81 | Layout::Layout(std::vector&& _nodes, std::vector>&& _lines, Real _nodeRadius, Real _lineThickness) 82 | : m_nodes{ std::move(_nodes) }, m_lines{ std::move(_lines) }, m_lineThickness{ _lineThickness }, m_nodeRadius{ _nodeRadius } 83 | { 84 | assert(m_nodeRadius > 0.f); 85 | assert(m_lineThickness > 0.f); 86 | calculateBoundingBox(); 87 | } 88 | 89 | const std::vector>& Layout::lines() const 90 | { 91 | return m_lines; 92 | } 93 | 94 | const std::vector& Layout::nodes() const 95 | { 96 | return m_nodes; 97 | } 98 | 99 | const Vec2& Layout::bottomLeft() const 100 | { 101 | return m_bottomLeft; 102 | } 103 | 104 | const Vec2& Layout::topRight() const 105 | { 106 | return m_topRight; 107 | } 108 | 109 | const Vec2& Layout::size() const 110 | { 111 | return m_size; 112 | } 113 | 114 | Real Layout::aspectRatio() const 115 | { 116 | return m_aspectRatio; 117 | } 118 | 119 | Real Layout::lineThickness() const 120 | { 121 | return m_lineThickness; 122 | } 123 | 124 | Real Layout::nodeRadius() const 125 | { 126 | return m_nodeRadius; 127 | } 128 | 129 | } -------------------------------------------------------------------------------- /gui/src/SidebarWidget.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Gui 4 | { 5 | 6 | void SidebarWidget::draw() 7 | { 8 | drawSidebar(); 9 | } 10 | 11 | SidebarWidget::SidebarWidget(const std::string& _title) : cinolib::SideBarItem{ _title } 12 | {} 13 | 14 | bool SidebarWidget::open() const 15 | { 16 | return show_open; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /gui/src/Utils/Controls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Gui::Utils::Controls 7 | { 8 | 9 | bool dragVec(const char* _label, Vec& _vec, Real _speed, Real _min, Real _max, const char* _format) 10 | { 11 | cinolib::vec3 xyz{ _vec.cast() }; 12 | const bool changed{ ImGui::DragFloat3(_label, xyz.ptr(), static_cast(_speed) / 1000.0f, static_cast(_min), static_cast(_max), _format, ImGuiSliderFlags_AlwaysClamp) }; 13 | if (changed) 14 | { 15 | _vec = xyz.cast(); 16 | } 17 | return changed; 18 | } 19 | 20 | bool dragTranslationVec(const char* _label, Vec& _translation, Real _sceneSize) 21 | { 22 | return dragVec(_label, _translation, _sceneSize); 23 | } 24 | 25 | bool dragScaleVec(const char* _label, Vec& _scale, Real _defScale) 26 | { 27 | Vec percScale{ _scale * 100.0 }; 28 | const bool changed{ dragVec(_label, percScale, 100.0 * _defScale, -100.0 * 100.0 * _defScale, 100.0 * 100.0 * _defScale, "%.2f%%") }; 29 | if (changed) 30 | { 31 | _scale = percScale / 100.0; 32 | } 33 | return changed; 34 | } 35 | 36 | bool dragScale(const char* _label, Real& _scale, Real _defScale) 37 | { 38 | float percScale{ static_cast(_scale * 100.0) }; 39 | float defScaleF{ static_cast(_defScale) }; 40 | const bool changed{ ImGui::DragFloat(_label, &percScale, 100.0f * defScaleF / 1000.0f, 100.0f / 100.0f * defScaleF, 100.0f * 100.0f * defScaleF, "%.2f%%", ImGuiSliderFlags_AlwaysClamp) }; 41 | if (changed) 42 | { 43 | _scale = static_cast(percScale) / 100.0; 44 | } 45 | return changed; 46 | } 47 | 48 | bool dragRotation(const char* _label, Vec& _rotation) 49 | { 50 | Vec wrappedRotation{ Transform::wrapAngles(_rotation) }; 51 | const bool changed{ dragVec(_label, wrappedRotation, 360.0, -360.0 * 2, 360.0 * 2, "%.1f deg") }; 52 | if (changed) 53 | { 54 | _rotation = wrappedRotation; 55 | } 56 | return changed; 57 | } 58 | 59 | bool colorButton(const char* _label, cinolib::Color& _color) 60 | { 61 | return ImGui::ColorEdit4(_label, _color.rgba, 62 | ImGuiColorEditFlags_NoInputs | 63 | ImGuiColorEditFlags_AlphaBar | 64 | ImGuiColorEditFlags_AlphaPreviewHalf | 65 | //ImGuiColorEditFlags_DisplayHSV | 66 | //ImGuiColorEditFlags_InputHSV | 67 | ImGuiColorEditFlags_PickerHueWheel 68 | ); 69 | } 70 | 71 | bool sliderI(const char* _label, I& _value, I _min, I _max) 72 | { 73 | int value{ static_cast(std::clamp(_value, _min, _max)) }; 74 | if (ImGui::SliderInt(_label, &value, static_cast(_min), static_cast(_max), "%d", ImGuiSliderFlags_AlwaysClamp)) 75 | { 76 | _value = static_cast(value); 77 | return true; 78 | } 79 | return false; 80 | } 81 | 82 | bool sliderReal(const char* _label, Real& _value, Real _min, Real _max, bool _logarithmic, const char* _format) 83 | { 84 | float value{ static_cast(std::clamp(_value, _min, _max)) }; 85 | ImGuiSliderFlags flags{ ImGuiSliderFlags_AlwaysClamp }; 86 | if (_logarithmic) 87 | { 88 | flags |= ImGuiSliderFlags_Logarithmic; 89 | } 90 | if (ImGui::SliderFloat(_label, &value, static_cast(_min), static_cast(_max), _format, flags)) 91 | { 92 | _value = static_cast(value); 93 | return true; 94 | } 95 | return false; 96 | } 97 | 98 | bool sliderPercentage(const char* _label, Real& _value, Real _min, Real _max, const char* _format) 99 | { 100 | Real value{ _value * 100.0 }; 101 | if (sliderReal(_label, value, _min * 100.0, _max * 100.0, false, _format)) 102 | { 103 | _value = value / 100.0; 104 | return true; 105 | } 106 | return false; 107 | } 108 | 109 | bool sliderPercentage(const char* _label, float& _value, float _min, float _max, const char* _format) 110 | { 111 | Real value{ static_cast(_value) }; 112 | if (sliderPercentage(_label, value, static_cast(_min), static_cast(_max), _format)) 113 | { 114 | _value = static_cast(value); 115 | return true; 116 | } 117 | return false; 118 | } 119 | 120 | bool disabledButton(const char* _label, bool _enabled) 121 | { 122 | if (!_enabled) 123 | { 124 | ImGui::BeginDisabled(); 125 | } 126 | const bool pressed{ ImGui::Button(_label) }; 127 | if (!_enabled) 128 | { 129 | ImGui::EndDisabled(); 130 | } 131 | return pressed; 132 | } 133 | 134 | bool disabledSmallButton(const char* _label, bool _enabled) 135 | { 136 | if (!_enabled) 137 | { 138 | ImGui::BeginDisabled(); 139 | } 140 | const bool pressed{ ImGui::SmallButton(_label) }; 141 | if (!_enabled) 142 | { 143 | ImGui::EndDisabled(); 144 | } 145 | return pressed; 146 | } 147 | 148 | } -------------------------------------------------------------------------------- /gui/src/Utils/FilePicking.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace HMP::Gui::Utils::FilePicking 8 | { 9 | 10 | std::string withExt(const std::string& _filename, const std::string& _ext) 11 | { 12 | if (!_filename.empty()) 13 | { 14 | std::filesystem::path path{ _filename }; 15 | std::string oldExtLower{ path.extension().string() }; 16 | for (char& c : oldExtLower) c = static_cast(std::tolower(c)); 17 | std::string newExtLower{ _ext }; 18 | for (char& c : newExtLower) c = static_cast(std::tolower(c)); 19 | if (oldExtLower != ("." + newExtLower)) 20 | { 21 | return _filename + "." + _ext; 22 | } 23 | else 24 | { 25 | return path.replace_extension(_ext).string(); 26 | } 27 | } 28 | return _filename; 29 | } 30 | 31 | std::optional toOptional(const std::string& _filenameOrEmpty) 32 | { 33 | if (_filenameOrEmpty.empty()) 34 | { 35 | return std::nullopt; 36 | } 37 | return _filenameOrEmpty; 38 | } 39 | 40 | std::optional open() 41 | { 42 | return toOptional(cinolib::file_dialog_open()); 43 | } 44 | 45 | std::optional save(const std::string& _extension) 46 | { 47 | std::optional filename{ save() }; 48 | if (filename) 49 | { 50 | const std::string dotExt{ "." + _extension }; 51 | std::string oldExt{ std::filesystem::path{ *filename }.extension().string() }; 52 | for (char& c : oldExt) c = static_cast(std::tolower(c)); 53 | if (oldExt != dotExt) 54 | { 55 | return *filename + dotExt; 56 | } 57 | } 58 | return filename; 59 | } 60 | 61 | std::optional save() 62 | { 63 | return toOptional(cinolib::file_dialog_save()); 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /gui/src/Utils/Theme.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace HMP::Gui::Utils 10 | { 11 | 12 | inline constexpr cinolib::Color hsv(float _r, float _g, float _b, float _a = 1.0f) 13 | { 14 | return cinolib::Color::hsv2rgb(_r, _g, _b, _a); 15 | } 16 | 17 | using Drawing::toImU32; 18 | using Controls::toImVec4; 19 | 20 | static constexpr float okHue{ 0.4f }, warnHue{ 0.15f }, errHue{ 0.02f }; 21 | 22 | #ifdef HMP_GUI_ENABLE_DAG_VIEWER 23 | static constexpr float dagNodeRefineHueShift{ 0.4f }, dagNodeExtrudeHueShift{ 0.6f }, dagNodeDeleteHueShift{ 0.8f }; 24 | #endif 25 | 26 | Theme Theme::makeLight(float _hueDeg, float _scale) 27 | { 28 | const float hue{ _hueDeg / 360.0f }; 29 | return Theme{ 30 | .ovScale = (1.0f + _scale * 2.0f) / 3.0f, 31 | .sbScale = _scale, 32 | .hue = hue, 33 | .dark = false, 34 | .sbOk{ toImVec4(hsv(okHue, 0.8f, 0.4f)) }, 35 | .sbWarn{ toImVec4(hsv(warnHue, 0.8f, 0.45f))}, 36 | .sbErr{ toImVec4(hsv(errHue, 0.85f, 0.45f))}, 37 | .bg{ hsv(hue, 0.0f, 0.97f) }, 38 | .ovHi = toImU32(hsv(hue, 0.8f, 0.9f)), 39 | .ovMut = toImU32(hsv(hue, 0.0f, 0.0f, 0.28f)), 40 | .ovWarn = toImU32(hsv(warnHue, 0.8f, 0.55f)), 41 | .ovErr = toImU32(hsv(errHue, 1.0f, 0.75f)), 42 | .ovPolyHi = toImU32(hsv(hue, 0.3f, 0.85f, 0.2f)), 43 | .ovFaceHi = toImU32(hsv(hue, 0.75f, 1.0f, 0.3f)), 44 | .srcFace{ hsv(hue, 0.0f, 0.8f) }, 45 | .srcEdge{ hsv(hue, 0.0f, 0.22f) }, 46 | .tgtFace{ hsv(hue, 0.0f, 0.0f, 0.08f) }, 47 | .tgtEdge{ hsv(hue, 0.0f, 0.0f, 0.24f) }, 48 | #ifdef HMP_GUI_ENABLE_DAG_VIEWER 49 | .dagNodeEl = toImU32(hsv(hue, 0.0f, 0.6f)), 50 | .dagNodeElHi = toImU32(hsv(hue, 0.7f, 0.9f)), 51 | .dagNodeElMut = toImU32(hsv(hue, 0.0f, 0.83f)), 52 | .dagNodeRefine = toImU32(hsv(std::fmod(hue + dagNodeRefineHueShift, 1.0f), 0.7f, 0.75f)), 53 | .dagNodeExtrude = toImU32(hsv(std::fmod(hue + dagNodeExtrudeHueShift, 1.0f), 0.7f, 0.75f)), 54 | .dagNodeDelete = toImU32(hsv(std::fmod(hue + dagNodeDeleteHueShift, 1.0f), 0.7f, 0.75f)), 55 | #endif 56 | .ovAxesSat = 0.55f, 57 | .ovAxesVal = 0.9f, 58 | .ovPathSat = 0.8f, 59 | .ovPathVal = 0.75f 60 | }; 61 | } 62 | 63 | Theme Theme::makeDark(float _hueDeg, float _scale) 64 | { 65 | const float hue{ _hueDeg / 360.0f }; 66 | return Theme{ 67 | .ovScale = (1.0f + _scale * 2.0f) / 3.0f, 68 | .sbScale = _scale, 69 | .hue = hue, 70 | .dark = true, 71 | .sbOk{ toImVec4(hsv(okHue, 0.5f, 0.8f))}, 72 | .sbWarn{ toImVec4(hsv(warnHue, 0.5f, 0.81f))}, 73 | .sbErr{ toImVec4(hsv(errHue, 0.5f, 0.83f))}, 74 | .bg{ hsv(hue, 0.0f, 0.09f) }, 75 | .ovHi = toImU32(hsv(hue, 0.5f, 1.0f)), 76 | .ovMut = toImU32(hsv(hue, 0.0f, 1.0f, 0.27f)), 77 | .ovWarn = toImU32(hsv(warnHue, 0.5f, 0.55f)), 78 | .ovErr = toImU32(hsv(errHue, 0.7f, 0.7f)), 79 | .ovPolyHi = toImU32(hsv(hue, 0.75f, 0.5f, 0.1f)), 80 | .ovFaceHi = toImU32(hsv(hue, 0.75f, 1.0f, 0.2f)), 81 | .srcFace{ hsv(hue, 0.0f, 0.25f) }, 82 | .srcEdge{ hsv(hue, 0.0f, 0.0f) }, 83 | .tgtFace{ hsv(hue, 0.0f, 1.0f, 0.09f) }, 84 | .tgtEdge{ hsv(hue, 0.0f, 1.0f, 0.27f) }, 85 | #ifdef HMP_GUI_ENABLE_DAG_VIEWER 86 | .dagNodeEl = toImU32(hsv(hue, 0.0f, 0.37f)), 87 | .dagNodeElHi = toImU32(hsv(hue, 0.55f, 1.0f)), 88 | .dagNodeElMut = toImU32(hsv(hue, 0.0f, 0.22f)), 89 | .dagNodeRefine = toImU32(hsv(std::fmod(hue + dagNodeRefineHueShift, 1.0f), 0.5f, 0.75f)), 90 | .dagNodeExtrude = toImU32(hsv(std::fmod(hue + dagNodeExtrudeHueShift, 1.0f), 0.5f, 0.75f)), 91 | .dagNodeDelete = toImU32(hsv(std::fmod(hue + dagNodeDeleteHueShift, 1.0f), 0.5f, 0.75f)), 92 | #endif 93 | .ovAxesSat = 0.6f, 94 | .ovAxesVal = 0.8f, 95 | .ovPathSat = 0.65f, 96 | .ovPathVal = 0.85f 97 | }; 98 | } 99 | 100 | Theme Theme::make(bool _dark, float _hueDeg, float _scale) 101 | { 102 | return _dark ? makeDark(_hueDeg, _scale) : makeLight(_hueDeg, _scale); 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /gui/src/Utils/Themer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace HMP::Gui::Utils 7 | { 8 | 9 | void Themer::setTheme(const Theme& _theme) 10 | { 11 | m_theme = _theme; 12 | applyImGui(); 13 | onThemeChange(); 14 | } 15 | 16 | const Theme& Themer::operator*() const 17 | { 18 | return m_theme; 19 | } 20 | 21 | const Theme* Themer::operator->() const 22 | { 23 | return &m_theme; 24 | } 25 | 26 | void Themer::applyImGui() const 27 | { 28 | static constexpr float lightStyleHue{ 213.0f / 360.0f }; 29 | static constexpr float darkStyleHue{ 213.0f / 360.0f }; 30 | const float styleHue{ m_theme.dark ? darkStyleHue : lightStyleHue }; 31 | ImGuiStyle& style{ ImGui::GetStyle() }; 32 | style = {}; 33 | if (m_theme.dark) 34 | { 35 | ImGui::StyleColorsDark(); 36 | } 37 | else 38 | { 39 | ImGui::StyleColorsLight(); 40 | } 41 | style.ScaleAllSizes(m_theme.sbScale); 42 | for (ImVec4& color : style.Colors) 43 | { 44 | float h, s, v; 45 | ImGui::ColorConvertRGBtoHSV(color.x, color.y, color.z, h, s, v); 46 | h += m_theme.hue - styleHue; 47 | h = static_cast(Utils::Transform::wrapAngle(static_cast(h * 360.0f))) / 360.0f; 48 | ImGui::ColorConvertHSVtoRGB(h, s, v, color.x, color.y, color.z); 49 | } 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /gui/src/Utils/Transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace HMP::Gui::Utils 6 | { 7 | 8 | bool Transform::isNull(Real _value, Real epsilon) 9 | { 10 | return _value >= -epsilon && _value <= epsilon; 11 | } 12 | 13 | bool Transform::isNull(const Vec& _vec, Real epsilon) 14 | { 15 | return isNull(_vec.x(), epsilon) && 16 | isNull(_vec.y(), epsilon) && 17 | isNull(_vec.z(), epsilon); 18 | } 19 | 20 | Real Transform::wrapAngle(Real _angleDeg) 21 | { 22 | if (_angleDeg < 0) 23 | { 24 | return 360.0f - static_cast(std::fmod(-_angleDeg, 360.0f)); 25 | } 26 | else 27 | { 28 | return static_cast(std::fmod(_angleDeg, 360.0f)); 29 | } 30 | } 31 | 32 | Vec Transform::wrapAngles(const Vec& _anglesDeg) 33 | { 34 | return { 35 | wrapAngle(_anglesDeg.x()), 36 | wrapAngle(_anglesDeg.y()), 37 | wrapAngle(_anglesDeg.z()) 38 | }; 39 | } 40 | 41 | Vec Transform::toDeg(const Vec& _rad) 42 | { 43 | return { 44 | cinolib::to_deg(_rad.x()), 45 | cinolib::to_deg(_rad.y()), 46 | cinolib::to_deg(_rad.z()) 47 | }; 48 | } 49 | 50 | Vec Transform::toRad(const Vec& _deg) 51 | { 52 | return { 53 | cinolib::to_rad(_deg.x()), 54 | cinolib::to_rad(_deg.y()), 55 | cinolib::to_rad(_deg.z()) 56 | }; 57 | } 58 | 59 | Vec Transform::rotationMatToVec(const Mat3& _mat) 60 | { 61 | Real sy = std::sqrt(_mat(0, 0) * _mat(0, 0) + _mat(1, 0) * _mat(1, 0)); 62 | const bool singular{ isNull(sy) }; 63 | Vec rad; 64 | if (!singular) 65 | { 66 | rad.x() = std::atan2(_mat(2, 1), _mat(2, 2)); 67 | rad.y() = std::atan2(-_mat(2, 0), sy); 68 | rad.z() = std::atan2(_mat(1, 0), _mat(0, 0)); 69 | } 70 | else 71 | { 72 | rad.x() = std::atan2(-_mat(1, 2), _mat(1, 1)); 73 | rad.y() = std::atan2(-_mat(2, 0), sy); 74 | rad.z() = 0; 75 | } 76 | return toDeg(rad); 77 | } 78 | 79 | Mat3 Transform::rotationXMat(Real _angleDeg) 80 | { 81 | const Real r{ cinolib::to_rad(_angleDeg) }; 82 | const Real c{ std::cos(r) }; 83 | const Real s{ std::sin(r) }; 84 | return Mat3{ 85 | 1, 0, 0, 86 | 0, c, -s, 87 | 0, s, c 88 | }; 89 | } 90 | 91 | Mat3 Transform::rotationYMat(Real _angleDeg) 92 | { 93 | const Real r{ cinolib::to_rad(_angleDeg) }; 94 | const Real c{ std::cos(r) }; 95 | const Real s{ std::sin(r) }; 96 | return Mat3{ 97 | c, 0, s, 98 | 0, 1, 0, 99 | -s, 0, c 100 | }; 101 | } 102 | 103 | Mat3 Transform::rotationZMat(Real _angleDeg) 104 | { 105 | const Real r{ cinolib::to_rad(_angleDeg) }; 106 | const Real c{ std::cos(r) }; 107 | const Real s{ std::sin(r) }; 108 | return Mat3{ 109 | c, -s, 0, 110 | s, c, 0, 111 | 0, 0, 1 112 | }; 113 | } 114 | 115 | Mat3 Transform::rotationMat(const Vec& _axis, Real _angleDeg) 116 | { 117 | return Mat3::ROT_3D(_axis, cinolib::to_rad(_angleDeg)); 118 | } 119 | 120 | Mat3 Transform::rotationMat(const Vec& _eulerAnglesDeg) 121 | { 122 | return 123 | rotationXMat(_eulerAnglesDeg.x()) * 124 | rotationYMat(_eulerAnglesDeg.y()) * 125 | rotationZMat(_eulerAnglesDeg.z()); 126 | } 127 | 128 | Mat3 Transform::scaleMat(const Vec& _scale) 129 | { 130 | return Mat3::DIAG(_scale); 131 | } 132 | 133 | Mat4 Transform::translationMat(const Vec& _translation) 134 | { 135 | return Mat4::TRANS(_translation); 136 | } 137 | 138 | Mat4 Transform::homogeneous(const Mat3& _mat) 139 | { 140 | return Mat4{ 141 | _mat(0,0), _mat(0,1), _mat(0,2), 0, 142 | _mat(1,0), _mat(1,1), _mat(1,2), 0, 143 | _mat(2,0), _mat(2,1), _mat(2,2), 0, 144 | 0, 0, 0, 1 145 | }; 146 | } 147 | 148 | Vec2 Transform::dir(const Vec2& _from, const Vec2& _to, const Vec2& _else) 149 | { 150 | Vec2 diff{ _to - _from }; 151 | return diff.is_null() ? _else : diff.normalized(); 152 | } 153 | 154 | Real Transform::angle(const Vec2& _from, const Vec2& _to) 155 | { 156 | return wrapAngle(cinolib::to_deg(std::atan2(_from.y(), _from.x()) - std::atan2(_to.y(), _to.x()))); 157 | } 158 | 159 | Real Transform::avgScale() const 160 | { 161 | return (scale.x() + scale.y() + scale.z()) / 3; 162 | } 163 | 164 | Mat4 Transform::matrix() const 165 | { 166 | const Mat4 rotation{ homogeneous(rotationMat(this->rotation)) }; 167 | const Mat4 scale{ homogeneous(scaleMat(this->scale)) }; 168 | const Mat4 translation{ translationMat(this->translation + origin) }; 169 | const Mat4 origin{ translationMat(-this->origin) }; 170 | return translation * rotation * scale * origin; 171 | } 172 | 173 | bool Transform::isIdentity(Real epsilon) const 174 | { 175 | return 176 | isNull(translation, epsilon) && 177 | isNull(scale - Vec{ 1 }, epsilon) && 178 | isNull(wrapAngles(rotation + Vec{ 180 }) - Vec{ 180 }, epsilon); 179 | } 180 | 181 | } -------------------------------------------------------------------------------- /gui/src/Widget.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace HMP::Gui 6 | { 7 | 8 | Widget::Widget(): m_app{} 9 | {} 10 | 11 | App& Widget::app() 12 | { 13 | return *m_app; 14 | } 15 | 16 | const App& Widget::app() const 17 | { 18 | return *m_app; 19 | } 20 | 21 | void Widget::printUsage() const 22 | {} 23 | 24 | void Widget::draw(const cinolib::GLcanvas& _canvas) 25 | { 26 | drawCanvas(); 27 | } 28 | 29 | void Widget::drawCanvas() 30 | {} 31 | 32 | bool Widget::keyPressed(const cinolib::KeyBinding& _binding) 33 | { 34 | return false; 35 | } 36 | 37 | bool Widget::mouseClicked(bool _right) 38 | { 39 | return false; 40 | } 41 | 42 | bool Widget::mouseMoved(const Vec2& _position) 43 | { 44 | return false; 45 | } 46 | 47 | void Widget::cursorChanged() 48 | {} 49 | 50 | void Widget::cameraChanged() 51 | {} 52 | 53 | void Widget::actionApplied() 54 | {} 55 | 56 | void Widget::actionPrepared() 57 | {} 58 | 59 | void Widget::serialize(HMP::Utils::Serialization::Serializer& _serializer) const 60 | {} 61 | 62 | void Widget::deserialize(HMP::Utils::Serialization::Deserializer& _deserializer) 63 | {} 64 | 65 | void Widget::attached() 66 | {} 67 | 68 | std::vector Widget::additionalDrawables() const 69 | { 70 | return {}; 71 | } 72 | 73 | std::vector Widget::additionalFonts(const std::vector& _fonts) const 74 | { 75 | return {}; 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /gui/src/Widgets/Axes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace HMP::Gui::Widgets 16 | { 17 | 18 | void Axes::drawCanvas() 19 | { 20 | using Utils::Controls::toImVec2; 21 | ImDrawList& drawList{ *ImGui::GetWindowDrawList() }; 22 | Vec origin; 23 | Real radius; 24 | const cinolib::FreeCamera& camera{ app().canvas.camera }; 25 | if (camera.projection.perspective) 26 | { 27 | origin = camera.view.centerAt(3); 28 | radius = std::tan(cinolib::to_rad(camera.projection.verticalFieldOfView / 2)); 29 | } 30 | else 31 | { 32 | origin = camera.view.centerAt(2); 33 | radius = camera.projection.verticalFieldOfView / 2 * 0.75; 34 | } 35 | const Vec right(origin + cinolib::GLcanvas::world_right() * radius); 36 | const Vec up(origin + cinolib::GLcanvas::world_up() * radius); 37 | const Vec forward(origin - cinolib::GLcanvas::world_forward() * radius); 38 | const Real maxSize{ static_cast(std::min(app().canvas.canvas_width(), app().canvas.height())) }; 39 | const Real size{ std::min((maxSize * 0.1 + 100 * static_cast(themer->ovScale)) / 2, maxSize / 3) }; 40 | const auto project{ [&](const Vec& _point) -> Vec { 41 | Vec proj(camera.projectionViewMatrix() * _point); 42 | proj.x() *= camera.projection.aspectRatio; 43 | const ImVec2 windowOrigin{ ImGui::GetWindowPos() }; 44 | const ImVec2 windowSize{ ImGui::GetWindowSize() }; 45 | proj.x() = proj.x() * size + windowOrigin.x + windowSize.x - size; 46 | proj.y() = -proj.y() * size + windowOrigin.y + windowSize.y - size; 47 | return proj; 48 | } }; 49 | origin = project(origin); 50 | std::array, 3> tips{ 51 | std::pair{project(right), Utils::Drawing::toImU32(cinolib::Color::hsv2rgb(0.0f / 3.0f, themer->ovAxesSat, themer->ovAxesVal)) }, 52 | std::pair{project(up), Utils::Drawing::toImU32(cinolib::Color::hsv2rgb(1.0f / 3.0f, themer->ovAxesSat, themer->ovAxesVal)) }, 53 | std::pair{project(forward), Utils::Drawing::toImU32(cinolib::Color::hsv2rgb(2.0f / 3.0f, themer->ovAxesSat, themer->ovAxesVal)) } 54 | }; 55 | std::sort(tips.begin(), tips.end(), [](const std::pair& _a, const std::pair& _b) { return _a.first.z() > _b.first.z(); }); 56 | for (const auto& [tip, color] : tips) 57 | { 58 | Utils::Drawing::line(drawList, { toImVec2(origin.rem_coord()), toImVec2(tip.rem_coord()) }, color, 3.0f); 59 | Utils::Drawing::circleFilled(drawList, toImVec2(tip.rem_coord()), 5.0f, color); 60 | } 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /gui/src/Widgets/Commander.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace HMP::Gui::Widgets 13 | { 14 | 15 | Commander::Commander(): SidebarWidget{ "Commander" } 16 | {} 17 | 18 | bool Commander::keyPressed(const cinolib::KeyBinding& _key) 19 | { 20 | if (_key == c_kbUndo) 21 | { 22 | app().undo(); 23 | } 24 | else if (_key == c_kbRedo) 25 | { 26 | app().redo(); 27 | } 28 | else 29 | { 30 | return false; 31 | } 32 | return true; 33 | } 34 | 35 | void Commander::printUsage() const 36 | { 37 | cinolib::print_binding(c_kbUndo.name(), "undo"); 38 | cinolib::print_binding(c_kbRedo.name(), "redo"); 39 | } 40 | 41 | void Commander::drawSidebar() 42 | { 43 | constexpr auto actionsControl{ [](HMP::Commander::Stack& _stack, const std::string& _name) { 44 | int limit{ static_cast(_stack.limit()) }; 45 | ImGui::TableNextRow(); 46 | ImGui::TableNextColumn(); 47 | ImGui::SliderInt((_name + " limit").c_str(), &limit, 0, 100, "Max %d actions", ImGuiSliderFlags_AlwaysClamp); 48 | _stack.limit(static_cast(limit)); 49 | ImGui::TableNextColumn(); 50 | if (Utils::Controls::disabledButton((std::string{ "Clear " } + std::to_string(_stack.size()) + " actions").c_str(), !_stack.empty())) 51 | { 52 | _stack.clear(); 53 | } 54 | } }; 55 | ImGui::BeginTable("stacks", 2, ImGuiTableFlags_RowBg); 56 | ImGui::TableSetupColumn("size", ImGuiTableColumnFlags_WidthStretch); 57 | ImGui::TableSetupColumn("clear", ImGuiTableColumnFlags_WidthFixed); 58 | actionsControl(app().commander.applied(), "Undo"); 59 | actionsControl(app().commander.unapplied(), "Redo"); 60 | ImGui::EndTable(); 61 | ImGui::Spacing(); 62 | 63 | ImGui::Text("History"); 64 | ImGui::BeginChild("history", { ImGui::GetContentRegionAvail().x, 130 * themer->sbScale }, true); 65 | if (app().vertEditWidget.pendingAction()) 66 | { 67 | ImGui::TextColored(themer->sbWarn, "Pending vertex edit action on %d vertices", static_cast(app().vertEditWidget.vids().size())); 68 | } 69 | 70 | for (const auto& action : app().commander.unapplied().reverse()) 71 | { 72 | ImGui::TextColored(themer->sbErr, "%s", Utils::HrDescriptions::describe(action, app().dagNamer).c_str()); 73 | } 74 | 75 | for (const HMP::Commander::Action& action : app().commander.applied()) 76 | { 77 | ImGui::TextColored(themer->sbOk, "%s", Utils::HrDescriptions::describe(action, app().dagNamer).c_str()); 78 | } 79 | ImGui::EndChild(); 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /gui/src/Widgets/Pad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Gui::Widgets 9 | { 10 | 11 | Pad::Pad(): SidebarWidget{ "Pad" } {} 12 | 13 | void Pad::requestPad() 14 | { 15 | app().applyAction(*new HMP::Actions::Pad{ m_length, m_smoothIterations, m_smoothSurfVertWeight, m_cornerShrinkFactor }); 16 | } 17 | 18 | void Pad::drawSidebar() 19 | { 20 | Utils::Controls::sliderI("Smooth iterations", m_smoothIterations, 0, 20); 21 | Utils::Controls::sliderPercentage("Smooth surface weight", m_smoothSurfVertWeight, 0.5, 2.0); 22 | Utils::Controls::sliderPercentage("Corner shrink factor", m_cornerShrinkFactor); 23 | const Real meshSize{ app().mesh.bbox().diag() }; 24 | Utils::Controls::sliderReal("Length", m_length, meshSize / 500.0, meshSize / 5.0); 25 | if (ImGui::Button("Pad")) 26 | { 27 | requestPad(); 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /gui/src/Widgets/Smooth.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HMP::Gui::Widgets 9 | { 10 | 11 | Smooth::Smooth(): SidebarWidget{ "Smooth" } {} 12 | 13 | void Smooth::requestSmooth() 14 | { 15 | app().applyAction(*new HMP::Actions::Smooth{ m_surfaceIterations, m_internalIterations, m_surfVertWeight }); 16 | } 17 | 18 | void Smooth::drawSidebar() 19 | { 20 | Utils::Controls::sliderI("Surface iterations", m_surfaceIterations, 0, 20); 21 | Utils::Controls::sliderI("Internal iterations", m_internalIterations, 0, 20); 22 | Utils::Controls::sliderPercentage("Smooth surface weight", m_surfVertWeight, 0.5, 2.0); 23 | if (ImGui::Button("Smooth")) 24 | { 25 | requestSmooth(); 26 | } 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /gui/src/main.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include 3 | #include 4 | 5 | int main(int _argc, char* _argv[]) 6 | { 7 | std::optional file{ std::nullopt }; 8 | if (_argc == 2) 9 | { 10 | file = _argv[1]; 11 | std::cout << "loading file '" << *file << "'" << std::endl; 12 | } 13 | else if (_argc > 2) 14 | { 15 | std::cerr << "expected 0 or 1 argument, got " << _argc - 1 << std::endl; 16 | return 1; 17 | } 18 | return HMP::Gui::App::run(file); 19 | } -------------------------------------------------------------------------------- /gui/src/themer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace HMP::Gui 4 | { 5 | 6 | Utils::Themer themer{}; 7 | 8 | } -------------------------------------------------------------------------------- /models.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg3hci/HexBox/5ac05edd190ce8d5ab1c2a52346fde2e78d94cc4/models.zip -------------------------------------------------------------------------------- /models/Fig15/SGP.mesh: -------------------------------------------------------------------------------- 1 | MeshVersionFormatted 1 2 | Dimension 3 3 | Vertices 4 | 168 5 | 0.5 1 -4.5 0 6 | 0.5 1 -5 0 7 | 1 1 -1 0 8 | 0.5 2 -8 0 9 | 0.5 2 -9 0 10 | 1 2.5 -9 0 11 | 0.5 2.5 -9 0 12 | 0.5 3 -9 0 13 | 0.5 1.5 -3 0 14 | 0.5 1.5 -3.5 0 15 | 1 1 -3 0 16 | 0.5 2 -3 0 17 | 0.5 2 -3.5 0 18 | 1 1.5 -3 0 19 | 1 1.5 -3.5 0 20 | 1 1 -5 0 21 | 1 2 -3.5 0 22 | 0.5 1.5 -4 0 23 | 0.5 2 -4 0 24 | 1 1 -7 0 25 | 1 1.5 -4 0 26 | 0.5 2.5 -3 0 27 | 0.5 2.5 -3.5 0 28 | 1 1 -9 0 29 | 0.5 3 -3 0 30 | 0.5 3 -3.5 0 31 | 1 3 1 0 32 | 1 3 -1 0 33 | 1 2.5 -3 0 34 | 1 3 -3 0 35 | 1 3 -5 0 36 | 1 2.5 -3.5 0 37 | 1 3 -7 0 38 | 1 3 -9 0 39 | 1 3 -3.5 0 40 | 0.5 2.5 -4 0 41 | 0.5 3 -4 0 42 | 1 2.5 -4 0 43 | 1 2.5 -7 0 44 | 0.5 2.5 -7 0 45 | 1 2.5 -7.5 0 46 | 0.5 2.5 -7.5 0 47 | 0.5 3 -7 0 48 | 1 3 -7.5 0 49 | 0.5 3 -7.5 0 50 | 1 2.5 -8 0 51 | 0.5 2.5 -8 0 52 | 0.5 3 -8 0 53 | 1 2.5 -8.5 0 54 | 0.5 2.5 -8.5 0 55 | 1 3 -8.5 0 56 | 0.5 3 -8.5 0 57 | 1 1.5 -8.5 0 58 | 0.5 1.5 -8.5 0 59 | 1 2 -8.5 0 60 | 0.5 2 -8.5 0 61 | 1 1.5 -9 0 62 | 0.5 1.5 -9 0 63 | 0.5 1.5 -1 0 64 | 0.5 0.5 -1 0 65 | 0.5 0.5 -0.5 0 66 | 0.5 1.5 -0.5 0 67 | 1 0.5 -1 0 68 | 1 0.5 -0.5 0 69 | 0.5 2 -1 0 70 | 0.5 1 -1 0 71 | 0.5 1 -0.5 0 72 | 0.5 2 -0.5 0 73 | 1 1 -0.5 0 74 | 0.5 1.5 0 0 75 | 1 1 -4 0 76 | 0.5 2 0 0 77 | 1 1.5 -1 0 78 | 1 1.5 -0.5 0 79 | 1 2 -0.5 0 80 | 1 1.5 0 0 81 | 0.5 2.5 -1 0 82 | 0.5 2.5 -0.5 0 83 | 0.5 3 -1 0 84 | 0.5 3 -0.5 0 85 | 0.5 2.5 0 0 86 | 0.5 3 0 0 87 | 1 2.5 -1 0 88 | 1 2.5 -0.5 0 89 | 1 3 -0.5 0 90 | 1 2.5 0 0 91 | 0.5 1.5 0.5 0 92 | 0.5 2 0.5 0 93 | 0.5 1.5 1 0 94 | 1 1 -8 0 95 | 0.5 2 1 0 96 | 1 1.5 0.5 0 97 | 1 2 0.5 0 98 | 1 1.5 1 0 99 | 0.5 2.5 0.5 0 100 | 0.5 3 0.5 0 101 | 0.5 2.5 1 0 102 | 1 0.5 -7 0 103 | 0.5 0.5 -7 0 104 | 1 0.5 -7.5 0 105 | 0.5 0.5 -7.5 0 106 | 1 0.5 -8 0 107 | 0.5 0.5 -8 0 108 | 1 2 -1 0 109 | 1 2 0 0 110 | 1 3 0 0 111 | 1 2 1 0 112 | 0.5 3 1 0 113 | 1 2.5 0.5 0 114 | 1 3 0.5 0 115 | 0.5 1 -7 0 116 | 1 1 -7.5 0 117 | 0.5 1 -7.5 0 118 | 0.5 1 -8 0 119 | 1 2 -3 0 120 | 1 2 -4 0 121 | 1 3 -4 0 122 | 1 2.5 1 0 123 | 1 0.5 -8.5 0 124 | 0.5 0.5 -8.5 0 125 | 1 2 -5 0 126 | 1 2 -7 0 127 | 1 0.5 -9 0 128 | 1 2 -8 0 129 | 0.5 0.5 -9 0 130 | 0.5 1.5 -4.5 0 131 | 1 3 -8 0 132 | 0.5 2 -4.5 0 133 | 1 2 -9 0 134 | 1 1 -8.5 0 135 | 0.5 1 -8.5 0 136 | 0.5 1 -9 0 137 | 1 1.5 -4.5 0 138 | 1 2 -4.5 0 139 | 0.5 1.5 -5 0 140 | 0.5 2 -5 0 141 | 1 1.5 -5 0 142 | 0.5 2.5 -4.5 0 143 | 0.5 3 -4.5 0 144 | 1 2.5 -4.5 0 145 | 1 3 -4.5 0 146 | 0.5 2.5 -5 0 147 | 0.5 3 -5 0 148 | 1 2.5 -5 0 149 | 1 1.5 -7 0 150 | 0.5 1.5 -7 0 151 | 1 1.5 -7.5 0 152 | 1 0.5 -3 0 153 | 0.5 0.5 -3 0 154 | 1 0.5 -3.5 0 155 | 0.5 0.5 -3.5 0 156 | 1 0.5 -4 0 157 | 0.5 0.5 -4 0 158 | 0.5 1.5 -7.5 0 159 | 0.5 2 -7 0 160 | 1 2 -7.5 0 161 | 0.5 1 -3 0 162 | 1 1 -3.5 0 163 | 0.5 1 -3.5 0 164 | 0.5 1 -4 0 165 | 0.5 2 -7.5 0 166 | 1 0.5 -4.5 0 167 | 0.5 0.5 -4.5 0 168 | 1 0.5 -5 0 169 | 0.5 0.5 -5 0 170 | 1 1.5 -8 0 171 | 0.5 1.5 -8 0 172 | 1 1 -4.5 0 173 | Hexahedra 174 | 40 175 | 77 78 84 83 79 80 85 28 0 176 | 36 38 140 138 37 117 141 139 0 177 | 78 81 86 84 80 82 106 85 0 178 | 55 129 5 56 49 6 7 50 0 179 | 39 41 42 40 33 44 45 43 0 180 | 152 153 160 71 162 163 1 168 0 181 | 162 163 1 168 164 165 2 16 0 182 | 23 32 38 36 26 35 117 37 0 183 | 128 134 121 136 138 140 144 142 0 184 | 138 140 144 142 139 141 31 143 0 185 | 70 87 92 76 72 88 93 105 0 186 | 111 20 112 113 146 145 147 154 0 187 | 87 89 94 92 88 91 107 93 0 188 | 145 147 154 146 122 156 161 155 0 189 | 49 6 7 50 51 34 8 52 0 190 | 147 166 167 154 156 124 4 161 0 191 | 157 11 158 159 9 14 15 10 0 192 | 9 14 15 10 12 115 17 13 0 193 | 81 95 109 86 82 96 110 106 0 194 | 88 91 107 93 95 97 118 109 0 195 | 95 97 118 109 96 108 27 110 0 196 | 41 46 47 42 44 127 48 45 0 197 | 1 168 16 2 126 133 137 135 0 198 | 126 133 137 135 128 134 121 136 0 199 | 3 66 67 69 73 59 62 74 0 200 | 59 62 74 73 65 68 75 104 0 201 | 98 99 111 20 100 101 113 112 0 202 | 100 101 113 112 102 103 114 90 0 203 | 10 15 21 18 13 17 116 19 0 204 | 62 70 76 74 68 72 105 75 0 205 | 60 63 3 66 61 64 69 67 0 206 | 166 53 54 167 124 55 56 4 0 207 | 46 49 50 47 127 51 52 48 0 208 | 53 57 58 54 55 129 5 56 0 209 | 22 29 32 23 25 30 35 26 0 210 | 102 103 114 90 119 120 131 130 0 211 | 119 120 131 130 123 125 132 24 0 212 | 148 149 157 11 150 151 159 158 0 213 | 150 151 159 158 152 153 160 71 0 214 | 65 68 75 104 77 78 84 83 0 215 | End 216 | 217 | -------------------------------------------------------------------------------- /models/Fig2/hole.mesh: -------------------------------------------------------------------------------- 1 | MeshVersionFormatted 1 2 | Dimension 3 3 | Vertices 4 | 36 5 | -1 -1 -1 0 6 | 1 -1 -1 0 7 | 5.4076237921249266 -2.4472135954999579 -1 0 8 | 0 1 -1 0 9 | -1 -1 1 0 10 | 1 -1 1 0 11 | 5.4076237921249266 -2.4472135954999579 1 0 12 | 0 1 1 0 13 | 2 1 -1 0 14 | 2 1 1 0 15 | 3 -1 1 0 16 | 3 -1 -1 0 17 | 1 2.9871639999999999 -1 0 18 | 1 2.9871639999999999 1 0 19 | -1.8868522050868926 1.9495201226908763 -1 0 20 | -1.8868522050868926 1.9495201226908763 1 0 21 | -0.88685220508689255 3.9366841226908762 1 0 22 | -0.88685220508689255 3.9366841226908762 -1 0 23 | -2.8527797900615615 0.030018705280247693 1 0 24 | -2.8527797900615615 0.030018705280247693 -1 0 25 | 1 -3 1 0 26 | 1 -3 -1 0 27 | 3 -3 -1 0 28 | 3 -3 1 0 29 | -1 -3 -1 0 30 | -1 -3 1 0 31 | 4.8944271909999157 -0.052786404500042017 1 0 32 | 4.8944271909999157 -0.052786404500042017 -1 0 33 | 3.8944271909999157 1.9472135954999579 -1 0 34 | 3.8944271909999157 1.9472135954999579 1 0 35 | 2.9302295014184354 3.8627692523453536 -1 0 36 | 2.9302295014184354 3.8627692523453536 1 0 37 | 1.0583724110180355 5.7559727764147581 1 0 38 | 1.0583724110180355 5.7559727764147581 -1 0 39 | -3.4268415804368941 -2.3851944629502086 -1 0 40 | -3.4268415804368941 -2.3851944629502086 1 0 41 | Hexahedra 42 | 9 43 | 13 14 32 31 18 17 33 34 0 44 | 5 1 25 26 19 20 35 36 0 45 | 11 12 28 27 24 23 3 7 0 46 | 4 8 14 13 15 16 17 18 0 47 | 4 8 16 15 1 5 19 20 0 48 | 6 2 12 11 21 22 23 24 0 49 | 6 2 22 21 5 1 25 26 0 50 | 9 10 11 12 29 30 27 28 0 51 | 9 13 14 10 29 31 32 30 0 52 | End 53 | 54 | -------------------------------------------------------------------------------- /models/Fig2/val11.mesh: -------------------------------------------------------------------------------- 1 | MeshVersionFormatted 1 2 | Dimension 3 3 | Vertices 4 | 46 5 | -1 -0.97745596315184069 0.28204942079377082 0 6 | 1 -0.97745596315184069 0.28204942079377082 0 7 | 1 -0.68716972859841507 -0.3821500427582275 0 8 | -1 -0.68716972859841507 -0.3821500427582275 0 9 | -1 -1.0688569524236515 1.0011272222270402 0 10 | 1 -1.0688569524236515 1.0011272222270402 0 11 | 1 1.3356708288192745 0.99999999999999967 0 12 | -1 1.3356708288192745 0.99999999999999967 0 13 | 1 -0.95396793184565953 1.7168279545898057 0 14 | 1 -0.64209652659377903 2.3711698009821842 0 15 | -1 -0.64209652659377903 2.3711698009821842 0 16 | -1 -0.95396793184565953 1.7168279545898057 0 17 | 1 -0.22151551308818163 -0.93766167803828326 0 18 | -1 -0.22151551308818163 -0.93766167803828326 0 19 | -1 0.38178214819047018 -1.3394812361109056 0 20 | 1 0.38178214819047018 -1.3394812361109056 0 21 | 1 1.0738476666700894 -1.5550556860939806 0 22 | -1 1.0738476666700894 -1.5550556860939806 0 23 | -1 1.7986140099155743 -1.566920468120498 0 24 | 1 1.7986140099155743 -1.566920468120498 0 25 | -1 3.1134917513347378 -0.99225738963278121 0 26 | 1 3.1134917513347378 -0.99225738963278121 0 27 | 1 2.4973649191485894 -1.3741143681132444 0 28 | -1 2.4973649191485894 -1.3741143681132444 0 29 | -1 3.9089509800295437 0.2020565323076795 0 30 | 1 3.9089509800295437 0.2020565323076795 0 31 | 1 3.5970795747776636 -0.45228531408469974 0 32 | -1 3.5970795747776636 -0.45228531408469974 0 33 | 1 -0.15850870315085297 2.9111418765302659 0 34 | 1 0.45761812903529675 3.2929988550107296 0 35 | -1 0.45761812903529675 3.2929988550107296 0 36 | -1 -0.15850870315085297 2.9111418765302659 0 37 | 1 1.1563690382683105 3.4858049550179824 0 38 | 1 1.8811353815137954 3.473940172991465 0 39 | -1 1.8811353815137954 3.473940172991465 0 40 | -1 1.1563690382683105 3.4858049550179824 0 41 | -1 3.1764985612720671 2.8565461649357666 0 42 | -1 2.5732008999934148 3.25836572300839 0 43 | 1 2.5732008999934148 3.25836572300839 0 44 | 1 3.1764985612720671 2.8565461649357666 0 45 | -1 3.9324390113357248 1.6368350661037134 0 46 | -1 3.6421527767822992 2.3010345296557126 0 47 | 1 3.6421527767822992 2.3010345296557126 0 48 | 1 3.9324390113357248 1.6368350661037134 0 49 | -1 4.0238400006075361 0.91775726467044583 0 50 | 1 4.0238400006075361 0.91775726467044583 0 51 | Hexahedra 52 | 11 53 | 1 2 3 4 5 6 7 8 0 54 | 5 6 7 8 12 9 10 11 0 55 | 3 4 8 7 13 14 15 16 0 56 | 8 7 16 15 19 20 17 18 0 57 | 8 7 20 19 21 22 23 24 0 58 | 8 7 22 21 25 26 27 28 0 59 | 7 8 11 10 30 31 32 29 0 60 | 7 8 31 30 34 35 36 33 0 61 | 7 8 35 34 40 37 38 39 0 62 | 7 8 37 40 44 41 42 43 0 63 | 7 8 41 44 26 25 45 46 0 64 | End 65 | 66 | -------------------------------------------------------------------------------- /models/Fig2/val3.mesh: -------------------------------------------------------------------------------- 1 | MeshVersionFormatted 1 2 | Dimension 3 3 | Vertices 4 | 14 5 | -1 -1 -1 0 6 | 1 -1 -1 0 7 | 1 0.29972300000000002 -1 0 8 | 0 1 -1 0 9 | -1 -1 1 0 10 | 1 -1 1 0 11 | 1 0.29972300000000002 1 0 12 | 0 1 1 0 13 | 2 1 -1 0 14 | 2 1 1 0 15 | 3 -1 1 0 16 | 3 -1 -1 0 17 | 1 2.9871639999999999 -1 0 18 | 1 2.9871639999999999 1 0 19 | Hexahedra 20 | 3 21 | 1 2 3 4 5 6 7 8 0 22 | 2 3 7 6 12 9 10 11 0 23 | 3 4 8 7 9 13 14 10 0 24 | End 25 | 26 | -------------------------------------------------------------------------------- /models/Fig2/val5.mesh: -------------------------------------------------------------------------------- 1 | MeshVersionFormatted 1 2 | Dimension 3 3 | Vertices 4 | 22 5 | -1 -1 -1 0 6 | 1 -1 -1 0 7 | 1 1.5141230000000001 -1 0 8 | -1.5 1 -1 0 9 | -1 -1 1 0 10 | 1 -1 1 0 11 | 1 1.5141230000000001 1 0 12 | -1.5 1 1 0 13 | 3 -1 1 0 14 | 3 -1 -1 0 15 | 3.5 1 -1 0 16 | 3.5 1 1 0 17 | -0.42082000000000003 3.8944269999999999 -1 0 18 | -1.947214 2.8944269999999999 -1 0 19 | -1.947214 2.8944269999999999 1 0 20 | -0.42082000000000003 3.8944269999999999 1 0 21 | 2.42082 3.8944269999999999 -1 0 22 | 2.42082 3.8944269999999999 1 0 23 | 3.9472139999999998 2.8944269999999999 1 0 24 | 3.9472139999999998 2.8944269999999999 -1 0 25 | 1 4.8152480000000004 1 0 26 | 1 4.8152480000000004 -1 0 27 | Hexahedra 28 | 5 29 | 1 2 3 4 5 6 7 8 0 30 | 2 3 7 6 10 11 12 9 0 31 | 3 4 8 7 13 14 15 16 0 32 | 3 7 12 11 17 18 19 20 0 33 | 3 7 18 17 13 16 21 22 0 34 | End 35 | 36 | -------------------------------------------------------------------------------- /schemes/adapter2FacesSubdivide3x3.rse: -------------------------------------------------------------------------------- 1 | 3 2 | 17 3 | 0 4 | 0 5 | 0 6 | 1 7 | 0 8 | 0 9 | 0 10 | 1 11 | 0 12 | 1 13 | 1 14 | 0 15 | 0 16 | 0 17 | 1 18 | 1 19 | 0 20 | 1 21 | 0 22 | 1 23 | 1 24 | 1 25 | 1 26 | 1 27 | 1 28 | 0 29 | 0 30 | 2 31 | 0 32 | 0 33 | 1 34 | 1 35 | 0 36 | 2 37 | 1 38 | 0 39 | 1 40 | 0 41 | 1 42 | 2 43 | 0 44 | 1 45 | 1 46 | 1 47 | 1 48 | 2 49 | 1 50 | 1 51 | 2 52 | 0 53 | 0 54 | 3 55 | 0 56 | 0 57 | 2 58 | 1 59 | 0 60 | 3 61 | 1 62 | 0 63 | 2 64 | 0 65 | 1 66 | 3 67 | 0 68 | 1 69 | 2 70 | 1 71 | 1 72 | 3 73 | 1 74 | 1 75 | 0 76 | 0 77 | 1 78 | 1 79 | 0 80 | 1 81 | 0 82 | 1 83 | 1 84 | 1 85 | 1 86 | 1 87 | 0 88 | 0 89 | 2 90 | 1 91 | 0 92 | 2 93 | 0 94 | 2 95 | 2 96 | 1 97 | 2 98 | 2 99 | 1 100 | 0 101 | 1 102 | 2 103 | 0 104 | 1 105 | 1 106 | 1 107 | 1 108 | 2 109 | 1 110 | 1 111 | 1 112 | 0 113 | 2 114 | 2 115 | 0 116 | 2 117 | 1 118 | 2 119 | 2 120 | 2 121 | 2 122 | 2 123 | 2 124 | 0 125 | 1 126 | 3 127 | 0 128 | 1 129 | 2 130 | 1 131 | 1 132 | 3 133 | 1 134 | 1 135 | 2 136 | 0 137 | 2 138 | 3 139 | 0 140 | 2 141 | 2 142 | 2 143 | 2 144 | 3 145 | 2 146 | 2 147 | 0 148 | 1 149 | 0 150 | 1 151 | 1 152 | 0 153 | 0 154 | 2 155 | 0 156 | 1 157 | 2 158 | 0 159 | 0 160 | 1 161 | 1 162 | 1 163 | 1 164 | 1 165 | 0 166 | 2 167 | 2 168 | 1 169 | 2 170 | 2 171 | 1 172 | 1 173 | 0 174 | 2 175 | 1 176 | 0 177 | 1 178 | 2 179 | 0 180 | 2 181 | 2 182 | 0 183 | 1 184 | 1 185 | 1 186 | 2 187 | 1 188 | 1 189 | 1 190 | 2 191 | 2 192 | 2 193 | 2 194 | 2 195 | 2 196 | 1 197 | 0 198 | 3 199 | 1 200 | 0 201 | 2 202 | 2 203 | 0 204 | 3 205 | 2 206 | 0 207 | 2 208 | 1 209 | 1 210 | 3 211 | 1 212 | 1 213 | 2 214 | 2 215 | 2 216 | 3 217 | 2 218 | 2 219 | 0 220 | 2 221 | 0 222 | 1 223 | 2 224 | 0 225 | 0 226 | 3 227 | 0 228 | 1 229 | 3 230 | 0 231 | 0 232 | 2 233 | 2 234 | 1 235 | 2 236 | 2 237 | 0 238 | 3 239 | 3 240 | 1 241 | 3 242 | 2 243 | 1 244 | 2 245 | 0 246 | 2 247 | 2 248 | 0 249 | 1 250 | 3 251 | 0 252 | 2 253 | 3 254 | 0 255 | 1 256 | 2 257 | 2 258 | 2 259 | 2 260 | 2 261 | 1 262 | 3 263 | 2 264 | 2 265 | 3 266 | 2 267 | 2 268 | 2 269 | 0 270 | 3 271 | 2 272 | 0 273 | 2 274 | 3 275 | 0 276 | 3 277 | 3 278 | 0 279 | 2 280 | 2 281 | 2 282 | 3 283 | 2 284 | 2 285 | 2 286 | 3 287 | 2 288 | 3 289 | 3 290 | 3 291 | 0 292 | 0 293 | 2 294 | 1 295 | 0 296 | 2 297 | 0 298 | 2 299 | 2 300 | 1 301 | 2 302 | 2 303 | 0 304 | 0 305 | 3 306 | 1 307 | 0 308 | 3 309 | 0 310 | 3 311 | 3 312 | 1 313 | 2 314 | 3 315 | 1 316 | 0 317 | 2 318 | 2 319 | 0 320 | 2 321 | 1 322 | 2 323 | 2 324 | 2 325 | 2 326 | 2 327 | 1 328 | 0 329 | 3 330 | 2 331 | 0 332 | 3 333 | 1 334 | 2 335 | 3 336 | 2 337 | 2 338 | 3 339 | 2 340 | 0 341 | 2 342 | 3 343 | 0 344 | 2 345 | 2 346 | 2 347 | 2 348 | 3 349 | 2 350 | 2 351 | 2 352 | 0 353 | 3 354 | 3 355 | 0 356 | 3 357 | 2 358 | 2 359 | 3 360 | 3 361 | 3 362 | 3 363 | 1 364 | 2 365 | 2 366 | 2 367 | 2 368 | 2 369 | 0 370 | 2 371 | 2 372 | 3 373 | 2 374 | 2 375 | 1 376 | 2 377 | 3 378 | 2 379 | 2 380 | 3 381 | 0 382 | 3 383 | 3 384 | 3 385 | 3 386 | 3 387 | 1 388 | 2 389 | 2 390 | 2 391 | 2 392 | 2 393 | 1 394 | 3 395 | 2 396 | 2 397 | 3 398 | 2 399 | 0 400 | 2 401 | 2 402 | 3 403 | 2 404 | 2 405 | 0 406 | 3 407 | 3 408 | 3 409 | 3 410 | 3 411 | -------------------------------------------------------------------------------- /schemes/adapterEdgeSubdivide3x3.rse: -------------------------------------------------------------------------------- 1 | 3 2 | 5 3 | 1 4 | 2 5 | 0 6 | 2 7 | 2 8 | 0 9 | 0 10 | 3 11 | 0 12 | 3 13 | 3 14 | 0 15 | 1 16 | 2 17 | 2 18 | 2 19 | 2 20 | 2 21 | 0 22 | 3 23 | 3 24 | 3 25 | 3 26 | 3 27 | 0 28 | 0 29 | 0 30 | 1 31 | 0 32 | 0 33 | 0 34 | 3 35 | 0 36 | 1 37 | 2 38 | 0 39 | 0 40 | 0 41 | 3 42 | 1 43 | 0 44 | 2 45 | 0 46 | 3 47 | 3 48 | 1 49 | 2 50 | 2 51 | 2 52 | 0 53 | 0 54 | 3 55 | 0 56 | 0 57 | 2 58 | 2 59 | 0 60 | 3 61 | 3 62 | 0 63 | 2 64 | 0 65 | 2 66 | 3 67 | 0 68 | 3 69 | 2 70 | 2 71 | 2 72 | 3 73 | 3 74 | 3 75 | 1 76 | 0 77 | 2 78 | 2 79 | 0 80 | 2 81 | 1 82 | 2 83 | 2 84 | 2 85 | 2 86 | 2 87 | 0 88 | 0 89 | 3 90 | 3 91 | 0 92 | 3 93 | 0 94 | 3 95 | 3 96 | 3 97 | 3 98 | 3 99 | 1 100 | 0 101 | 0 102 | 2 103 | 0 104 | 0 105 | 1 106 | 2 107 | 0 108 | 2 109 | 2 110 | 0 111 | 1 112 | 0 113 | 2 114 | 2 115 | 0 116 | 2 117 | 1 118 | 2 119 | 2 120 | 2 121 | 2 122 | 2 123 | -------------------------------------------------------------------------------- /schemes/adapterFaceSubdivide3x3.rse: -------------------------------------------------------------------------------- 1 | 3 2 | 13 3 | 0 4 | 0 5 | 0 6 | 1 7 | 0 8 | 0 9 | 0 10 | 1 11 | 0 12 | 1 13 | 1 14 | 0 15 | 0 16 | 0 17 | 3 18 | 1 19 | 0 20 | 2 21 | 0 22 | 1 23 | 2 24 | 1 25 | 1 26 | 1 27 | 0 28 | 2 29 | 0 30 | 1 31 | 2 32 | 0 33 | 0 34 | 3 35 | 0 36 | 1 37 | 3 38 | 0 39 | 0 40 | 2 41 | 2 42 | 1 43 | 2 44 | 1 45 | 0 46 | 3 47 | 3 48 | 1 49 | 3 50 | 2 51 | 0 52 | 1 53 | 0 54 | 1 55 | 1 56 | 0 57 | 0 58 | 2 59 | 0 60 | 1 61 | 2 62 | 0 63 | 0 64 | 1 65 | 2 66 | 1 67 | 1 68 | 1 69 | 0 70 | 2 71 | 2 72 | 1 73 | 2 74 | 1 75 | 0 76 | 1 77 | 2 78 | 1 79 | 1 80 | 1 81 | 0 82 | 2 83 | 2 84 | 1 85 | 2 86 | 1 87 | 0 88 | 0 89 | 3 90 | 1 91 | 0 92 | 2 93 | 0 94 | 3 95 | 3 96 | 1 97 | 3 98 | 2 99 | 2 100 | 0 101 | 0 102 | 3 103 | 0 104 | 0 105 | 2 106 | 1 107 | 0 108 | 3 109 | 1 110 | 0 111 | 2 112 | 0 113 | 2 114 | 3 115 | 0 116 | 3 117 | 2 118 | 1 119 | 1 120 | 3 121 | 1 122 | 2 123 | 2 124 | 2 125 | 0 126 | 3 127 | 2 128 | 0 129 | 2 130 | 3 131 | 0 132 | 3 133 | 3 134 | 0 135 | 2 136 | 2 137 | 1 138 | 3 139 | 2 140 | 2 141 | 2 142 | 3 143 | 2 144 | 3 145 | 3 146 | 3 147 | 2 148 | 1 149 | 0 150 | 3 151 | 1 152 | 0 153 | 2 154 | 2 155 | 0 156 | 3 157 | 2 158 | 0 159 | 2 160 | 1 161 | 1 162 | 3 163 | 1 164 | 2 165 | 2 166 | 2 167 | 1 168 | 3 169 | 2 170 | 2 171 | 2 172 | 1 173 | 1 174 | 3 175 | 1 176 | 2 177 | 2 178 | 2 179 | 1 180 | 3 181 | 2 182 | 2 183 | 2 184 | 0 185 | 2 186 | 3 187 | 0 188 | 3 189 | 2 190 | 3 191 | 2 192 | 3 193 | 3 194 | 3 195 | 1 196 | 1 197 | 1 198 | 2 199 | 1 200 | 1 201 | 1 202 | 2 203 | 1 204 | 2 205 | 2 206 | 1 207 | 1 208 | 0 209 | 2 210 | 2 211 | 0 212 | 2 213 | 1 214 | 3 215 | 2 216 | 2 217 | 3 218 | 2 219 | 1 220 | 0 221 | 0 222 | 2 223 | 0 224 | 0 225 | 1 226 | 1 227 | 0 228 | 2 229 | 1 230 | 0 231 | 1 232 | 0 233 | 2 234 | 2 235 | 0 236 | 2 237 | 1 238 | 1 239 | 1 240 | 2 241 | 1 242 | 1 243 | 1 244 | 1 245 | 0 246 | 2 247 | 1 248 | 0 249 | 1 250 | 2 251 | 0 252 | 2 253 | 2 254 | 0 255 | 1 256 | 1 257 | 1 258 | 2 259 | 1 260 | 1 261 | 1 262 | 2 263 | 1 264 | 2 265 | 2 266 | 1 267 | 1 268 | 2 269 | 0 270 | 2 271 | 2 272 | 0 273 | 1 274 | 3 275 | 0 276 | 2 277 | 3 278 | 0 279 | 1 280 | 2 281 | 1 282 | 2 283 | 2 284 | 1 285 | 1 286 | 3 287 | 2 288 | 2 289 | 3 290 | 2 291 | 1 292 | 0 293 | 2 294 | 2 295 | 0 296 | 2 297 | 1 298 | 3 299 | 2 300 | 2 301 | 3 302 | 2 303 | 0 304 | 0 305 | 3 306 | 3 307 | 0 308 | 3 309 | 0 310 | 3 311 | 3 312 | 3 313 | 3 314 | 3 315 | -------------------------------------------------------------------------------- /schemes/inset.rse: -------------------------------------------------------------------------------- 1 | 3 2 | 6 3 | 2 4 | 1 5 | 0 6 | 3 7 | 0 8 | 0 9 | 2 10 | 2 11 | 0 12 | 3 13 | 3 14 | 0 15 | 2 16 | 1 17 | 1 18 | 3 19 | 0 20 | 3 21 | 2 22 | 2 23 | 1 24 | 3 25 | 3 26 | 3 27 | 0 28 | 0 29 | 0 30 | 1 31 | 1 32 | 0 33 | 0 34 | 3 35 | 0 36 | 1 37 | 2 38 | 0 39 | 0 40 | 0 41 | 3 42 | 1 43 | 1 44 | 1 45 | 0 46 | 3 47 | 3 48 | 1 49 | 2 50 | 1 51 | 1 52 | 2 53 | 0 54 | 2 55 | 2 56 | 0 57 | 0 58 | 3 59 | 0 60 | 3 61 | 3 62 | 0 63 | 1 64 | 2 65 | 1 66 | 2 67 | 2 68 | 1 69 | 0 70 | 3 71 | 3 72 | 3 73 | 3 74 | 3 75 | 0 76 | 0 77 | 0 78 | 3 79 | 0 80 | 0 81 | 1 82 | 1 83 | 0 84 | 2 85 | 1 86 | 0 87 | 0 88 | 0 89 | 3 90 | 3 91 | 0 92 | 3 93 | 1 94 | 1 95 | 1 96 | 2 97 | 1 98 | 1 99 | 1 100 | 1 101 | 1 102 | 2 103 | 1 104 | 1 105 | 1 106 | 2 107 | 1 108 | 2 109 | 2 110 | 1 111 | 0 112 | 0 113 | 3 114 | 3 115 | 0 116 | 3 117 | 0 118 | 3 119 | 3 120 | 3 121 | 3 122 | 3 123 | 1 124 | 1 125 | 0 126 | 2 127 | 1 128 | 0 129 | 1 130 | 2 131 | 0 132 | 2 133 | 2 134 | 0 135 | 1 136 | 1 137 | 1 138 | 2 139 | 1 140 | 1 141 | 1 142 | 2 143 | 1 144 | 2 145 | 2 146 | 1 147 | -------------------------------------------------------------------------------- /schemes/planeSplit: -------------------------------------------------------------------------------- 1 | 2 2 | 2 3 | 1 4 | 0 5 | 0 6 | 2 7 | 0 8 | 0 9 | 1 10 | 2 11 | 0 12 | 2 13 | 2 14 | 0 15 | 1 16 | 0 17 | 2 18 | 2 19 | 0 20 | 2 21 | 1 22 | 2 23 | 2 24 | 2 25 | 2 26 | 2 27 | 0 28 | 0 29 | 0 30 | 1 31 | 0 32 | 0 33 | 0 34 | 2 35 | 0 36 | 1 37 | 2 38 | 0 39 | 0 40 | 0 41 | 2 42 | 1 43 | 0 44 | 2 45 | 0 46 | 2 47 | 2 48 | 1 49 | 2 50 | 2 51 | -------------------------------------------------------------------------------- /schemes/subdivide2x2.rse: -------------------------------------------------------------------------------- 1 | 2 2 | 8 3 | 0 4 | 0 5 | 0 6 | 1 7 | 0 8 | 0 9 | 0 10 | 1 11 | 0 12 | 1 13 | 1 14 | 0 15 | 0 16 | 0 17 | 1 18 | 1 19 | 0 20 | 1 21 | 0 22 | 1 23 | 1 24 | 1 25 | 1 26 | 1 27 | 0 28 | 0 29 | 1 30 | 1 31 | 0 32 | 1 33 | 0 34 | 1 35 | 1 36 | 1 37 | 1 38 | 1 39 | 0 40 | 0 41 | 2 42 | 1 43 | 0 44 | 2 45 | 0 46 | 1 47 | 2 48 | 1 49 | 1 50 | 2 51 | 0 52 | 1 53 | 0 54 | 1 55 | 1 56 | 0 57 | 0 58 | 2 59 | 0 60 | 1 61 | 2 62 | 0 63 | 0 64 | 1 65 | 1 66 | 1 67 | 1 68 | 1 69 | 0 70 | 2 71 | 1 72 | 1 73 | 2 74 | 1 75 | 0 76 | 1 77 | 1 78 | 1 79 | 1 80 | 1 81 | 0 82 | 2 83 | 1 84 | 1 85 | 2 86 | 1 87 | 0 88 | 1 89 | 2 90 | 1 91 | 1 92 | 2 93 | 0 94 | 2 95 | 2 96 | 1 97 | 2 98 | 2 99 | 1 100 | 0 101 | 0 102 | 2 103 | 0 104 | 0 105 | 1 106 | 1 107 | 0 108 | 2 109 | 1 110 | 0 111 | 1 112 | 0 113 | 1 114 | 2 115 | 0 116 | 1 117 | 1 118 | 1 119 | 1 120 | 2 121 | 1 122 | 1 123 | 1 124 | 0 125 | 1 126 | 2 127 | 0 128 | 1 129 | 1 130 | 1 131 | 1 132 | 2 133 | 1 134 | 1 135 | 1 136 | 0 137 | 2 138 | 2 139 | 0 140 | 2 141 | 1 142 | 1 143 | 2 144 | 2 145 | 1 146 | 2 147 | 1 148 | 1 149 | 0 150 | 2 151 | 1 152 | 0 153 | 1 154 | 2 155 | 0 156 | 2 157 | 2 158 | 0 159 | 1 160 | 1 161 | 1 162 | 2 163 | 1 164 | 1 165 | 1 166 | 2 167 | 1 168 | 2 169 | 2 170 | 1 171 | 1 172 | 1 173 | 1 174 | 2 175 | 1 176 | 1 177 | 1 178 | 2 179 | 1 180 | 2 181 | 2 182 | 1 183 | 1 184 | 1 185 | 2 186 | 2 187 | 1 188 | 2 189 | 1 190 | 2 191 | 2 192 | 2 193 | 2 194 | 2 195 | -------------------------------------------------------------------------------- /videos.md: -------------------------------------------------------------------------------- 1 | ### Modeling sessions 2 | 3 | Modeling the Cow model shown in the teaser of the paper. 4 | 5 | https://github.com/gcherchi/HexBox/assets/14749123/c442f8cd-2c3b-4591-968c-52a964f10cfb 6 | 7 | 8 | 9 | HexBox supports the creation of hexahedral meshes that are outside of the scope of previous fully interactive modeling approaches working in polycube space, either because they contain internal singularities, or because fitting cuboids in the user interface is problematic due to the presence of non axis-aligned topological features or twisting. 10 | 11 | https://github.com/gcherchi/HexBox/assets/14749123/5e87698f-9197-4c8e-b2f3-c7c4866f7594 12 | 13 | 14 | 15 | Modeling sessions of some of the models created from scratch and shown in Fig 12 of the paper. 16 | 17 | https://github.com/gcherchi/HexBox/assets/14749123/aeeacb36-9af4-4413-b5a1-f0d3f75defe4 18 | 19 | https://github.com/gcherchi/HexBox/assets/14749123/9898b9cd-3dc8-4bd0-a197-b9e3e39a838e 20 | 21 | https://github.com/gcherchi/HexBox/assets/14749123/f0eda324-8ee6-497e-9ec4-2ff69d7b6fbb 22 | 23 | https://github.com/gcherchi/HexBox/assets/14749123/667c8b96-2795-4ad4-aee4-87bab76f35fc 24 | 25 | https://github.com/gcherchi/HexBox/assets/14749123/5cb319af-89d8-4384-8f93-67fd6ccd327b 26 | 27 | https://github.com/gcherchi/HexBox/assets/14749123/9f30da1d-56d4-418a-8783-7be37e73ac21 28 | 29 | 30 | 31 | Modeling sessions of some of the models created using HexBox as a remeshing tool and shown in Fig 13 of the paper. 32 | 33 | https://github.com/gcherchi/HexBox/assets/14749123/f3e26889-2e27-4833-8238-ae76e5a2f1fb 34 | 35 | https://github.com/gcherchi/HexBox/assets/14749123/7d0c0f1c-9b3e-45f6-a456-d06b050eaa27 36 | 37 | https://github.com/gcherchi/HexBox/assets/14749123/6604b0eb-93d7-4706-8e24-eba77eba30e6 38 | 39 | https://github.com/gcherchi/HexBox/assets/14749123/6007c1f5-7d59-4f5e-867e-b29fd6b3b8d0 40 | 41 | 42 | 43 | HexBox allows users to model a wide range of mesh topologies, regardless of the number of handles and inner cavities. 44 | The Tic-tac-toe model has genus 5. The Hollow-sphere model has one cavity. 45 | 46 | https://github.com/gcherchi/HexBox/assets/14749123/abe0118c-d72c-4e2c-88de-d3ab3eecea5f 47 | 48 | https://github.com/gcherchi/HexBox/assets/14749123/645be510-06ae-4e1f-8a15-c2ac567a064f 49 | 50 | 51 | Modeling a hexmesh with multiple connected components starting from a single cube is possible with HexBox. 52 | The desired effect can be obtained by using hex removal to separate the various components. 53 | 54 | https://github.com/gcherchi/HexBox/assets/14749123/bf5446d3-af5f-41d5-9b69-c725229912e2 55 | 56 | 57 | Starting from a plain wheel, we modeled a single dent in HexBox and then copy/pasted it to insert all the others. 58 | The whole process took 2:42 min. Making the same model (Cogwheel1) creating each dent separately took 4:15 min. 59 | 60 | 61 | 62 | https://github.com/gcherchi/HexBox/assets/14749123/4f5e9d8d-f41d-459d-b465-d5dacd234c85 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | --------------------------------------------------------------------------------