Source code for geomfum.shape._base
"""Base shape."""
import abc
import logging
import gsops.backend as gs
from geomfum.operator import Gradient, Laplacian
[docs]
class Shape(abc.ABC):
"""Abstract base class for geometric shapes with differential operators.
Parameters
----------
is_mesh : bool
Whether the shape is a mesh (True) or point cloud (False).
"""
def __init__(self, is_mesh):
self.is_mesh = is_mesh
self._basis = None
self.laplacian = Laplacian(self)
self.gradient = Gradient(self)
self.landmark_indices = None
[docs]
def equip_with_operator(self, name, Operator, allow_overwrite=True, **kwargs):
"""Equip shape with a differential or geometric operator.
Parameters
----------
name : str
Attribute name for the operator.
Operator : class
Operator class to instantiate.
allow_overwrite : bool, optional
Whether to allow overwriting existing attributes (default: True).
**kwargs
Additional arguments passed to the Operator constructor.
Returns
-------
self : Shape
The shape instance for method chaining.
"""
name_exists = hasattr(self, name)
if name_exists:
if allow_overwrite:
logging.warning(f"Overriding {name}.")
else:
raise ValueError(f"{name} already exists")
operator = Operator(self, **kwargs)
setattr(self, name, operator)
return self
@property
def basis(self):
"""Function basis associated with the shape.
Returns
-------
basis : Basis
Basis.
"""
if self._basis is None:
return self.laplacian.basis
return self._basis
[docs]
def set_basis(self, basis):
"""Set function basis associated with the shape.
Parameters
----------
basis : Basis
Basis.
"""
self._basis = basis
[docs]
def set_landmarks(self, landmark_indices, append=False):
"""Set landmarks points on the shape.
Parameters
----------
landmark_indices : array-like, shape=[n_landmarks]
Landmarks.
append : bool
Whether to append landmarks to already-existing ones.
"""
if append:
self.landmark_indices = gs.stack(self.landmark_indices, landmark_indices)
else:
self.landmark_indices = landmark_indices
return self