skshapes.PolyData
- class skshapes.PolyData(points, *, edges=None, triangles=None, point_densities=None, device=None, landmarks=None, control_points=None, stiff_edges=None, point_data=None, edge_data=None, triangle_data=None, cache_size=None)
Bases:
polydata_type
A polygonal shape that is composed of points, edges and/or triangles.
A
PolyData
object can be created from:Points, edges and triangles as torch.Tensors, numpy.arrays, lists or tuples of numbers.
A path to a file containing a mesh, in a format that is accepted by pyvista.read.
A pyvista.PolyData object.
A vedo.Mesh object.
Warning
Internally, points are stored as float32 torch Tensors while indices for edges and triangles are stored as int64 torch Tensors. If you provide numpy arrays, lists or tuples, they will be converted to torch Tensors with the correct dtype. Since float32 precision corresponds to scientific notation with about 7 significant decimal digits, you may run into issues if you provide data that is centered far away from the origin. For instance, a sphere of radius 1 and centered at (1e6, 1e6, 1e6) will not be represented accurately. In such cases, we recommend centering the data around the origin before creating the
PolyData
object.As a general rule, scikit-shapes accepts data in a wide range of formats but always outputs torch Tensors with float32 precision for point coordinates and int64 precision for indices. This design choice is motivated by a requirement for consistency (the output type of our methods should not surprise downstream functions) and support for both GPU computing and automatic differentiation (which are not supported by NumPy).
Main features:
Custom scalar- or vector-valued signals on a
PolyData
can be stored in the three attributespoint_data
,edge_data
andtriangle_data
that behave as dictionaries of torch Tensors.Landmarks or “keypoints” can also be defined on the shape, typically via a list of point indices. If
landmarks
is a sparse tensor of shape(n_landmarks, n_points)
, each row defines a landmark in barycentric coordinates. This allows us to define landmarks in a continuous space (e.g. on a triangle or an edge) instead of being constrained to the vertices of the shape.For visualization purposes, a
PolyData
can be converted to a pyvista.PolyData or a vedo.Mesh using theto_pyvista()
andto_vedo()
methods.The
save()
method lets you save shape data to any file whose format is supported by PyVista (.ply, .stl, .vtk…).
- Parameters:
points (
Float32[Tensor, '_ 2']
|Float32[Tensor, '_ 3']
|Mesh
|PolyData
|Path
|str
) –The vertices of the shape, usually given as a
(n_points, 3)
torch Tensor of xyz coordinates for 3D data or as a(n_points, 2)
torch Tensor of xy coordinates for 2D data. This first argument can also be a vedo.Mesh, a pyvista.PolyData or a path to a file, in which case the edges and triangles are automatically inferred.edges (
Int64[Tensor, '_ 2']
|None
) – The edges of the shape, understood as a set of non-oriented curves or as a wireframe mesh. The edges are encoded as a(n_points, 2)
torch Tensor of integer values. Each row[a, b]
corresponds to a non-oriented edge between pointsa
andb
. Iftriangles
is not None, the edges will be automatically derived from it and this argument will be ignored.triangles (
Int64[Tensor, '_ 3']
|None
) – The triangles of the shape, understood as a surface mesh. The triangles are encoded as a(n_triangles, 3)
torch Tensor of integer values. Each row[a, b, c]
corresponds to a triangle with verticesa
,b
andc
. Ifedges
andtriangles
are both None, the shape is understood as a point cloud.point_densities (
Float32[Tensor, 'n_points']
|None
) – The densities of the points, which act as a multiplier to compute masses inpoint_masses
. For point clouds (with each point having a mass of 1 by default), point densities exactly correspond to point masses. For wireframes, point densities correspond to multipliers on the lengths of the edges. For triangle meshes, point densities correspond to multipliers on the areas of the triangles and can be understood as local thicknesses.device (
str
|device
|None
) – The device on which the shape is stored (e.g."cpu"
or"cuda"
). If None it is inferred from the points.landmarks (
Union
[Tensor
,Int[Tensor, '_']
,Int[ndarray, '_']
,list
[int
],None
]) – The landmarks of the shape.control_points (
polydata_type
|None
) – The control points of the shape.stiff_edges (
Int64[Tensor, '_ 2']
|None
) – The stiff edges structure of the shape, useful for as_isometric_as_possiblepoint_data (
DataAttributes
|None
) – The point data of the shape.edge_data (
DataAttributes
|None
) – The edge data of the shape.triangle_data (
DataAttributes
|None
) – The triangle data of the shape.cache_size (
int
|None
) – Size of the cache for memoized properties. Defaults to None (= no cache limit). Use a smaller value if you intend to e.g. compute point curvatures at many different scales.
Examples
import skshapes as sks shape = sks.PolyData( points=[[0, 0], [1, 0], [0, 1], [1, 1]], triangles=[[0, 1, 2], [1, 2, 3]] ) print(shape.points)
tensor([[0., 0.], [1., 0.], [0., 1.], [1., 1.]])
print(shape.edges)
tensor([[0, 1], [0, 2], [1, 2], [1, 3], [2, 3]])
print(shape.triangles)
tensor([[0, 1, 2], [1, 2, 3]])
Please also check the gallery.
- __init__(points, *, edges=None, triangles=None, point_densities=None, device=None, landmarks=None, control_points=None, stiff_edges=None, point_data=None, edge_data=None, triangle_data=None, cache_size=None)
Methods
__init__
(points, *[, edges, triangles, ...])add_landmarks
(indices)Add vertices landmarks to the shape.
bounding_grid
([N, offset])Bounding grid of the shape.
Reload all cached properties.
copy
()Copy the shape.
edge_lengths
edge_midpoints
edge_points
k_ring_graph
([k, verbose])Computes the k-ring graph of the shape.
knn_graph
([k, include_edges])Returns the k-nearest neighbors edges of a shape.
mesh_convolution
([weight_by_length])Convolution kernel on a triangle mesh or a wireframe PolyData.
normalize
([inplace])Normalize the shape.
plot
([backend])Displays the shape, typically using a PyVista interactive window.
point_convolution
(*[, kernel, scale, ...])Convolution kernel on a PolyData.
point_curvature_colors
(**kwargs)point_curvedness
(**kwargs)Point-wise curvedness, estimated at a given scale.
point_frames
(*[, scale])point_masses
point_mean_gauss_curvatures
(*[, scale, ...])Point-wise mean and gauss curvatures.
point_moments
([method])Compute the local moments of a point cloud.
point_neighborhoods
(*[, method, scale, ...])Blablabla.
point_normals
(**kwargs)Compute a smooth field of normals at the vertices of a mesh.
point_principal_curvatures
(**kwargs)Point-wise principal curvatures.
point_quadratic_coefficients
(*[, scale])Point-wise principal curvatures.
point_quadratic_fits
(*[, scale])point_shape_indices
(**kwargs)Point-wise shape index, estimated at a given scale.
resample
(*[, n_points, ratio, scale, ...])Resample the shape with a different number of vertices.
save
(filename)Save the shape to a file.
to
(device)Copy the shape onto a given device.
to_point_cloud
()to_vedo
()Convert the shape to a weighted point cloud.
triangle_area_normals
triangle_areas
triangle_centroids
triangle_normals
triangle_points
Attributes
Control points of the shape.
Device getter.
Dimension of the shape getter.
Edge data getter.
Edges getter.
Check if the shape is a point cloud.
Check if the shape has triangle connectivity.
Check if the shape has edge connectivity.
Indices of the landmarks.
Landmarks in spatial coordinates.
Landmarks in 3D coordinates.
Get the landmarks of the shape.
Mean point of the shape.
Number of edges getter.
Return the number of landmarks.
Number of points getter.
Number of triangles getter.
Point data getter.
The density of each point of the shape.
Points getter.
Radius of the shape.
Standard deviation of the shape.
Stiff edges getter
Triangle data getter.
Triangles getter.
- add_landmarks(indices)
Add vertices landmarks to the shape.
- Parameters:
indices (
Int[Tensor, '_']
|Int[ndarray, '_']
|list
[int
] |int
) – The indices of the vertices to add to the landmarks.- Return type:
None
- bounding_grid(N=10, offset=0.05)
Bounding grid of the shape.
Compute a bounding grid of the shape. The grid is a PolyData with points and edges representing a regular grid enclosing the shape.
- Parameters:
N (
int
) – The number of points on each axis of the grid.offset (
float
|int
) – The offset of the grid with respect to the shape. If offset=0, the grid is exactly the bounding box of the shape. If offset=1, the grid is the bounding box of the shape dilated by a factor 2.
- Returns:
The bounding grid of the shape.
- Return type:
- cache_clear()
Reload all cached properties.
- property control_points: polydata_type | None
Control points of the shape.
- copy()
Copy the shape.
- Returns:
The copy of the shape.
- Return type:
Examples
import skshapes as sks a = sks.Sphere() b = a.copy() b.points[1, :] = 7 print("Original:") print(a.points[0:4, :]) print("Edited copy:") print(b.points[0:4, :])
Original: tensor([[ 0.0000, 0.0000, 0.5000], [ 0.0000, 0.0000, -0.5000], [ 0.0541, 0.0000, 0.4971], [ 0.1075, 0.0000, 0.4883]]) Edited copy: tensor([[0.0000, 0.0000, 0.5000], [7.0000, 7.0000, 7.0000], [0.0541, 0.0000, 0.4971], [0.1075, 0.0000, 0.4883]])
- property device: device
Device getter.
- property dim: int
Dimension of the shape getter.
- property edge_data: DataAttributes
Edge data getter.
- property edges: Int64[Tensor, '_ 2'] | None
Edges getter.
- Returns:
The edges of the shape. If the shape is a triangle mesh, the edges are computed from the triangles. If the shape is not a triangle mesh, the edges are directly returned. If the shape is a point cloud without explicit topology information, returns None.
- Return type:
Optional[Edges]
- property is_point_cloud: bool
Check if the shape is a point cloud.
- property is_triangle_mesh: bool
Check if the shape has triangle connectivity.
- property is_wireframe: bool
Check if the shape has edge connectivity.
- k_ring_graph(k=2, verbose=False)
Computes the k-ring graph of the shape.
The k-ring graph is the graph where each vertex is connected to its k-neighbors, where the neighborhoods are defined by the edges.
- Parameters:
k (
int
) – the size of the neighborhood, by default 2optional – the size of the neighborhood, by default 2
verbose (
bool
) – whether or not display information about the remaining number of stepsoptional – whether or not display information about the remaining number of steps
- Return type:
Int64[Tensor, '_ 2']
- Returns:
The k-ring neighbors edges.
- knn_graph(k=2, include_edges=False)
Returns the k-nearest neighbors edges of a shape.
- Parameters:
shape – The shape to process.
k (
int
) – The number of neighbors.include_edges (
bool
) – If True, the edges of the shape are concatenated with the k-nearest neighbors edges.
- Returns:
The k-nearest neighbors edges.
- Return type:
Edges
- property landmark_indices: Int64[Tensor, '*_'] | None
Indices of the landmarks.
- Raises:
ValueError – If the landmarks are not indices (there are defined in barycentric coordinates).
- Returns:
The indices of the landmarks. None if no landmarks are defined.
- Return type:
Optional[IntTensor]
- property landmark_points: Float32[Tensor, '_ 2'] | Float32[Tensor, '_ 3'] | None
Landmarks in spatial coordinates.
- property landmark_points_3D: Float32[Tensor, '_ 2'] | Float32[Tensor, '_ 3'] | None
Landmarks in 3D coordinates.
If self.dim == 3, it is equivalent to landmark_points. Otherwise, if self.dim == 2, it returns the landmarks with a third coordinate set to 0.
- Returns:
The landmarks in 3D coordinates.
- Return type:
Points
- property landmarks: is_sparse]] | None
Get the landmarks of the shape.
The format is a sparse tensor of shape (n_landmarks, n_points), each line is a landmark in barycentric coordinates. If you want to get the landmarks in 3D coordinates, use the landmark_points property. If you want to get the landmarks as a list of indices, use the landmark_indices property.
If no landmarks are defined, returns None.
- property mean_point: Float32[Tensor, '_ 2'] | Float32[Tensor, '_ 3']
Mean point of the shape.
Return the mean point as a (N_batch, 3) tensor.
- mesh_convolution(weight_by_length=False)
Convolution kernel on a triangle mesh or a wireframe PolyData.
- Parameters:
weight_by_length (
bool
) – If True, the convolution kernel is weighted by the length of the edges.- Raises:
AttributeError – If the PolyData has no edges.
- Returns:
A (N, N) convolution kernel.
- Return type:
- property n_edges: int
Number of edges getter.
- property n_landmarks: int
Return the number of landmarks.
- property n_points: int
Number of points getter.
- property n_triangles: int
Number of triangles getter.
- normalize(inplace=False)
Normalize the shape.
Center the shape at the origin and scale it so that the standard deviation of the points is 1.
- Returns:
The normalized shape.
- Return type:
- plot(backend='pyvista', **kwargs)
Displays the shape, typically using a PyVista interactive window.
Available backends are
"pyvista"
and"vedo"
. See the documentation of the corresponding plot methods for possible arguments:- Parameters:
backend (
Literal
['pyvista'
,'vedo'
]) – Which backend to use for plotting.- Return type:
None
- point_convolution(*, kernel='gaussian', scale=None, window=None, cutoff=None, geodesic=False, normalize=False, dtype=None, target=None)
Convolution kernel on a PolyData.
Creates a convolution kernel on a PolyData as a (N, N) linear operatorif no target is provided, or as a (M, N) linear operator if a target is provided.
- Parameters:
kernel (
Literal
['uniform'
,'gaussian'
]) – The kernel to use.scale (
int
|float
|None
) – The scale of the kernel.window (
Literal
[None
,'ball'
,'knn'
,'spectral'
]) – The type of window to use.cutoff (
int
|float
|None
) – The cutoff value for the window.geodesic (
bool
) – Whether to use geodesic distances.normalize (
bool
) – Whether to normalize the kernel.dtype (
Optional
[Literal
['float'
,'double'
]]) – The data type of the kernel.target (
polydata_type
|None
) – The target PolyData.
- Returns:
A (N, N) or (M, N) convolution kernel.
- Return type:
- point_curvedness(**kwargs)
Point-wise curvedness, estimated at a given scale.
For reference, see: “Surface shape and curvature scales”, Koenderink and van Doorn, 1992.
- Return type:
Float32[Tensor, '_']
- property point_data: DataAttributes
Point data getter.
- property point_densities: Float32[Tensor, 'n_points']
The density of each point of the shape.
The densities of the points act as a multiplier to compute masses in
point_masses
. For point clouds (with each point having a mass of 1 by default), point densities exactly correspond to point masses. For wireframes, point densities correspond to multipliers on the lengths of the edges. For triangle meshes, point densities correspond to multipliers on the areas of the triangles and can be understood as local thicknesses.
- point_mean_gauss_curvatures(*, scale=None, method='varifold', mean_only=False, **kwargs)
Point-wise mean and gauss curvatures.
- Return type:
MeanGaussCurvatures
- point_moments(method='cosine', **kwargs)
Compute the local moments of a point cloud.
- Return type:
- point_neighborhoods(*, method='auto', scale=None, n_neighbors=None, n_normalization_iterations=None, smoothing_method='auto', laplacian_method='auto')
Blablabla.
- point_normals(**kwargs)
Compute a smooth field of normals at the vertices of a mesh.
Please refer to this example for an illustration of the difference between parameter values.
- Parameters:
kwargs – These arguments will be passed to
point_neighborhoods()
in order to create a neighborhood structure.- Returns:
A
(n_points, 3)
tensor of normal vectors at the vertices of the mesh.- Return type:
Points
Examples
import skshapes as sks mesh = sks.Sphere() raw_normals = mesh.point_normals() smooth_normals = mesh.point_normals( method="gaussian kernel", scale=0.3, ) print(mesh.points.shape, raw_normals.shape, smooth_normals.shape)
torch.Size([842, 3]) torch.Size([842, 3]) torch.Size([842, 3])
- point_principal_curvatures(**kwargs)
Point-wise principal curvatures.
- Return type:
PrincipalCurvatures
- point_quadratic_coefficients(*, scale=None, **kwargs)
Point-wise principal curvatures.
- Return type:
QuadraticCoefficients
- point_shape_indices(**kwargs)
Point-wise shape index, estimated at a given scale.
For reference, see: “Surface shape and curvature scales”, Koenderink and van Doorn, 1992.
- Return type:
Float32[Tensor, '_']
- property points: Float32[Tensor, '_ 2'] | Float32[Tensor, '_ 3']
Points getter.
- property radius: Float32[Tensor, '_']
Radius of the shape.
Returns the radius of the smallest sphere, centered around the mean point, that contains the shape.
- resample(*, n_points=None, ratio=None, scale=None, method='auto', strict=True)
Resample the shape with a different number of vertices.
Warning
Supsampling has not been implemented yet. Currently, we only support decimation.
To handle multiple scales at once, please consider using the
Multiscale
class.- Parameters:
n_points (
int
|None
) – The number of points to keep in the output shape.ratio (
int
|float
|None
) – The ratio of points to keep in the output shape. A ratio of 1.0 keeps all the points, while a ratio of 0.1 keeps 10% of the points.scale (
int
|float
|None
) – The typical distance between vertices in the output shape.method (
Literal
['auto'
]) – The method to use for resampling. Currently, only “auto” is supported. It corresponds to using quadratic decimation on a triangle surface mesh.strict (
bool
) – If False, the decimation may run faster but with a value of n_points that is slightly different from the requested value.
- Raises:
InputStructureError – If both target_reduction and n_points are provided. If none of target_reduction and n_points are provided.
- Returns:
The decimated shape.
- Return type:
Examples
import skshapes as sks shape = sks.Sphere() lowres = shape.resample(ratio=0.1) print(f"from {shape.n_points} to {lowres.n_points} points")
from 842 to 84 points
lowres = shape.resample(n_points=100) print(f"from {shape.n_points} to {lowres.n_points} points")
from 842 to 100 points
lowres = shape.resample(n_points=100, strict=False) print(f"from {shape.n_points} to {lowres.n_points} points")
from 842 to 101 points
- save(filename)
Save the shape to a file.
Format accepted by PyVista are supported (.ply, .stl, .vtk) see: https://github.com/pyvista/pyvista/blob/release/0.40/pyvista/core/pointset.py#L439-L1283 # noqa: E501
- Parameters:
filename (
Path
|str
) – The path where to save the shape.- Return type:
None
- property standard_deviation: Float32[Tensor, '_']
Standard deviation of the shape.
Returns the standard deviation (radius) of the shape as a (N_batch,) tensor.
- property stiff_edges: Int64[Tensor, '_ 2'] | None
Stiff edges getter
- to_pyvista()
Converts the shape to a pyvista.PolyData object.
- Returns:
The shape as a pyvista.PolyData object.
- Return type:
pyvista.PolyData
Examples
import skshapes as sks shape = sks.Sphere() print(shape.to_pyvista())
PolyData (0x7f9b96ab0e80) N Cells: 1680 N Points: 842 N Strips: 0 X Bounds: -4.993e-01, 4.993e-01 Y Bounds: -4.965e-01, 4.965e-01 Z Bounds: -5.000e-01, 5.000e-01 N Arrays: 0
- to_vedo()
Converts the shape to a vedo.Mesh object.
- Returns:
The shape as a vedo.Mesh object.
- Return type:
vedo.Mesh
Examples
import skshapes as sks shape = sks.Sphere() print(shape.to_vedo())
vedo.mesh.Mesh at (0x30e7f0e0) name : Mesh elements : vertices=842 polygons=1,680 lines=0 position : (0, 0, 0) scaling : (1.00000, 1.00000, 1.00000) size : average=0.500000, diagonal=1.72721 center of mass: (0, 0, 0) bounds : x=(-0.499, 0.499), y=(-0.497, 0.497), z=(-0.500, 0.500)
- to_weighted_points()
Convert the shape to a weighted point cloud.
- Return type:
tuple
[Float32[Tensor, '_ 2']
|Float32[Tensor, '_ 3']
,Float32[Tensor, '_']
]- Returns:
points – The points of the weighted point cloud.
weights – The weights of the weighted point cloud.
- property triangle_data: DataAttributes
Triangle data getter.
- property triangles: Int64[Tensor, '_ 3'] | None
Triangles getter.