### Install mkdocs and theme Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/README.md Installs the necessary tools for managing and previewing the documentation locally. ```shell pip install mkdocs mkdocs-material pygments ``` -------------------------------- ### Sparse Matrix File Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/numerical/linear_algebra_utilities.md Illustrates the format of a sparse matrix ASCII file. Files start with a comment indicating dimensions, followed by lines of row, column, and value for each entry. Rows and columns are 1-indexed. ```plaintext # sparse 1858 1858 1 1 3.969412682295582 2 1 -1.010447934542366 3 1 -0.5162236467210192 ... ``` -------------------------------- ### Preview documentation locally Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/README.md Starts a local development server to preview the documentation. ```shell python3 -m mkdocs serve ``` -------------------------------- ### Dense Matrix File Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/numerical/linear_algebra_utilities.md Illustrates the format of a dense matrix ASCII file. Files start with a comment indicating dimensions, followed by rows of space-separated values. Each line represents a row in the matrix. ```plaintext # dense 1858 3 -0.095724 -0.9734159999999999 -0.244313 -0.105421 -0.984621 -0.301998 -0.003629 -0.979971 -0.245996 ... ``` -------------------------------- ### Fast Marching Method Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/geodesic_distance.md Example demonstrating how to load a mesh, define initial distances for source vertices, and compute geodesic distances using the FMMDistance function. ```cpp #include "geometrycentral/surface/fast_marching_method.h" #include "geometrycentral/surface/meshio.h" // Load a mesh std::unique_ptr mesh; std::unique_ptr geometry; std::tie(mesh, geometry) = loadMesh(filename); // Pick some vertices and initial distances. std::vector> initialDistances; initialDistances.emplace_back(mesh->vertex(7), 0.); initialDistances.emplace_back(mesh->vertex(8), 0.); // Compute distance VertexData dist = FMMDistance(*geometry, initialDistances); /* do something useful */ ``` -------------------------------- ### Getting Number of Points Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/basics.md Returns the total number of points currently in the point cloud. ```c++ size_t count = cloud.nPoints(); ``` -------------------------------- ### Creating a Copy of PointCloud Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/basics.md Returns a deep copy of the PointCloud object. ```c++ std::unique_ptr cloudCopy = cloud.copy(); ``` -------------------------------- ### PointCloud Constructor Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/basics.md Constructs a new point cloud with a specified number of points. ```c++ PointCloud cloud(nPts); ``` -------------------------------- ### Iterating Through Points Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/basics.md Demonstrates how to iterate through all points in a PointCloud using a range-based for loop. ```c++ for(Point p : cloud.points()) { // do science } ``` -------------------------------- ### Basic PointCloud Functionality Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/basics.md Demonstrates creating a PointCloud, accessing its properties, iterating through points, storing data, and associating geometric data like positions and normals. ```c++ #include "geometrycentral/pointcloud/point_cloud.h" #include "geometrycentral/pointcloud/point_position_geometry.h" size_t nPts = 5000; // create a new cloud PointCloud cloud(nPts); // access properties of the cloud std::cout << "cloud has " << cloud.nPoints() << " points.\n"; // Prints "cloud has 5000 points" // iterate through the points in the cloud for(Point p : cloud.points()) { std::cout << "Hi, I'm point " << p << "\n"; // Prints "Hi, I'm point p_245" (etc) } // store data on a point cloud PointData values(cloud); for(Point p : cloud.points()) { values[p] = 7; } // associate 3D positions with the point cloud // compute geometric data using the geomety object PointData positions = /* some positions */; PointPositionGeometry geom(*cloud, positions); // for example, compute normals geom.requireNormals(); for(Point p : cloud.points()) { std::cout << "normal for point " << p << " is " << geom.normals[p] << "\n"; } ``` -------------------------------- ### Poisson Disk Sampling Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/surface_sampling.md Demonstrates how to load a mesh, construct a PoissonDiskSampler, and perform sampling using default and custom parameters. Requires including necessary geometry-central headers. ```cpp #include "geometrycentral/surface/manifold_surface_mesh.h" #include "geometrycentral/surface/vertex_position_geometry.h" #include "geometrycentral/surface/meshio.h" #include "geometrycentral/surface/surface_point.h" #include "geometrycentral/surface/poisson_disk_sampler.h" // Load a mesh std::unique_ptr mesh; std::unique_ptr geometry; std::tie(mesh, geometry) = readManifoldSurfaceMesh(filename); // construct a solver PoissonDiskSampler poissonSampler(*mesh, *geometry); std::vector samples = poissonSampler.sample(); // sample using default parameters // Sample with some different parameters. PoissonDiskOptions sampleOptions; sampleOptions.minDist = 2.; std::vector newSamples = poissonSampler.sample(sampleOptions); ``` -------------------------------- ### Example: Handling Exterior Halfedges and Boundary Loops Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/boundaries.md Demonstrates how to identify an exterior halfedge, access its associated boundary loop 'face', and convert it to a BoundaryLoop object for further processing. ```cpp Halfedge myHe = /* some exterior halfedge */; assert(myHe.isInterior() == false); // this is an exterior halfedge // Traverse to "face" Face bFace = myExteriorHalfedge.face(); // bFace is really a boundary loop, doing any face things // with it would be invalid assert(bFace.isBoundaryLoop() == true); // Convert the "face" to its true boundary loop form BoundaryLoop bLoop = bFace.asBoundaryLoop(); // Now we can do all kinds of things with it for(Edge e : bLoop.adjacentEdges()) { /* do science */ } ``` -------------------------------- ### Configure Include Directories Source: https://github.com/nmwsharp/geometry-central/blob/master/src/CMakeLists.txt Sets public include directories for build and installation targets, including Eigen3 and happly. ```cmake target_include_directories(geometry-central PUBLIC $ $) ``` -------------------------------- ### Accessing a Specific Point Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/basics.md Retrieves a handle to the i'th point in the point cloud. ```c++ Point p = cloud.point(i); ``` -------------------------------- ### Initialize and Visualize Mesh with Polyscope Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/tutorials/load_mesh.md Initializes the Polyscope GUI, registers a surface mesh with its vertex positions and face vertex list, and then displays the GUI until the user exits. Ensure Polyscope is installed and initialized before use. ```cpp polyscope::init(); // initialize the gui // add the mesh to the gui polyscope::registerSurfaceMesh("my mesh", geometry->vertexPositions, mesh->getFaceVertexList()); polyscope::show(); // pass control to the gui until the user exits ``` -------------------------------- ### Repeated Parameterization Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/parameterization.md Demonstrates efficient repeated parameterizations of the same mesh using the stateful BFF class. Loads a mesh, defines target boundary conditions, initializes BFF, and computes two parameterizations. ```cpp #include "geometrycentral/surface/boundary_first_flattening.h" #include "geometrycentral/surface/meshio.h" // Load a mesh std::unique_ptr mesh; std::unique_ptr geometry; std::tie(mesh, geometry) = readManifoldSurfaceMesh(filename); VertexData boundaryScaleFactors = /* target scale factors */; VertexData exteriorAngles = /* target exteriorAngles */; BFF bff(*mesh, *geometry); VertexData parameterization1 = bff.flattenFromScaleFactors(boundaryScaleFactors); VertexData parameterization2 = bff.flattenFromExteriorAngles(exteriorAngles); ``` -------------------------------- ### Repeatedly Solve Linear Systems with Retained Factorization Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/numerical/linear_solvers.md When solving many linear systems with the same matrix A but different right-hand sides (b), it is significantly more efficient to reuse the matrix's factorization. This example demonstrates how to construct a solver, perform multiple solves, and optionally place the solution into an existing vector. It also shows how to query the matrix rank. ```cpp SparseMatrix A = /* ... some matrix ... */; // Build the solver Solver solver(A); // Solve a problem Vector rhs1 = /* ... */; Vector sol = solver.solve(rhs1); // Solve another problem Vector rhs2 = /* ... */; Vector sol2 = solver.solve(rhs2); // Can place solution in existing vector Vector rhs3 = /* ... */; solver.solve(sol, rhs3); // Some solvers have extra powers. // Solver<> can compute matrix rank, since it uses QR under the hood. std::cout << "matrix rank is " << solver.rank() << std::endl; ``` -------------------------------- ### Log Maps with Intrinsic Triangulations Example Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/vector_heat_method.md Demonstrates how to compute logarithmic maps using an intrinsic triangulation, particularly a Delaunay triangulation, for enhanced accuracy. The resulting logmap is then restricted back to the original mesh. ```cpp #include <#include "geometrycentral/surface/signpost_intrinsic_triangulation.h"> // Construct an intrinsic triangulation SignpostIntrinsicTriangulation signpostTri(*mesh, *geometry); signpostTri.flipToDelaunay(); // this is the important step, makes it numerically nice! // Remap the vertex to the intrinsic triangulation, if using Vertex origSourceVert = /* your vertex */; Vertex intrinsicSourceVert = signpostTri->equivalentPointOnIntrinsic(SurfacePoint(origSourceVert)).vertex; // Run the algorithm VectorHeatMethodSolver solver(signpostTri); VertexData logmapIntrinsic = solver->computeLogMap(sourceVert, logMapStrategy); // Copy the logmap back to your original mesh VertexData logmap = signpostTri->restrictToInput(logmapIntrinsic); ``` -------------------------------- ### Compute Convex Embedding with Custom Options Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/embedding.md Customize the convex embedding process by providing an EmbedConvexOptions struct. This example shows how to adjust the tolerance for the embedding algorithm. ```cpp EmbedConvexOptions options; options.tolerance = 1e-2; // use a looser tolerance than default EmbedConvexResult result = embedConvex( *mesh, *uvs, options ); ``` -------------------------------- ### Build documentation Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/README.md Builds the static documentation files for deployment. Deployment steps are pending. ```shell mkdocs build ``` -------------------------------- ### Get MeshData Default Value Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/containers.md Get the current default value for the MeshData container. ```cpp T MeshData::getDefault() const ``` -------------------------------- ### Get Normalized Copy (Function Operation) Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/vector3.md Provides a function to get a normalized copy of a Vector3. ```cpp Vector3 normalize(Vector3 v) { return v.normalize(); } ``` -------------------------------- ### Compile and Run Tests Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/build/tests.md Navigate to the test directory, create a build directory, configure with CMake, and then compile and run the tests using Make. Requires a network connection for the initial download of googletest binaries. ```shell cd test mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Debug .. make -j12 && ./bin/geometry-central-test ``` -------------------------------- ### Construct FlipEdgeNetwork using Dijkstra Path Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/flip_geodesics.md Creates a FlipEdgeNetwork with a single path generated by Dijkstra's algorithm between a start and end vertex. Requires the mesh, geometry, and the start/end vertices. ```cpp static std::unique_ptr FlipEdgeNetwork::constructFromDijkstraPath(ManifoldSurfaceMesh& mesh, IntrinsicGeometryInterface& geom, Vertex startVert, Vertex endVert) ``` -------------------------------- ### Get Vertex Degree Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/elements.md Returns the number of edges connected to the vertex. ```cpp size_t Vertex::degree() ``` -------------------------------- ### Basic Point Cloud Geometry Usage Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/geometry.md Demonstrates how to create a PointCloud and PointPositionGeometry, then compute and access per-point normals and the Laplace matrix. Ensure quantities are computed by calling their respective require functions before accessing them. ```c++ #include "geometrycentral/pointcloud/point_cloud.h" #include "geometrycentral/pointcloud/point_position_geometry.h" // create a new cloud & geometry object size_t nPts = 5000; PointCloud cloud(nPts); PointData positions = /* some positions */; PointPositionGeometry geom(*cloud, positions); // Per-point normals geom.requireNormals(); for(Point p : cloud.points()) { std::cout << "normal for point " << p << " is " << geom.normals[p] << "\n"; } // Point cloud Laplace matrix geom.requireLaplacian(); Eigen::SparseMatrix L = geom.laplacian; ``` -------------------------------- ### Get Vertex Positions Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/geometry/quantities.md Accesses the 3D vertex positions. Requires `EmbeddedGeometryInterface`. ```cpp geometry.requireVertexPositions(); VertexData positions = geometry.vertexPositions; ``` -------------------------------- ### Get Number of Faces Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the total count of faces in the surface mesh. ```cpp size_t SurfaceMesh::nFaces() ``` -------------------------------- ### Create and Reassign Vector3 Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/vector3.md Demonstrates how to create a Vector3 using brace-initialization and reassign it. ```cpp #include "geometrycentral/utilities/vector3.h" using namespace geometrycentral; Vector3 myVec{3.8, 2.9, 1.1}; //create myVec = Vector3{1.1, 2.2, 3.3}; // reassign ``` -------------------------------- ### Get Number of Edges Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the total count of edges in the surface mesh. ```cpp size_t SurfaceMesh::nEdges() ``` -------------------------------- ### Get Number of Vertices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the total count of vertices in the surface mesh. ```cpp size_t SurfaceMesh::nVertices() ``` -------------------------------- ### Get Incident Corner of a Vertex Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/elements.md Retrieves one of the corners associated with the vertex. ```cpp Corner Vertex::corner() ``` -------------------------------- ### Create and Reassign Vector2 Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/vector2.md Demonstrates how to create and reassign Vector2 objects using brace initialization syntax. ```cpp #include "geometrycentral/utilities/vector2.h" using namespace geometrycentral; Vector2 myVec{3.8, 2.9}; //create myVec = Vector2{1.1, 2.2}; // reassign ``` -------------------------------- ### Basic Usage of PointCloudHeatSolver Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/algorithms/heat_solver.md Demonstrates how to read a point cloud, create a solver, and compute geodesic distance, signed distance to curves, scalar extension, parallel transport, and logarithmic map. Requires including necessary geometry-central headers. ```cpp #include "geometrycentral/pointcloud/point_cloud.h" #include "geometrycentral/pointcloud/point_position_geometry.h" #include "geometrycentral/pointcloud/point_cloud_heat_solver.h" #include "geometrycentral/pointcloud/point_cloud_io.h" using namespace geometrycentral; using namespace geometrycentral::pointcloud; // Read in a point cloud std::unique_ptr cloud; std::unique_ptr geom; std::tie(cloud, geom) = readPointCloud("my_cloud.ply"); // Create the solver PointCloudHeatSolver solver(*cloud, *geom); // Pick a source point or two Point pSource = cloud->point(7); Point pSource2 = cloud->point(8); // Pick a source curve or two std::vector> curves; curves.push_back({cloud->point(11), cloud->point(12), cloud->point(15), cloud->point(14), cloud->point(13)}); curves.push_back({cloud->point(17), cloud->point(18), cloud->point(19)}); // Compute geodesic distance PointData distance = solver.computeDistance(pSource); // Compute signed distance to a set of curves. PointData signedDistance = solver.computeSignedDistance(curves, pointNormals); // Compute scalar extension PointData extended = solver.extendScalars({{pSource, 3.}, {pSource2, -5.}}); // Compute parallel transport Vector2 sourceVec{1, 2}; PointData transport = solver.transportTangentVector(pSource, sourceVec); // Compute the logarithmic map PointData logmap = solver.computeLogMap(pSource); ``` -------------------------------- ### unit Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/vector2.md An alias for the `normalize` function, providing an alternative way to get a unit vector. ```APIDOC ## unit ### Description Alias for `normalize(v)`. ### Signature `Vector2 unit(Vector2 v)` ``` -------------------------------- ### Vector2 Construction Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/vector2.md Demonstrates how to construct Vector2 objects using brace initialization and factory methods. ```APIDOC ## Vector2 Construction `Vector2` is a POD type, so you should use brace-initialization syntax: ```cpp #include "geometrycentral/utilities/vector2.h" using namespace geometrycentral; Vector2 myVec{3.8, 2.9}; // create myVec = Vector2{1.1, 2.2}; // reassign ``` Factory methods can construct a few common values: ### `static Vector2 Vector2::zero()` Returns the zero vector. ### `static Vector2 Vector2::constant(double c)` Returns a vector with all components set to $c$. ### `static Vector2 Vector2::infinity()` Returns the infinite vector $(\infty, \infty)$. ### `static Vector2 Vector2::undefined()` Returns the undefined vector `(NaN, NaN)`. And serve as constructors: ### `static Vector2 Vector2::fromAngle(double theta)` Returns the vector $(\cos(\theta), \sin(\theta))$. ### `static Vector2 Vector2::fromComplex(std::complex c)` Converts a `std::complex` to a `Vector2`. ``` -------------------------------- ### Get face-vertex list from SurfaceMesh Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns a listing of the vertex indices incident on each face. ```cpp std::vector> SurfaceMesh::getFaceVertexList() const ``` -------------------------------- ### Initialize and Query NearestNeighborFinder Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/nearest_neighbors.md Demonstrates initializing the NearestNeighborFinder with a set of points and performing k-nearest neighbor and radius searches. All query results are indices into the input points vector. ```cpp #include "geometrycentral/utilities/knn.h" using namespace geometrycentral; std::vector points = { {0,0,0}, {1,0,0}, {2,0,0}, {3,0,0} }; NearestNeighborFinder finder(points); // 2 nearest points to a query location std::vector nearest = finder.kNearest({1.1, 0, 0}, 2); // 2 nearest neighbors of points[1], excluding itself std::vector neighbors = finder.kNearestNeighbors(1, 2); // all points within radius 1.5 of a query location std::vector inBall = finder.radiusSearch({0, 0, 0}, 1.5); ``` -------------------------------- ### Get type name as string Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/miscellaneous.md Returns the name of a type as a string using typeid(). ```cpp std::string typeNameString(T& x) ``` -------------------------------- ### Get Number of Boundary Vertices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the count of vertices that are incident on the mesh boundary. ```cpp size_t SurfaceMesh::nBoundaryVertices() ``` -------------------------------- ### Get Number of Interior Vertices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the count of vertices that are not incident on the mesh boundary. ```cpp size_t SurfaceMesh::nInteriorVertices() ``` -------------------------------- ### Fetch and Configure Googletest Source: https://github.com/nmwsharp/geometry-central/blob/master/test/CMakeLists.txt Downloads the googletest framework using FetchContent and makes it available for the project. Ensures correct CRT settings on Windows and sets the C++ standard for gtest. ```cmake if(${CMAKE_VERSION} VERSION_LESS 3.14) include(FetchContentLocal) else() include(FetchContent) endif() FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.15.2 SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" ) # Prevent overriding the parent project's compiler/ # settings on Windows set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) set_property(TARGET gtest PROPERTY CXX_STANDARD 11) # silence warning about deprecated copies in gtest # https://github.com/abseil/abseil-cpp/issues/948#issuecomment-846592426 if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") target_compile_options(gtest INTERFACE -Wno-deprecated-copy) endif() ``` -------------------------------- ### Load Manifold and General Surface Meshes Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/utilities/io.md Demonstrates loading a manifold mesh from 'spot.obj' and a general mesh from 'spot_messy.obj'. These functions return unique pointers to `ManifoldSurfaceMesh` and `SurfaceMesh` respectively, along with their associated geometry. ```cpp #include "geometrycentral/surface/meshio.h" using namespace geometrycentral::surface; // Load a surface mesh which is required to be manifold std::unique_ptr mesh; std::unique_ptr geometry; std::tie(mesh, geometry) = readManifoldSurfaceMesh("spot.obj"); // Load a more general surface mesh, which might be nonmanifold std::unique_ptr mesh2; std::unique_ptr geometry2; std::tie(mesh2, geometry2) = readSurfaceMesh("spot_messy.obj"); ``` -------------------------------- ### Get Number of Exterior Halfedges Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the count of exterior halfedges, which are opposite boundary faces. ```cpp size_t SurfaceMesh::nExteriorHalfedges() ``` -------------------------------- ### Vector3 Construction Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/vector3.md Demonstrates how to construct Vector3 objects using brace initialization and factory methods for common values. ```APIDOC ## Vector3 Construction `Vector3` is a POD type, so you should use brace-initialization syntax: ```cpp #include "geometrycentral/utilities/vector3.h" using namespace geometrycentral; Vector3 myVec{3.8, 2.9, 1.1}; // create myVec = Vector3{1.1, 2.2, 3.3}; // reassign ``` Factory methods can construct a few common values: ### `static Vector3 Vector3::zero()` Returns the zero vector. ### `static Vector3 Vector3::constant(double c)` Returns a vector with all components set to $c$. ### `static Vector3 Vector3::infinity()` Returns the infinite vector $(\infty, \infty, \infty)$. ### `static Vector3 Vector3::undefined()` Returns the undefined vector `(NaN, NaN, NaN)`. ``` -------------------------------- ### Get Unit Vector (Function Operation) Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/vector3.md An alias for the normalize function, this returns a unit vector copy. ```cpp Vector3 unit(Vector3 v) { return normalize(v); } ``` -------------------------------- ### Initialize BFF Solver Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/parameterization.md Creates a stateful BFF solver object for efficient repeated parameterizations. Precomputation is performed upon construction. ```cpp BFF bff(*mesh, *geometry); ``` -------------------------------- ### Get pointer type name as string Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/utilities/miscellaneous.md Returns the name of a pointer type as a string using typeid(). ```cpp std::string typeNameString(T* x) ``` -------------------------------- ### Construct and Use SignedHeatSolver Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/signed_heat_method.md Demonstrates how to initialize a `SignedHeatSolver` with mesh geometry and compute distances to specified curves. Ensure your mesh and geometry objects are properly defined before instantiation. ```cpp #include "geometrycentral/surface/signed_heat_method.h" // your mesh and geometry VertexPositionGeometry geometry; SurfaceMesh mesh; // construct a solver SignedHeatSolver signedHeatSolver(geometry); // specify some source geometry std::vector curves; curves.emplace_back(); curves.back().nodes.emplace_back(mesh.vertex(0)); curves.back().nodes.emplace_back(mesh.edge(5), 0.3); // solve! VertexData distance = signedHeatSolver->computeDistance(curves); ``` -------------------------------- ### Get Number of Boundary Loops Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the count of distinct boundary loops in the mesh, each represented as a fictional face. ```cpp size_t SurfaceMesh::nBoundaryLoops() ``` -------------------------------- ### Saving and Loading Matrices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/numerical/linear_algebra_utilities.md Shows how to save and load sparse and dense matrices from ASCII files. Ensure the filenames are correctly specified for saving and loading operations. ```cpp SparseMatrix spMat = loadSparseMatrix(sparseFilename); DenseMatrix dMat = loadDenseMatrix(denseFilename); /* do something with matrices */ saveSparseMatrix(newSparseFilename, spMat); saveDenseMatrix(newDenseFilename, dMat); ``` -------------------------------- ### Set and Get Default Value Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/containers.md Allows setting and retrieving the default value for elements within a MeshData container. ```APIDOC ## void MeshData::setDefault(T newDefault) ### Description Sets a new default value for the container. Does not modify any existing data in the container. ### Method `void` ### Parameters - **newDefault** (T) - The new default value. ## T MeshData::getDefault() const ### Description Get the current default value for the container. ### Method `T` ``` -------------------------------- ### Get Number of Interior Halfedges Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the count of interior halfedges, which are incident on faces. This equals the sum of sides of all faces. ```cpp size_t SurfaceMesh::nInterioHalfedges() ``` -------------------------------- ### Build and Trace Ray with MeshRayTracer Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/utilities/mesh_ray_tracer.md Build the acceleration structure once and then trace rays. The direction vector does not need to be normalized. Requires the geometry of the mesh. ```cpp #include "geometrycentral/surface/mesh_ray_tracer.h" using namespace geometrycentral::surface; // Build the acceleration structure once MeshRayTracer tracer(geometry); // Trace a ray — origin and direction, direction need not be normalized RayHitResult hit = tracer.trace({0.5, 0.5, 10.0}, {0.0, 0.0, -1.0}); if (hit.hit) { // distance along ray double t = hit.t; // which triangle was hit size_t faceIdx = hit.faceIndex; // barycentric coords in that triangle Vector3 bary = hit.faceCoords; } ``` -------------------------------- ### Set Minimum CMake Version Source: https://github.com/nmwsharp/geometry-central/blob/master/src/CMakeLists.txt Specifies the minimum required version of CMake for the project. Ensure your CMake installation meets this requirement. ```cmake cmake_minimum_required(VERSION 3.8.0) ``` -------------------------------- ### Immediate Computation vs. Cached Quantities Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/geometry/geometry.md Demonstrates the difference between computing geometric quantities on-the-fly and using the automatic caching system. Use the cached approach for better performance when quantities are accessed repeatedly. ```cpp VertexPositionGeometry& geometry = /* ... */; // bad: immediate computation everywhere for(Face f : mesh->faces()) { Vector3 normal = geometry.faceNormal(f); } // good: automatic caching and storage geometry.requireFaceNormals(); for(Face f : mesh->faces()) { Vector3 normal = geometry.faceNormals[f]; } ``` -------------------------------- ### Get Face Centroids Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/geometry/quantities.md Computes the geometric center of each face as the average of its vertex positions. Works for faces of any degree. Requires `EmbeddedGeometryInterface`. ```cpp geometry.requireFaceCentroids(); FaceData centroids = geometry.faceCentroids; ``` -------------------------------- ### PointCloudHeatSolver Constructor Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/algorithms/heat_solver.md Creates a new solver for heat methods. Precomputation is performed at startup and lazily as needed. Algorithm options like `tCoef` cannot be changed after construction; create a new solver object with the new settings. ```APIDOC ## PointCloudHeatSolver::PointCloudHeatSolver(PointCloud& cloud, PointPositionGeometry& geom, double tCoef = 1.0) ### Description Create a new solver for the heat methods. Precomputation is performed at startup and lazily as needed. - `cloud` is the point cloud to operate on. - `geom` is the geometry (e.g., vertex positions) for the cloud. Note that nearly any point cloud geometry object can be passed here. For instance, use a `PointPositionFrameGeometry` if you want to represent tangent-valued data in tangent bases of your own choosing. - `tCoef` is the time to use for short time heat flow, as a factor `m * h^2`, where `h` is the mean between-point spacing. The default value of `1.0` is almost always sufficient. Algorithm options (like `tCoef`) cannot be changed after construction; create a new solver object with the new settings. ``` -------------------------------- ### Get Number of Halfedges Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/basics.md Returns the total count of halfedges, including interior and exterior ones. This is always twice the number of edges. ```cpp size_t SurfaceMesh::nHalfedges() ``` -------------------------------- ### Get Vertex Normals Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/geometry/quantities.md Calculates a normal vector for each vertex, defined as the corner-angle weighted average of incident face normals. Requires `EmbeddedGeometryInterface`. ```cpp geometry.requireFaceNormals(); VertexData normals = geometry.vertexNormals; ``` -------------------------------- ### Initialize Mesh Data Containers Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/tutorials/basic_mutation.md Create VertexData and EdgeData containers to track original vertices and edges. Initialize a vector to store edges that will be flipped in a later phase. ```cpp VertexData isOrigVert(*mesh, true); EdgeData isOrigEdge(*mesh, true); std::vector toFlip; ``` -------------------------------- ### Get Face Indices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/indexing.md Retrieves an array of indices for all faces in the mesh. Values range from 0 to F-1, where F is the total number of faces. ```cpp FaceData SurfaceMesh::getFaceIndices() ``` -------------------------------- ### Construct FlipEdgeNetwork with Explicit Paths Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/flip_geodesics.md Initializes a FlipEdgeNetwork with a given set of paths, represented as sequences of halfedges. Optionally marks specific vertices where the path should be pinned. ```cpp FlipEdgeNetwork(ManifoldSurfaceMesh& mesh, IntrinsicGeometryInterface& inputGeom, const std::vector>& paths, VertexData extraMarkedVerts = VertexData()) ``` -------------------------------- ### Get Edge Indices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/indexing.md Retrieves an array of indices for all edges in the mesh. Values range from 0 to E-1, where E is the total number of edges. ```cpp EdgeData SurfaceMesh::getEdgeIndices() ``` -------------------------------- ### Load Mesh and Initialize Polyscope Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/tutorials/direction_fields.md Load a manifold surface mesh from a file and initialize Polyscope. Register the mesh with Polyscope for visualization, ensuring it's manifold for consistent tangent spaces. ```cpp std::unique_ptr mesh; std::unique_ptr geometry; std::tie(mesh, geometry) = readManifoldSurfaceMesh(args::get(inputFilename)); polyscope::init(); auto* psMesh = polyscope::registerSurfaceMesh("input mesh", geometry->vertexPositions, mesh->getFaceVertexList()); ``` -------------------------------- ### Get Vertex Indices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/indexing.md Retrieves an array of indices for all vertices in the mesh. Values range from 0 to V-1, where V is the total number of vertices. ```cpp VertexData SurfaceMesh::getVertexIndices() ``` -------------------------------- ### Construct Point Position Geometry with Initial Positions Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/pointcloud/geometry.md Constructs a PointPositionGeometry object and immediately sets the positions for each point in the point cloud. The provided positions are copied into the geometry's position buffer. ```c++ PointPositionGeometry geom(*cloud, positions); ``` -------------------------------- ### Quick Solves Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/numerical/linear_solvers.md One-off routines for solving sparse linear systems. These functions perform the decomposition and solve in a single call. ```APIDOC ## solve ### Description Solve a system with a general matrix using QR decomposition. ### Method `solve(SparseMatrix& matrix, const Vector& rhs)` ### Parameters - `matrix` (SparseMatrix) - The coefficient matrix. - `rhs` (Vector) - The right-hand side vector. ### Response - Returns `Vector`: The solution vector. ### Warning The Eigen built-in sparse QR solver is very inefficient for many problems and may not work well for underdetermined systems. ``` ```APIDOC ## solveSquare ### Description Solve a system with a square matrix using LU decomposition. ### Method `solveSquare(SparseMatrix& matrix, const Vector& rhs)` ### Parameters - `matrix` (SparseMatrix) - The square coefficient matrix. - `rhs` (Vector) - The right-hand side vector. ### Response - Returns `Vector`: The solution vector. ``` ```APIDOC ## solvePositiveDefinite ### Description Solve a system with a symmetric positive (semi-)definite matrix using LDLT decomposition. ### Method `solvePositiveDefinite(SparseMatrix& matrix, const Vector& rhs)` ### Parameters - `matrix` (SparseMatrix) - The symmetric positive (semi-)definite coefficient matrix. - `rhs` (Vector) - The right-hand side vector. ### Response - Returns `Vector`: The solution vector. ``` -------------------------------- ### Get Corner Indices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/indexing.md Retrieves an array of indices for all corners in the mesh. Values range from 0 to C-1, where C is the total number of corners. ```cpp CornerData SurfaceMesh::getCornerIndices() ``` -------------------------------- ### Get Halfedge Indices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/indexing.md Retrieves an array of indices for all halfedges in the mesh. Values range from 0 to H-1, where H is the total number of halfedges. ```cpp HalfedgeData SurfaceMesh::getHalfedgeIndices() ``` -------------------------------- ### Basic Usage of PolygonMeshHeatSolver Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/polygon_heat_solver.md Demonstrates how to read a mesh, create a PolygonMeshHeatSolver, and compute unsigned geodesic distance, signed distance to curves, scalar extension, and tangent vector transport. ```cpp #include "geometrycentral/surface/polygon_mesh_heat_solver.h" using namespace geometrycentral; using namespace geometrycentral::surface; // Read in a polygon mesh std::unique_ptr mesh; std::unique_ptr geom; std::tie(mesh, geom) = readSurfaceMesh("my_mesh.obj"); // Create the solver PolygonMeshHeatSolver solver(*geom); // Pick a source point or two Vertex vSource = mesh->vertex(7); Vertex vSource2 = mesh->vertex(8); // Pick some source curves std::vector> curves; curves.push_back({mesh->vertex(11), mesh->vertex(12), mesh->vertex(15), mesh->vertex(14), mesh->vertex(13)}); curves.push_back({mesh->vertex(17), mesh->vertex(18), mesh->vertex(19)}); // Compute geodesic distance VertexData distance = solver.computeDistance(vSource); // Compute signed distance to a set of curves. VertexData signedDistance = solver.computeSignedDistance(curves); // Compute scalar extension VertexData extended = solver.extendScalars({{vSource, 3.}, {vSource2, -5.}}); // Compute parallel transport Vector2 sourceVec{1, 2}; VertexData transport = solver.transportTangentVector(vSource, sourceVec); ``` -------------------------------- ### Solver Class for General Matrices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/numerical/linear_solvers.md This class provides a stateful interface for solving linear systems with general sparse matrices using QR decomposition. It supports constructing the solver from a matrix, solving into a new vector, solving into an existing vector, and querying the matrix rank. Note that the Eigen QR solver can be inefficient and may not handle underdetermined systems well. ```cpp template > class Solver { public: // construct from a matrix Sovler(SparseMatrix& mat); // solve and return result in new vector Vector solve(const Vector& rhs); // solve and place result in existing vector void solve(Vector& result, const Vector& rhs); // report the rank of the matrix. Some solvers may give only an approximate rank. size_t rank(); }; ``` -------------------------------- ### Get Incident Halfedge of a Vertex Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/elements.md Retrieves one of the halfedges connected to the vertex. For boundary vertices, it returns the interior halfedge along the boundary. ```cpp Halfedge Vertex::halfedge() ``` -------------------------------- ### Get Distance Gradient at Vertex Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/geodesic_distance.md Returns the gradient of the distance function at the given vertex. This is a unit tangent vector pointing away from the closest source. ```cpp Vector2 GeodesicAlgorithmExact::getDistanceGradient(const Vertex& v) const ``` -------------------------------- ### Initialize and Embed using ConvexEmbedder Class Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/embedding.md Utilize the ConvexEmbedder class for more control over the embedding process. Call init() to check preconditions and embed() to find the embedding. Refresh vertex coordinates after successful embedding. ```cpp ConvexEmbedder embedder( *mesh, *uvs, options ); if( embedder.init() ) { // try initializing the embedding if( embedder.embed() ) { // try finding the embedding embedder.refreshVertexCoordinates(); // compute final vertex coordinates // now do something with members of embedder } } ``` -------------------------------- ### Get Vertex Face Degree Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/elements.md Returns the number of faces incident on the vertex. This is equal to the vertex degree on the interior of the mesh, and one less at the boundary. ```cpp size_t Vertex::faceDegree() ``` -------------------------------- ### PolygonMeshHeatSolver Constructor Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/polygon_heat_solver.md Creates a new solver for the heat methods. Precomputation is performed at startup and lazily as needed. Algorithm options cannot be changed after construction. ```APIDOC ## PolygonMeshHeatSolver::PolygonMeshHeatSolver(EmbeddedGeometryInterface& geom, double tCoef = 1.0) ### Description Create a new solver for the heat methods. Precomputation is performed at startup and lazily as needed. - `geom` is the geometry (and hence mesh) on which to compute. Any embedded geometry object (`VertexPositionGeometry`, etc) can be passed here. - `tCoef` is the time to use for short time heat flow, as a factor `m * h^2`, where `h` is the maximum between-point spacing. The default value of `1.0` is almost always sufficient. Algorithm options (like `tCoef`) cannot be changed after construction; create a new solver object with the new settings. ``` -------------------------------- ### Get All Edges as Surface Points Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/flip_geodesics.md Retrieves all edges in the underlying triangulation as a sequence of SurfacePoints. This provides a comprehensive view of the mesh's edge structure. ```cpp std::vector> FlipEdgeNetwork::getAllEdgePolyline() ``` -------------------------------- ### Load and Visualize Input Mesh Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/tutorials/basic_mutation.md Load a manifold surface mesh from a file and initialize Polyscope for visualization. This step requires the input mesh to be manifold. ```cpp std::unique_ptr mesh; std::unique_ptr geometry; std::tie(mesh, geometry) = readManifoldSurfaceMesh(args::get(inputFilename)); polyscope::init(); polyscope::registerSurfaceMesh("input mesh", geometry->vertexPositions, mesh->getFaceVertexList()); // call polyscope::show(); to inspect the mesh at this point ``` -------------------------------- ### Iterate Vertex Incoming Halfedges Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/navigation.md Iterate over halfedges that point inward to a given vertex. Asserts that the twin of the halfedge's vertex is the starting vertex. ```cpp for(Halfedge he : vert.incomingHalfedges()) { assert(he.twin().vertex() == vert); // true // do science here } ``` -------------------------------- ### Iterate Vertex Outgoing Halfedges Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/navigation.md Iterate over halfedges that point outward from a given vertex. Asserts that the halfedge's vertex is indeed the starting vertex. ```cpp for(Halfedge he : vert.outgoingHalfedges()) { assert(he.vertex() == vert); // true // do science here } ``` -------------------------------- ### Include EdgeLengthGeometry Header Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/geometry/geometry.md Include the necessary header file for using the EdgeLengthGeometry class. ```cpp #include "geometrycentral/surface/edge_length_geometry.h" ``` -------------------------------- ### Get Vertex Dual Mean Curvature Normals Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/geometry/quantities.md Computes the integrated mean curvature normal for each vertex. This quantity is only valid on triangular meshes and requires `EmbeddedGeometryInterface`. ```cpp geometry.requireVertexDualMeanCurvatureNormals(); VertexData meanCurvatureNormals = geometry.vertexDualMeanCurvatureNormals; ``` -------------------------------- ### Clone and Build geometry-central with CMake Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/build/building.md Standard procedure to clone the repository and compile the library using CMake. Assumes a Unix-like environment. ```sh git clone --recurse-submodules https://github.com/nmwsharp/geometry-central.git cd geometry-central mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release .. make -j4 ``` -------------------------------- ### Get Interior Vertex Indices Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/surface_mesh/indexing.md Retrieves an array of indices for all interior vertices in the mesh. Values range from 0 to I-1, where I is the total number of interior vertices. ```cpp VertexData SurfaceMesh::getInteriorVertexIndices() ``` -------------------------------- ### Compute Geodesic Distances with Heat Method Solver Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/geodesic_distance.md Demonstrates initializing the `HeatMethodDistanceSolver` and computing distances from various source types (vertices and surface points). The solver performs precomputation upon construction for efficient subsequent solves. ```cpp #include "geometrycentral/surface/heat_method_distance.h" #include "geometrycentral/surface/meshio.h" // Load a mesh std::unique_ptr mesh; std::unique_ptr geometry; std::tie(mesh, geometry) = loadMesh(filename); // Create the Heat Method solver HeatMethodDistanceSolver heatSolver(*geometry); // Alternately, set useRobustLaplacian=true to get a robustified version // HeatMethodDistanceSolver heatSolver(*geometry, 1.0, true); // Some vertices as source set std::vector sourceVerts = /* some interesting vertices */ for(Vertex v : sourceVerts) { VertexData distToSource = heatSolver.computeDistance(v); /* do something useful */ } // A point in a face as a source set Face sourceF = /* some face */; Vector3 sourceFBary = /* some barycentric coords in face */; SurfacePoint targetP(sourceF, sourceFBary); VertexData distToSource = heatSolver.computeDistance(targetP); /* do something useful */ ``` -------------------------------- ### Construct VectorHeatSolver Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/vector_heat_method.md Create a new solver for the Vector Heat Method. Precomputation is performed lazily as needed. Algorithm options cannot be changed after construction. ```cpp #include "geometrycentral/surface/vector_heat_method.h" // your mesh and geometry VertexPositionGeometry geometry; SurfaceMesh mesh; // construct a solver VectorHeatMethodSolver vhmSolver(geometry); ``` -------------------------------- ### sampleFromInput Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/intrinsic_triangulations/basics.md Given data defined on the vertices of the input triangulation, samples it to the vertices of the intrinsic triangulation. ```APIDOC ## sampleFromInput ### Description Given data defined on the vertices of the input triangulation, samples it to the vertices of the intrinsic triangulation. ### Method `VertexData IntrinsicTriangulation::sampleFromInput(const VertexData& dataOnInput)` ``` -------------------------------- ### Get Face Normals Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/geometry/quantities.md Calculates a normal vector for each face. For non-triangular faces, it uses the normalized vector area computed via the shoelace formula. Requires `EmbeddedGeometryInterface`. ```cpp geometry.requireFaceNormals(); FaceData normals = geometry.faceNormals; ``` -------------------------------- ### Compute Multiple Geodesic Paths Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/flip_geodesics.md Demonstrates a workflow for computing multiple point-to-point geodesic paths. It involves initializing a FlipEdgeNetwork, computing an initial path, reinitializing the network, shortening the path, and rewinding the network for the next path. Requires support for rewinding. ```cpp std::unique_ptr flipNetwork(new FlipEdgeNetwork(*mesh, *geometry, {})); flipNetwork->supportRewinding = true; flipNetwork->posGeom = geometry.get(); for(/* each path to compute */) { Vertex startVert; // populate these somehow Vertex endVert; // Get an initial dijkstra path // (surface/mesh_graph_algorithms.h) std::vector dijkstraPath = shortestEdgePath(*geom, startVert, endVert); // Reinitialize the ede network to contain this path flipNetwork->reinitializePath({dijkstraPath}); // Straighten the path to geodesic flipNetwork->iterativeShorten(); // Extract the path and store it in the vector std::vector path3D = flipNetwork->getPathPolyline3D().front(); // Be kind, rewind flipNetwork->rewind(); } ``` -------------------------------- ### Get Distance Gradient at Surface Point Source: https://github.com/nmwsharp/geometry-central/blob/master/docs/docs/surface/algorithms/geodesic_distance.md Returns the gradient of the distance function at the given surface point. This is a unit tangent vector pointing away from the closest source. ```cpp Vector2 GeodesicAlgorithmExact::getDistanceGradient(const SurfacePoint& point) const ```