use nalgebra::ComplexField;
use num_traits::Float;
use std::ops::Range;
use crate::integrable::ComplexScalar;
pub(crate) trait ContourPiece: Clone {
type Input: Clone + std::fmt::Debug;
type Float;
fn point(&self, t: Self::Float) -> Self::Input;
fn derivative(&self, t: Self::Float) -> Self::Input;
fn length_scale(&self) -> Self::Float;
fn is_degenerate(&self) -> bool;
fn split(&self) -> [Self; 2]
where
Self: Sized;
}
pub trait SplittableContourPiece: ContourPiece {
fn locate_point(&self, point: Self::Input, tolerance: Self::Float) -> Option<Self::Float>;
fn split_at(&self, t: Self::Float) -> [Self; 2];
}
#[derive(Clone, Debug)]
pub enum ContourSegment<F>
where
F: ComplexScalar,
{
Line(LineSegment<<F as ComplexScalar>::Complex>),
CircularArc(CircularArc<F>),
}
impl<F: ComplexScalar> ContourSegment<F> {
pub fn start(&self) -> F::Complex {
match self {
Self::Line(line) => line.start(),
Self::CircularArc(arc) => arc.point(F::zero()),
}
}
pub fn end(&self) -> F::Complex {
match self {
Self::Line(line) => line.end(),
Self::CircularArc(arc) => arc.point(F::one()),
}
}
pub fn reversed(self) -> Self {
match self {
Self::Line(line) => Self::Line(line.reversed()),
Self::CircularArc(arc) => Self::CircularArc(arc.reversed()),
}
}
}
impl<F> ContourPiece for ContourSegment<F>
where
F: ComplexScalar,
{
type Input = F::Complex;
type Float = F;
fn point(&self, t: F) -> Self::Input {
match self {
Self::Line(piece) => piece.point(t),
Self::CircularArc(piece) => piece.point(t),
}
}
fn derivative(&self, t: F) -> Self::Input {
match self {
Self::Line(piece) => piece.derivative(t),
Self::CircularArc(piece) => piece.derivative(t),
}
}
fn length_scale(&self) -> F {
match self {
Self::Line(piece) => piece.length_scale(),
Self::CircularArc(piece) => piece.length_scale(),
}
}
fn is_degenerate(&self) -> bool {
match self {
Self::Line(piece) => piece.is_degenerate(),
Self::CircularArc(piece) => piece.is_degenerate(),
}
}
fn split(&self) -> [Self; 2] {
match self {
Self::Line(piece) => {
let [a, b] = piece.split();
[Self::Line(a), Self::Line(b)]
}
Self::CircularArc(piece) => {
let [a, b] = piece.split();
[Self::CircularArc(a), Self::CircularArc(b)]
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct LineSegment<I> {
start: I,
end: I,
}
impl<I> From<Range<I>> for LineSegment<I> {
fn from(range: Range<I>) -> Self {
Self {
start: range.start,
end: range.end,
}
}
}
impl<I> LineSegment<I> {
pub fn new(start: I, end: I) -> Self {
Self::from(start..end)
}
pub fn start(&self) -> I
where
I: Copy,
{
self.start
}
pub fn end(&self) -> I
where
I: Copy,
{
self.end
}
pub fn reversed(self) -> Self
where
I: Copy,
{
Self::new(self.end, self.start)
}
}
impl<I, F> ContourPiece for LineSegment<I>
where
I: ComplexField<RealField = F> + Copy,
F: Float,
{
type Float = F;
type Input = I;
fn point(&self, t: Self::Float) -> Self::Input {
self.start + (self.end - self.start).scale(t)
}
fn derivative(&self, _t: Self::Float) -> Self::Input {
self.end - self.start
}
fn length_scale(&self) -> Self::Float {
(self.end - self.start).modulus()
}
fn is_degenerate(&self) -> bool {
self.length_scale() == F::zero()
}
fn split(&self) -> [Self; 2] {
let half = F::one() / (F::one() + F::one());
let mid = self.point(half);
[
Self {
start: self.start,
end: mid,
},
Self {
start: mid,
end: self.end,
},
]
}
}
#[derive(Clone, Copy, Debug)]
pub struct CircularArc<F: ComplexScalar> {
center: F::Complex,
radius: F,
theta0: F,
theta1: F,
}
impl<F: ComplexScalar> CircularArc<F> {
pub fn new(center: F::Complex, radius: F, theta0: F, theta1: F) -> Self {
Self {
center,
radius,
theta0,
theta1,
}
}
fn theta(&self, t: F) -> F
where
F: Float,
{
self.theta0 + (self.theta1 - self.theta0) * t
}
pub fn center(&self) -> F::Complex
where
F::Complex: Copy,
{
self.center
}
pub fn radius(&self) -> F
where
F: Copy,
{
self.radius
}
pub fn reversed(self) -> Self
where
F: Copy,
{
Self::new(self.center, self.radius, self.theta1, self.theta0)
}
}
impl<F> ContourPiece for CircularArc<F>
where
F: ComplexScalar,
{
type Input = F::Complex;
type Float = F;
fn point(&self, t: Self::Float) -> Self::Input {
let theta = self.theta(t);
self.center + F::complex(self.radius * theta.cos(), self.radius * theta.sin())
}
fn derivative(&self, t: Self::Float) -> Self::Input {
let theta = self.theta(t);
let dtheta_dt = self.theta1 - self.theta0;
F::complex(
-self.radius * theta.sin() * dtheta_dt,
self.radius * theta.cos() * dtheta_dt,
)
}
fn length_scale(&self) -> Self::Float {
self.radius * (self.theta1 - self.theta0).abs()
}
fn is_degenerate(&self) -> bool {
self.radius == F::zero() || self.theta0 == self.theta1
}
fn split(&self) -> [Self; 2] {
let mid = (self.theta0 + self.theta1) / (F::one() + F::one());
[
Self::new(self.center, self.radius, self.theta0, mid),
Self::new(self.center, self.radius, mid, self.theta1),
]
}
}
pub enum InfiniteInterval<F> {
Whole,
From(F),
To(F),
}