Source code for panel_bie.geometry
"""Geometry protocol and utilities."""
from __future__ import annotations
from typing import Protocol, runtime_checkable
import numpy as np
from numpy.typing import NDArray
[docs]
@runtime_checkable
class Geometry(Protocol):
"""Protocol for boundary geometry discretizations.
Any object providing these attributes is compatible with panel-bie solvers.
The `superellipse.PanelDiscretization` class implements this protocol.
"""
@property
def points(self) -> NDArray[np.floating]:
"""Boundary nodes, shape (N, 2)."""
...
@property
def normals(self) -> NDArray[np.floating]:
"""Outward unit normals, shape (N, 2)."""
...
@property
def weights(self) -> NDArray[np.floating]:
"""Quadrature weights (ds measure), shape (N,)."""
...
@property
def curvature(self) -> NDArray[np.floating]:
"""Signed curvature at each node, shape (N,)."""
...
[docs]
def validate_geometry(geom: Geometry) -> None:
"""Validate geometry object has correct shapes and properties."""
n = geom.points.shape[0]
if geom.points.shape != (n, 2):
raise ValueError(f"points must be (N, 2), got {geom.points.shape}")
if geom.normals.shape != (n, 2):
raise ValueError(f"normals must be (N, 2), got {geom.normals.shape}")
if geom.weights.shape != (n,):
raise ValueError(f"weights must be (N,), got {geom.weights.shape}")
if geom.curvature.shape != (n,):
raise ValueError(f"curvature must be (N,), got {geom.curvature.shape}")
# Check normals are unit vectors
norms = np.linalg.norm(geom.normals, axis=1)
if not np.allclose(norms, 1.0, atol=1e-10):
raise ValueError("normals must be unit vectors")
# Check weights are positive
if not np.all(geom.weights > 0):
raise ValueError("weights must be positive")