├── .clang-format ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md └── tutorials ├── common └── shared_utils.cpp ├── direction_fields └── main.cpp ├── load_mesh └── main.cpp └── simple_mutation └── main.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AlignAfterOpenBracket: Align 3 | AlignOperands: 'true' 4 | AllowShortBlocksOnASingleLine: 'false' 5 | AllowShortIfStatementsOnASingleLine: 'true' 6 | AllowShortLoopsOnASingleLine: 'true' 7 | AlwaysBreakTemplateDeclarations: 'true' 8 | BinPackParameters: 'true' 9 | BreakBeforeBraces: Attach 10 | ColumnLimit: '120' 11 | IndentWidth: '2' 12 | KeepEmptyLinesAtTheStartOfBlocks: 'true' 13 | MaxEmptyLinesToKeep: '2' 14 | PointerAlignment: Left 15 | ReflowComments: 'true' 16 | SpacesInAngles: 'false' 17 | SpacesInParentheses: 'false' 18 | SpacesInSquareBrackets: 'false' 19 | Standard: Cpp11 20 | UseTab: Never 21 | 22 | ... 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directories 2 | build/ 3 | build_debug/ 4 | 5 | # Editor and OS things 6 | .DS_Store 7 | .vscode 8 | *.swp 9 | tags 10 | 11 | # Prerequisites 12 | *.d 13 | 14 | # Compiled Object files 15 | *.slo 16 | *.lo 17 | *.o 18 | *.obj 19 | 20 | # Precompiled Headers 21 | *.gch 22 | *.pch 23 | 24 | # Compiled Dynamic libraries 25 | *.so 26 | *.dylib 27 | *.dll 28 | 29 | # Fortran module files 30 | *.mod 31 | *.smod 32 | 33 | # Compiled Static libraries 34 | *.lai 35 | *.la 36 | *.a 37 | *.lib 38 | 39 | # Executables 40 | *.exe 41 | *.out 42 | *.app 43 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/geometry-central"] 2 | path = deps/geometry-central 3 | url = https://github.com/nmwsharp/geometry-central.git 4 | [submodule "deps/polyscope"] 5 | path = deps/polyscope 6 | url = https://github.com/nmwsharp/polyscope.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.0) 2 | 3 | project(geometry-central-tutorials) 4 | 5 | ### Configure output locations 6 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 7 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 9 | 10 | # Print the build type 11 | if(NOT CMAKE_BUILD_TYPE) 12 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release" FORCE) 13 | endif() 14 | message(STATUS "cmake build type: ${CMAKE_BUILD_TYPE}") 15 | 16 | ### Configure the compiler 17 | # This is a basic, decent setup that should do something sane on most compilers 18 | 19 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 20 | 21 | # using Clang (linux or apple) or GCC 22 | message("Using clang/gcc compiler flags") 23 | SET(BASE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Werror -g3") 24 | SET(CMAKE_CXX_FLAGS_DEBUG "") 25 | SET(DISABLED_WARNINGS " -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-deprecated-declarations -Wno-missing-braces -Wno-unused-private-field") 26 | SET(TRACE_INCLUDES " -H -Wno-error=unused-command-line-argument") 27 | 28 | if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 29 | message("Setting clang-specific options") 30 | SET(BASE_CXX_FLAGS "${BASE_CXX_FLAGS} -ferror-limit=3 -fcolor-diagnostics") 31 | SET(CMAKE_CXX_FLAGS_DEBUG "-fsanitize=address -fno-limit-debug-info") 32 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 33 | message("Setting gcc-specific options") 34 | SET(BASE_CXX_FLAGS "${BASE_CXX_FLAGS} -fmax-errors=5") 35 | SET(DISABLED_WARNINGS "${DISABLED_WARNINGS} -Wno-maybe-uninitialized -Wno-format-zero-length -Wno-unused-but-set-parameter -Wno-unused-but-set-variable") 36 | endif() 37 | 38 | SET(CMAKE_CXX_FLAGS "${BASE_CXX_FLAGS} ${DISABLED_WARNINGS}") 39 | SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3") 40 | SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -DNDEBUG") 41 | 42 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 43 | # using Visual Studio C++ 44 | message("Using Visual Studio compiler flags") 45 | set(BASE_CXX_FLAGS "${BASE_CXX_FLAGS} /W4") 46 | set(BASE_CXX_FLAGS "${BASE_CXX_FLAGS} /MP") # parallel build 47 | SET(DISABLED_WARNINGS "${DISABLED_WARNINGS} /wd\"4267\"") # ignore conversion to smaller type (fires more aggressively than the gcc version, which is annoying) 48 | SET(DISABLED_WARNINGS "${DISABLED_WARNINGS} /wd\"4244\"") # ignore conversion to smaller type (fires more aggressively than the gcc version, which is annoying) 49 | SET(DISABLED_WARNINGS "${DISABLED_WARNINGS} /wd\"4305\"") # ignore truncation on initialization 50 | SET(CMAKE_CXX_FLAGS "${BASE_CXX_FLAGS} ${DISABLED_WARNINGS}") 51 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") 52 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") 53 | 54 | add_definitions(/D "_CRT_SECURE_NO_WARNINGS") 55 | add_definitions(-DNOMINMAX) 56 | add_definitions(-D_USE_MATH_DEFINES) 57 | else() 58 | # unrecognized 59 | message( FATAL_ERROR "Unrecognized compiler [${CMAKE_CXX_COMPILER_ID}]" ) 60 | endif() 61 | 62 | 63 | # == Deps 64 | add_subdirectory(deps/geometry-central) 65 | add_subdirectory(deps/polyscope) 66 | 67 | # == Shared things 68 | set(SHARED_SRCS 69 | "tutorials/common/shared_utils.cpp" # none for now 70 | ) 71 | add_library(tutorial-shared "${SHARED_SRCS}") 72 | target_link_libraries(tutorial-shared geometry-central polyscope) 73 | 74 | # == Build each of the tutorials 75 | 76 | # == load_mesh 77 | add_executable(load-mesh "tutorials/load_mesh/main.cpp") 78 | target_link_libraries(load-mesh tutorial-shared) 79 | 80 | # == simple_mutation 81 | add_executable(simple-mutation "tutorials/simple_mutation/main.cpp") 82 | target_link_libraries(simple-mutation tutorial-shared) 83 | 84 | # == direction_fields 85 | add_executable(direction-fields "tutorials/direction_fields/main.cpp") 86 | target_link_libraries(direction-fields tutorial-shared) 87 | 88 | 89 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nicholas Sharp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # geometry-central-tutorials 2 | Tutorials for the geometry-central geometry processing library. 3 | 4 | Each tutorial lives in a subdirectory of 5 | 6 | ### Building and running 7 | 8 | On unix-like machines, use: 9 | ``` 10 | git clone --recurse-submodules https://github.com/nmwsharp/geometry-central-tutorials 11 | cd geometry-central-tutorials 12 | mkdir build && cd build 13 | cmake -DCMAKE_BUILD_TYPE=Release .. 14 | make -j4 15 | 16 | ./bin/load-mesh ../assets/spot.obj 17 | ``` 18 | 19 | The codebase also builds on Visual Studio 2017 & 2019, by using CMake to generate a Visual Studio solution file. 20 | -------------------------------------------------------------------------------- /tutorials/common/shared_utils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmwsharp/geometry-central-tutorials/1b3be79129e7994b30c3a67ba25b8bac77a27e48/tutorials/common/shared_utils.cpp -------------------------------------------------------------------------------- /tutorials/direction_fields/main.cpp: -------------------------------------------------------------------------------- 1 | #include "geometrycentral/surface/direction_fields.h" 2 | #include "geometrycentral/surface/manifold_surface_mesh.h" 3 | #include "geometrycentral/surface/meshio.h" 4 | #include "geometrycentral/surface/surface_mesh.h" 5 | 6 | #include "polyscope/polyscope.h" 7 | #include "polyscope/surface_mesh.h" 8 | 9 | #include "args/args.hxx" 10 | 11 | using namespace geometrycentral; 12 | using namespace geometrycentral::surface; 13 | 14 | int main(int argc, char** argv) { 15 | 16 | // Configure a simple argument parser 17 | // clang-format off 18 | args::ArgumentParser parser(""); 19 | args::HelpFlag help(parser, "help", "Display this help message", {'h', "help"}); 20 | 21 | args::Positional inputFilename(parser, "mesh", "A surface mesh file (see geometry-central docs for valid formats)"); 22 | // clang-format on 23 | 24 | // Parse args 25 | try { 26 | parser.ParseCLI(argc, argv); 27 | } catch (args::Help) { 28 | std::cout << parser; 29 | return 0; 30 | } catch (args::ParseError e) { 31 | std::cerr << e.what() << std::endl; 32 | std::cerr << parser; 33 | return 1; 34 | } 35 | 36 | // Make sure a mesh name was given 37 | if (!inputFilename) { 38 | std::cout << parser; 39 | return EXIT_FAILURE; 40 | } 41 | 42 | // Load a general surface mesh from file 43 | std::unique_ptr mesh; 44 | std::unique_ptr geometry; 45 | std::tie(mesh, geometry) = readManifoldSurfaceMesh(args::get(inputFilename)); 46 | 47 | polyscope::init(); 48 | auto* psMesh = 49 | polyscope::registerSurfaceMesh("input mesh", 50 | geometry->inputVertexPositions, 51 | mesh->getFaceVertexList()); 52 | 53 | // Tell polyscope about vertex tangent spaces 54 | geometry->requireVertexTangentBasis(); 55 | VertexData vBasisX(*mesh); 56 | for (Vertex v : mesh->vertices()) { 57 | vBasisX[v] = geometry->vertexTangentBasis[v][0]; 58 | } 59 | psMesh->setVertexTangentBasisX(vBasisX); 60 | 61 | 62 | VertexData field = computeSmoothestVertexDirectionField(*geometry); 63 | psMesh->addVertexIntrinsicVectorQuantity("vectors", field); 64 | 65 | polyscope::show(); 66 | 67 | return EXIT_SUCCESS; 68 | } 69 | -------------------------------------------------------------------------------- /tutorials/load_mesh/main.cpp: -------------------------------------------------------------------------------- 1 | #include "geometrycentral/surface/manifold_surface_mesh.h" 2 | #include "geometrycentral/surface/meshio.h" 3 | #include "geometrycentral/surface/surface_mesh.h" 4 | 5 | #include "polyscope/polyscope.h" 6 | #include "polyscope/surface_mesh.h" 7 | 8 | #include "args/args.hxx" 9 | 10 | using namespace geometrycentral; 11 | using namespace geometrycentral::surface; 12 | 13 | int main(int argc, char** argv) { 14 | 15 | // Configure a simple argument parser 16 | // clang-format off 17 | args::ArgumentParser parser(""); 18 | args::HelpFlag help(parser, "help", "Display this help message", {'h', "help"}); 19 | 20 | args::Positional inputFilename(parser, "mesh", "A surface mesh file (see geometry-central docs for valid formats)"); 21 | // clang-format on 22 | 23 | // Parse args 24 | try { 25 | parser.ParseCLI(argc, argv); 26 | } catch (args::Help) { 27 | std::cout << parser; 28 | return 0; 29 | } catch (args::ParseError e) { 30 | std::cerr << e.what() << std::endl; 31 | std::cerr << parser; 32 | return 1; 33 | } 34 | 35 | // Make sure a mesh name was given 36 | if (!inputFilename) { 37 | std::cout << parser; 38 | return EXIT_FAILURE; 39 | } 40 | 41 | // Load a general surface mesh from file 42 | std::unique_ptr mesh; 43 | std::unique_ptr geometry; 44 | 45 | // load the mesh, constructing connectivity & geometry 46 | std::tie(mesh, geometry) = readSurfaceMesh(args::get(inputFilename)); 47 | 48 | // alternately, load a mesh which is required to be manifold 49 | // std::tie(mesh, geometry) = readManifoldSurfaceMesh(args::get(inputFilename)); 50 | 51 | // print some information about the mesh 52 | mesh->printStatistics(); 53 | 54 | // Iterate through the vertices of the mesh, printing the degree of each and the incident faces 55 | for (Vertex v : mesh->vertices()) { 56 | std::cout << "Vertex " << v << " has degree " << v.degree() << "\n"; 57 | for (Face fn : v.adjacentFaces()) { 58 | std::cout << " incident on face " << fn << "\n"; 59 | } 60 | } 61 | 62 | 63 | // visualize the mesh with polyscope 64 | polyscope::init(); 65 | polyscope::registerSurfaceMesh("my mesh", geometry->inputVertexPositions, mesh->getFaceVertexList()); 66 | polyscope::show(); 67 | 68 | return EXIT_SUCCESS; 69 | } 70 | -------------------------------------------------------------------------------- /tutorials/simple_mutation/main.cpp: -------------------------------------------------------------------------------- 1 | #include "geometrycentral/surface/manifold_surface_mesh.h" 2 | #include "geometrycentral/surface/meshio.h" 3 | #include "geometrycentral/surface/surface_mesh.h" 4 | 5 | #include "polyscope/polyscope.h" 6 | #include "polyscope/surface_mesh.h" 7 | 8 | #include "args/args.hxx" 9 | 10 | using namespace geometrycentral; 11 | using namespace geometrycentral::surface; 12 | 13 | int main(int argc, char** argv) { 14 | 15 | // Configure a simple argument parser 16 | // clang-format off 17 | args::ArgumentParser parser(""); 18 | args::HelpFlag help(parser, "help", "Display this help message", {'h', "help"}); 19 | 20 | args::Positional inputFilename(parser, "mesh", "A surface mesh file (see geometry-central docs for valid formats)"); 21 | // clang-format on 22 | 23 | // Parse args 24 | try { 25 | parser.ParseCLI(argc, argv); 26 | } catch (args::Help) { 27 | std::cout << parser; 28 | return 0; 29 | } catch (args::ParseError e) { 30 | std::cerr << e.what() << std::endl; 31 | std::cerr << parser; 32 | return 1; 33 | } 34 | 35 | // Make sure a mesh name was given 36 | if (!inputFilename) { 37 | std::cout << parser; 38 | return EXIT_FAILURE; 39 | } 40 | 41 | // Load a manifold surface mesh from file 42 | std::unique_ptr mesh; 43 | std::unique_ptr geometry; 44 | std::tie(mesh, geometry) = readManifoldSurfaceMesh(args::get(inputFilename)); 45 | 46 | polyscope::init(); 47 | polyscope::registerSurfaceMesh("input mesh", geometry->inputVertexPositions, mesh->getFaceVertexList()); 48 | 49 | VertexData isOrigVert(*mesh, true); 50 | EdgeData isOrigEdge(*mesh, true); 51 | 52 | // Split all edges 53 | std::vector toFlip; 54 | for (Edge e : mesh->edges()) { 55 | if (!isOrigEdge[e]) continue; 56 | 57 | Vertex oldA = e.halfedge().tipVertex(); 58 | Vertex oldB = e.halfedge().tailVertex(); 59 | Vector3 oldAPos = geometry->inputVertexPositions[oldA]; 60 | Vector3 oldBPos = geometry->inputVertexPositions[oldB]; 61 | 62 | // split the edge 63 | Vertex newV = mesh->splitEdgeTriangular(e).vertex(); 64 | isOrigVert[newV] = false; 65 | 66 | // position the new vertex 67 | Vector3 newPos = 0.5 * (oldAPos + oldBPos); 68 | geometry->inputVertexPositions[newV] = newPos; 69 | 70 | // make the new edges 71 | for (Edge e : newV.adjacentEdges()) { 72 | isOrigEdge[e] = false; 73 | Vertex otherV = e.otherVertex(newV); 74 | if (isOrigVert[otherV] && otherV != oldA && otherV != oldB) { 75 | toFlip.push_back(e); 76 | } 77 | } 78 | } 79 | 80 | // Flip edges connecting old to new 81 | for (Edge e : toFlip) { 82 | mesh->flip(e); 83 | } 84 | 85 | auto* psMesh = 86 | polyscope::registerSurfaceMesh("subdiv mesh", geometry->inputVertexPositions, mesh->getFaceVertexList()); 87 | 88 | 89 | 90 | polyscope::show(); 91 | 92 | return EXIT_SUCCESS; 93 | } 94 | --------------------------------------------------------------------------------