Source code for digeo.ops.sampling
import numpy as np
import torch
from digeo.mesh import Mesh, MeshBatch, MeshPointBatch
[docs]
def uniform_sampling(mesh: Mesh, n_points: int) -> MeshPointBatch:
"""
Sample points uniformly from the mesh.
Parameters
----------
mesh : Mesh | MeshBatch
The mesh to sample from.
n_points : int
The number of points to sample.
tensor : bool
Whether to use torch tensors for barycentric coordinates.
Returns
-------
MeshPointBatch
The sampled points.
"""
tri = mesh.faces
pos = mesh.vertices
p0 = pos[tri[:, 0]]
p1 = pos[tri[:, 1]]
p2 = pos[tri[:, 2]]
# Compute triangle areas
v0 = p1 - p0
v1 = p2 - p0
cross = torch.cross(v0, v1, dim=1).to(torch.float64)
weights = 0.5 * torch.linalg.norm(cross, axis=1)
if isinstance(mesh, MeshBatch):
faces = []
for k in range(len(mesh.triangle_idx) - 1):
weights_k = weights[mesh.triangle_idx[k] : mesh.triangle_idx[k + 1]]
weights_k /= weights_k.sum()
triangle_id_np = np.random.choice(
len(weights_k), p=weights_k, size=n_points
)
faces.append(
torch.tensor(triangle_id_np, dtype=torch.int32) + mesh.triangle_idx[k]
)
faces = torch.cat(faces, dim=0)
# Generate random uniform barycentric coordinates
r1 = torch.sqrt(torch.rand(n_points * len(mesh), dtype=torch.float32))
r2 = torch.rand(n_points * len(mesh), dtype=torch.float32)
u = 1 - r1
v = r1 * r2
uvs = torch.stack((u, v), dim=1)
return MeshPointBatch(faces=faces, uvs=uvs)
elif isinstance(mesh, Mesh):
weights /= weights.sum()
triangle_id_np = np.random.choice(
len(tri), p=weights.detach().cpu(), size=n_points
)
triangle_id = torch.tensor(triangle_id_np, dtype=torch.int32)
# Generate random uniform barycentric coordinates
r1 = torch.sqrt(torch.rand(n_points, dtype=torch.float32))
r2 = torch.rand(n_points, dtype=torch.float32)
u = 1 - r1
v = r1 * r2
uvs = torch.stack((u, v), dim=1)
return MeshPointBatch(faces=triangle_id, uvs=uvs)
else:
raise TypeError("Input mesh must be of type Mesh or MeshBatch.")