"""Abstract base class for floating bodies."""
# Copyright (C) 2017-2025 Matthieu Ancellin
# See LICENSE file at <https://github.com/capytaine/capytaine>
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Literal, List, Union, Tuple
import numpy as np
from capytaine.bodies.dofs import (
add_dofs_labels_to_vector,
add_dofs_labels_to_matrix,
)
[docs]
class AbstractBody(ABC):
"""Abstract base class for FloatingBody and Multibody.
Defines the shared interface that both single bodies and collections
of bodies must implement.
Subclasses must provide the following attributes (either as instance
attributes set in __init__, or as properties/cached_properties):
name: str
mesh
lid_mesh
mesh_including_lid
hull_mask
dofs: dict
mass
center_of_mass
"""
name: str
[docs]
@abstractmethod
def rename(self, name): ...
def __lt__(self, other: AbstractBody) -> bool:
"""Arbitrary order. The point is to sort together the problems involving the same body."""
return self.name < other.name
# --- Dof labelling (identical in both subclasses) ---
[docs]
def add_dofs_labels_to_vector(self, vector):
"""Helper function turning a bare vector into a vector labelled by the name of the dofs of the body,
to be used for instance for the computation of RAO."""
return add_dofs_labels_to_vector(self.dofs.keys(), vector)
[docs]
def add_dofs_labels_to_matrix(self, matrix):
"""Helper function turning a bare matrix into a matrix labelled by the name of the dofs of the body,
to be used for instance for the computation of RAO."""
return add_dofs_labels_to_matrix(self.dofs.keys(), matrix)
# --- Body joining (identical in both subclasses) ---
def __add__(self, body_to_add: AbstractBody) -> AbstractBody:
return self.join_bodies(body_to_add)
[docs]
def join_bodies(*bodies, name=None) -> Multibody: # noqa: F821
from capytaine.bodies.multibodies import Multibody
return Multibody(bodies, name=name)
# --- Abstract methods (different implementations) ---
[docs]
@abstractmethod
def integrate_pressure(self, pressure): ...
[docs]
@abstractmethod
def minimal_computable_wavelength(self): ...
[docs]
@abstractmethod
def first_irregular_frequency_estimate(self, *args, **kwargs): ...
[docs]
@abstractmethod
def compute_hydrostatic_stiffness(self, *, rho=1000.0, g=9.81): ...
[docs]
@abstractmethod
def compute_rigid_body_inertia(self, rho=1000.0): ...
@abstractmethod
def _check_dofs_shape_consistency(self): ...
# --- Geometric transforms ---
[docs]
@abstractmethod
def translated(self, shift, *, name=None) -> AbstractBody: ...
[docs]
def translated_x(self, dx: float, *, name=None) -> AbstractBody:
return self.translated([dx, 0.0, 0.0], name=name)
[docs]
def translated_y(self, dy: float, *, name=None) -> AbstractBody:
return self.translated([0.0, dy, 0.0], name=name)
[docs]
def translated_z(self, dz: float, *, name=None) -> AbstractBody:
return self.translated([0.0, 0.0, dz], name=name)
[docs]
@abstractmethod
def rotated_with_matrix(self, R, *, name=None) -> AbstractBody: ...
[docs]
def rotated_x(self, angle: float, *, name=None) -> AbstractBody:
c, s = np.cos(angle), np.sin(angle)
R = np.array([[1, 0, 0], [0, c, -s], [0, s, c]])
return self.rotated_with_matrix(R, name=name)
[docs]
def rotated_y(self, angle: float, *, name=None) -> AbstractBody:
c, s = np.cos(angle), np.sin(angle)
R = np.array([[c, 0, s], [0, 1, 0], [-s, 0, c]])
return self.rotated_with_matrix(R, name=name)
[docs]
def rotated_z(self, angle: float, *, name=None) -> AbstractBody:
c, s = np.cos(angle), np.sin(angle)
R = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]])
return self.rotated_with_matrix(R, name=name)
[docs]
@abstractmethod
def mirrored(self, plane: Literal['xOz', 'yOz']) -> AbstractBody: ...
[docs]
@abstractmethod
def clipped(self, *, origin, normal, name=None) -> AbstractBody: ...
[docs]
@abstractmethod
def immersed_part(self, free_surface=0.0, *, sea_botton=None, water_depth=None, name=None) -> AbstractBody: ...
[docs]
@abstractmethod
def copy(self, name=None) -> AbstractBody: ...
# --- Display ---
@abstractmethod
def __str__(self): ...
@abstractmethod
def __short_str__(self): ...
def __repr__(self):
return str(self)