mod deform;
mod piece;
pub use deform::IndentSide;
pub(crate) use piece::ContourPiece;
pub use piece::{CircularArc, ContourSegment, LineSegment};
use crate::integrable::ComplexScalar;
use num_traits::FromPrimitive;
#[derive(Clone, Debug)]
pub struct Contour<F: ComplexScalar> {
pieces: Vec<ContourSegment<F>>,
}
impl<F: ComplexScalar> Contour<F> {
pub fn from_pieces(pieces: Vec<ContourSegment<F>>) -> Self {
assert!(!pieces.is_empty());
Self { pieces }
}
pub fn pieces(&self) -> &[ContourSegment<F>] {
&self.pieces
}
pub fn into_pieces(self) -> Vec<ContourSegment<F>> {
self.pieces
}
pub fn reverse(mut self) -> Self {
self.pieces.reverse();
self.pieces = self
.pieces
.into_iter()
.map(ContourSegment::reversed)
.collect();
self
}
pub fn close(mut self) -> Self {
let Some(first) = self.pieces.first().map(ContourSegment::start) else {
return self;
};
let Some(last) = self.pieces.last().map(ContourSegment::end) else {
return self;
};
if first != last {
self.pieces
.push(ContourSegment::Line(LineSegment::new(last, first)));
}
self
}
pub fn with_principal_value(
self,
pole: F::Complex,
radius: F,
side: IndentSide,
tolerance: F,
) -> Self
where
F: ComplexScalar + FromPrimitive,
{
self.indent(pole, radius, side, tolerance)
}
pub fn indent_many(
mut self,
singularities: impl IntoIterator<Item = (F::Complex, F, IndentSide)>,
tolerance: F,
) -> Self
where
F: ComplexScalar + FromPrimitive,
{
for (pole, radius, side) in singularities {
self = self.indent(pole, radius, side, tolerance);
}
self
}
}
impl<F> Contour<F>
where
F: ComplexScalar,
{
pub fn piecewise_linear(points: Vec<F::Complex>) -> Self {
assert!(points.len() >= 2);
let pieces = points
.windows(2)
.map(|pair| ContourSegment::Line(LineSegment::from(pair[0]..pair[1])))
.collect();
Self { pieces }
}
pub fn upper_half_disk_centered(center: F::Complex, radius: F) -> Self
where
F: FromPrimitive,
{
let left = center - F::complex(radius, F::zero());
let right = center + F::complex(radius, F::zero());
Self::from_pieces(vec![
ContourSegment::Line(LineSegment::new(left, right)),
ContourSegment::CircularArc(CircularArc::new(
center,
radius,
F::zero(),
F::from_f64(std::f64::consts::PI).unwrap(),
)),
])
}
pub fn lower_half_disk_centered(center: F::Complex, radius: F) -> Self
where
F: FromPrimitive,
{
let left = center - F::complex(radius, F::zero());
let right = center + F::complex(radius, F::zero());
Self::from_pieces(vec![
ContourSegment::Line(LineSegment::new(left, right)),
ContourSegment::CircularArc(CircularArc::new(
center,
radius,
F::zero(),
-F::from_f64(std::f64::consts::PI).unwrap(),
)),
])
}
pub fn real_axis(radius: F) -> Self
where
F: FromPrimitive,
{
Self::piecewise_linear(vec![
F::complex(-radius, F::zero()),
F::complex(radius, F::zero()),
])
}
pub fn real_axis_offset(radius: F, imaginary_offset: F) -> Self
where
F: FromPrimitive,
{
Self::piecewise_linear(vec![
F::complex(-radius, imaginary_offset),
F::complex(radius, imaginary_offset),
])
}
pub fn upper_half_disk(radius: F) -> Self
where
F: FromPrimitive,
{
Self::upper_half_disk_centered(F::complex(F::zero(), F::zero()), radius)
}
pub fn lower_half_disk(radius: F) -> Self
where
F: FromPrimitive,
{
Self::lower_half_disk_centered(F::complex(F::zero(), F::zero()), radius)
}
pub fn upper_half_disk_offset(radius: F, imaginary_offset: F) -> Self
where
F: FromPrimitive,
{
Self::upper_half_disk_centered(F::complex(F::zero(), imaginary_offset), radius)
}
pub fn lower_half_disk_offset(radius: F, imaginary_offset: F) -> Self
where
F: FromPrimitive,
{
Self::lower_half_disk_centered(F::complex(F::zero(), imaginary_offset), radius)
}
}