# Geometry

The geometry classes associates 3D positions with the points in a point cloud, and can compute various derived quantities. These use the same paradigm of “requiring quantities” as the surface mesh geometry interface, see additional documentation there.

`#include "geometrycentral/pointcloud/point_position_geometry.h"`

Point clouds are in beta

The current point cloud API in geometry-central is preliminary, and may change in future versions.

The geometry classes manage buffers of geometric quantities which can be computed, as well as a dependency graph relationship between these quantities. For instance, calling `geom.requireNormals()`

will ensure the `geom.normals`

buffer is populated with normals, additionally computing & caching any preceding quantities which are needed (here: neighborhoods). Derived classes can be used to extend with more features, specify additional input data, or override the computation of particular quantities.

**Example:** Basic use of quantities

```
#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<Vector3> 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<double> L = geom.laplacian;
```

## Point Position Geometry

This is the most basic core geometry, corresponding to a 3D position associated with each vertex.

Remember, for each quantity YYY, call `requireYYY()`

to ensure it has been computed, then access it at `geom.YYYs`

.

### Construction

`PointPositionGeometry::PointPositionGeometry(PointCloud& cloud)`

Constructs a new unitialized point position geometry on the cloud.

You should immediately set positions like

```
PointPositionGeometry goem(*cloud);
for(Point p : cloud->points()) {
geom.positions[p] = /* some Vector3 position */;
}
```

`PointPositionGeometry::PointPositionGeometry(PointCloud& cloud, const PointData<Vector3>& positions)`

Constructs a new point position geometry with specified positions.

The given positions will be copied to the `geom.positions`

field.

### Quantities

## neighbors

##### neighbors

A collection of `k`

-nearest neighbors for each point. Represented via a `Neighborhoods`

object, which encapsulates the functionality.

Set the number of neighbors by assigning to `PointPositionGeometry::kNeighborSize`

. The default is 30. If you’re going to change it, do so *before* requiring any quantities that involve neighbors (most of them).

Iterate over neighbors like:

```
geom.requireNeighbors();
for (Point p : cloud->points()) {
std::vector<Point>& neigh = geom.neighbors->neighbors[p];
size_t M = neigh.size();
for (size_t iN = 0; iN < M; iN++) {
Point pN = neigh[iN];
std::cout << "Point " << p << " has neighbor " << pN << std::endl;
}
}
```

**member:**`std::unique_ptr<Neighborhoods> PointPositionGeometry::neighbors`

**require:**`void PointPositionGeometry::requireNeighbors()`

Changes coming

A future update will replace this nested `std::vector<>`

interface with a flat list and fancy iterators.

## normals

##### normals

A 3D unit normal at each point.

Normals are comptuted via PCA over neighbors. By default, nothing is done to orient normals, so orientations will be arbitrary.

**member:**`PointData<Vector3> PointPositionGeometry::normals`

**require:**`void PointPositionGeometry::requireNormals()`

## tangent basis

##### tangent basis

A pair of X-Y tangent basis axes at each point. Guaranteed to form an orthonormal right-handed coordinate frame with the normal vector.

**member:**`PointData<std::array<Vector3,2>> PointPositionGeometry::tangentBasis`

**require:**`void PointPositionGeometry::requireTangentBasis()`

## neighborhood tangent coordinates

##### tangent coordinates

Local 2D tangent coordinates associated with each neighboring point, corresponding to projection in to the axes in `geom.tangentBasis`

.

**member:**`PointData<std::vector<Vector2>> PointPositionGeometry::tangentCoordinates`

**require:**`void PointPositionGeometry::requireTangentCoordinates()`

## neighborhood tangent transport

##### tangent transport

Parallel transport coefficients to rotate tangent vectors between neighboring frames.`tangentTransport[i][j]`

holds the rotation which maps a vector in the tangent space of i to that of j.

**member:**`PointData<std::vector<Vector2>> PointPositionGeometry::tangentTransport`

**require:**`void PointPositionGeometry::requireTangentTransport()`

## tufted triangulation

##### tufted triangulation

A tufted intrinsic triangulation associated with the point cloud. Intuitively this is a special triangulation atop the points in the pointcloud, represented only by its connectivity and edge lengths. It is a very effective numerical data structure to compute downstream quantities, like a highly-quality Laplace matrix. To be clear, this is *not* a “nice” triangulation like you might get from 3D reconstruction; instead it is a crazy nonmanifold triangulation which happens to have a very useful structure for subsequent numerical computations. See the publication “A Laplacian for Nonmanifold Triangle Meshes” for formal details.

Intuitively,

**member:**`PointData<std::unique_ptr<surface::SurfaceMesh>> PointPositionGeometry::tuftedMesh`

**member:**`PointData<std::unique_ptr<surface::EdgeLengthGeometry>> PointPositionGeometry::tuftedGeom`

**require:**`void PointPositionGeometry::requireTuftedTriangulation()`

## Laplacian

##### Laplacian

A Laplace matrix for the point cloud. Computed internally using the tufted triangulation as described in A Laplacian for Nonmanifold Triangle Meshes”.

**member:**`Eigen::SparseMatrix<double> PointPositionGeometry::laplacian`

**require:**`void PointPositionGeometry::requireLaplacian()`

## connection Laplacian

##### connection Laplacian

A connection Laplace matrix for the point cloud, which is similar to normal scalar Laplacian, but operates on tangent vectors at each point rather than on scalar values. See “The Vector Heat Method” for a detailed introduction to connection Laplacians.

**Note:** This connection Laplacian includes an orientation flip to handle inconsistent normals. Rather than a complex matrix, it builds a `2N x 2N`

expanded real matrix, with sign flips on imaginary elements to conjugate (a necessary trick, because conjugation is not a complex-linear operation). This allows us to apply the connection even when normal orientations are inconsistent.

**member:**`Eigen::SparseMatrix<double> PointPositionGeometry::connectionLaplacian`

**require:**`void PointPositionGeometry::requireConnectionLaplacian()`

## gradient

##### gradient

A gradient operator `G`

for the point cloud. Given a vector `v`

of scalar values at each point in the point cloud, multiplying `G*v`

yields a tanget vector at each point (as a complex number), representing the spatial gradient of `v`

at that point.

Constructed via a least-squares approximation in the neighborhood tangent coordinate space at each point.

**member:**`Eigen::SparseMatrix<std::complex<double>> PointPositionGeometry::gradient`

**require:**`void PointPositionGeometry::requireGradient()`

## Point Position & Normal Geometry

The class `PointPositionNormalGeometry`

extends the basic `PointPositionGeometry`

class to manually specify a set of known normals at points. These normals will be used for all computations, rather than computing normals from scratch.

The `PointPositionNormalGeometry`

**is-a** `PointPositionGeometry`

via inheritance, so you can directly pass it anywhere a `PointPositionGeometry`

is expected.

`#include "geometrycentral/pointcloud/point_position_normal_geometry.h"`

**Example:**

```
std::unique_ptr<PointCloud> cloud; // your cloud
PointData<Vector3> positions(*cloud); // populate with your positions
PointData<Vector3> knownNormals(*cloud); // populate with your normals
PointPositionNormalGeometry geom(*cloud, positions, knownNormals);
// we can now use this just like a `PointPositionGeometry` as above
```

`PointPositionNormalGeometry::PointPositionNormalGeometry(PointCloud& cloud, const PointData<Vector3>& positions, const PointData<Vector3>& normals)`

Constructs a new point position geometry with specified normals.

The given normals will be copied to the `geom.normals`

field.

## Point Position & Tangent Basis Geometry

The class `PointPositionFrameGeometry`

extends the basic `PointPositionGeometry`

class to manually specify a set of known normals and tangent frames at points. These frames / normals will be used for all computations, rather than computing frames / normals from scratch.

The input frames are specified via three vectors at each point `std::array<Vector3, 3>`

. These vectors should form a right-handed, orthonormal basis at each vertex, with the two vectors forming the X/Y tangent basis, and the third as the normal direction.

The `PointPositionFrameGeometry`

**is-a** `PointPositionGeometry`

via inheritance, so you can directly pass it anywhere a `PointPositionGeometry`

is expected.

`#include "geometrycentral/pointcloud/point_position_frame_geometry.h"`

**Example:**

```
std::unique_ptr<PointCloud> cloud; // your cloud
PointData<Vector3> positions(*cloud); // populate with your positions
// your {tangent-X, tangent-Y, normal} at each vertex
PointData<std::array<Vector3, 3>> knownFrames(*cloud);
PointPositionFrameGeometrygeom(*cloud, positions, knownNormals);
// we can now use this just like a `PointPositionGeometry` as above
```

`PointPositionFrameGeometry::PointPositionFrameGeometry(PointCloud& cloud, const PointData<Vector3>& positions, const PointData<std::array<Vector3, 3>>& frames)`

Constructs a new point position geometry with specified normals.

The given tangent bases and normals will be copied to the `geom.normals`

and `geom.tangentBasis`

fields.