1use nalgebra::ComplexField;
22use num_traits::Float;
23use std::ops::Range;
24
25use crate::integrable::ComplexScalar;
26
27pub(crate) trait ContourPiece: Clone {
46 type Input: Clone + std::fmt::Debug;
48
49 type Float;
51
52 fn point(&self, t: Self::Float) -> Self::Input;
56
57 fn derivative(&self, t: Self::Float) -> Self::Input;
62
63 fn length_scale(&self) -> Self::Float;
69
70 fn is_degenerate(&self) -> bool;
72
73 fn split(&self) -> [Self; 2]
78 where
79 Self: Sized;
80}
81
82pub trait SplittableContourPiece: ContourPiece {
83 fn locate_point(&self, point: Self::Input, tolerance: Self::Float) -> Option<Self::Float>;
84 fn split_at(&self, t: Self::Float) -> [Self; 2];
85}
86
87#[derive(Clone, Debug)]
93pub enum ContourSegment<F>
94where
95 F: ComplexScalar,
96{
97 Line(LineSegment<<F as ComplexScalar>::Complex>),
99 CircularArc(CircularArc<F>),
101}
102
103impl<F: ComplexScalar> ContourSegment<F> {
104 pub fn start(&self) -> F::Complex {
105 match self {
106 Self::Line(line) => line.start(),
107 Self::CircularArc(arc) => arc.point(F::zero()),
108 }
109 }
110
111 pub fn end(&self) -> F::Complex {
112 match self {
113 Self::Line(line) => line.end(),
114 Self::CircularArc(arc) => arc.point(F::one()),
115 }
116 }
117
118 pub fn reversed(self) -> Self {
119 match self {
120 Self::Line(line) => Self::Line(line.reversed()),
121 Self::CircularArc(arc) => Self::CircularArc(arc.reversed()),
122 }
123 }
124}
125
126impl<F> ContourPiece for ContourSegment<F>
127where
128 F: ComplexScalar,
129{
130 type Input = F::Complex;
131 type Float = F;
132
133 fn point(&self, t: F) -> Self::Input {
134 match self {
135 Self::Line(piece) => piece.point(t),
136 Self::CircularArc(piece) => piece.point(t),
137 }
138 }
139
140 fn derivative(&self, t: F) -> Self::Input {
141 match self {
142 Self::Line(piece) => piece.derivative(t),
143 Self::CircularArc(piece) => piece.derivative(t),
144 }
145 }
146
147 fn length_scale(&self) -> F {
148 match self {
149 Self::Line(piece) => piece.length_scale(),
150 Self::CircularArc(piece) => piece.length_scale(),
151 }
152 }
153
154 fn is_degenerate(&self) -> bool {
155 match self {
156 Self::Line(piece) => piece.is_degenerate(),
157 Self::CircularArc(piece) => piece.is_degenerate(),
158 }
159 }
160
161 fn split(&self) -> [Self; 2] {
162 match self {
163 Self::Line(piece) => {
164 let [a, b] = piece.split();
165 [Self::Line(a), Self::Line(b)]
166 }
167 Self::CircularArc(piece) => {
168 let [a, b] = piece.split();
169 [Self::CircularArc(a), Self::CircularArc(b)]
170 }
171 }
172 }
173}
174
175#[derive(Debug, Clone, Copy)]
180pub struct LineSegment<I> {
181 start: I,
182 end: I,
183}
184
185impl<I> From<Range<I>> for LineSegment<I> {
186 fn from(range: Range<I>) -> Self {
187 Self {
188 start: range.start,
189 end: range.end,
190 }
191 }
192}
193
194impl<I> LineSegment<I> {
195 pub fn new(start: I, end: I) -> Self {
197 Self::from(start..end)
198 }
199
200 pub fn start(&self) -> I
201 where
202 I: Copy,
203 {
204 self.start
205 }
206
207 pub fn end(&self) -> I
208 where
209 I: Copy,
210 {
211 self.end
212 }
213
214 pub fn reversed(self) -> Self
215 where
216 I: Copy,
217 {
218 Self::new(self.end, self.start)
219 }
220}
221
222impl<I, F> ContourPiece for LineSegment<I>
223where
224 I: ComplexField<RealField = F> + Copy,
225 F: Float,
226{
227 type Float = F;
228 type Input = I;
229
230 fn point(&self, t: Self::Float) -> Self::Input {
231 self.start + (self.end - self.start).scale(t)
232 }
233
234 fn derivative(&self, _t: Self::Float) -> Self::Input {
235 self.end - self.start
236 }
237
238 fn length_scale(&self) -> Self::Float {
239 (self.end - self.start).modulus()
240 }
241
242 fn is_degenerate(&self) -> bool {
243 self.length_scale() == F::zero()
244 }
245
246 fn split(&self) -> [Self; 2] {
247 let half = F::one() / (F::one() + F::one());
248 let mid = self.point(half);
249 [
250 Self {
251 start: self.start,
252 end: mid,
253 },
254 Self {
255 start: mid,
256 end: self.end,
257 },
258 ]
259 }
260}
261
262#[derive(Clone, Copy, Debug)]
275pub struct CircularArc<F: ComplexScalar> {
276 center: F::Complex,
277 radius: F,
278 theta0: F,
279 theta1: F,
280}
281
282impl<F: ComplexScalar> CircularArc<F> {
283 pub fn new(center: F::Complex, radius: F, theta0: F, theta1: F) -> Self {
290 Self {
291 center,
292 radius,
293 theta0,
294 theta1,
295 }
296 }
297
298 fn theta(&self, t: F) -> F
300 where
301 F: Float,
302 {
303 self.theta0 + (self.theta1 - self.theta0) * t
304 }
305
306 pub fn center(&self) -> F::Complex
307 where
308 F::Complex: Copy,
309 {
310 self.center
311 }
312
313 pub fn radius(&self) -> F
314 where
315 F: Copy,
316 {
317 self.radius
318 }
319
320 pub fn reversed(self) -> Self
321 where
322 F: Copy,
323 {
324 Self::new(self.center, self.radius, self.theta1, self.theta0)
325 }
326}
327
328impl<F> ContourPiece for CircularArc<F>
329where
330 F: ComplexScalar,
331{
332 type Input = F::Complex;
333 type Float = F;
334
335 fn point(&self, t: Self::Float) -> Self::Input {
336 let theta = self.theta(t);
337
338 self.center + F::complex(self.radius * theta.cos(), self.radius * theta.sin())
339 }
340
341 fn derivative(&self, t: Self::Float) -> Self::Input {
342 let theta = self.theta(t);
343 let dtheta_dt = self.theta1 - self.theta0;
344
345 F::complex(
346 -self.radius * theta.sin() * dtheta_dt,
347 self.radius * theta.cos() * dtheta_dt,
348 )
349 }
350
351 fn length_scale(&self) -> Self::Float {
352 self.radius * (self.theta1 - self.theta0).abs()
353 }
354
355 fn is_degenerate(&self) -> bool {
356 self.radius == F::zero() || self.theta0 == self.theta1
357 }
358
359 fn split(&self) -> [Self; 2] {
360 let mid = (self.theta0 + self.theta1) / (F::one() + F::one());
361
362 [
363 Self::new(self.center, self.radius, self.theta0, mid),
364 Self::new(self.center, self.radius, mid, self.theta1),
365 ]
366 }
367}
368
369pub enum InfiniteInterval<F> {
370 Whole,
371 From(F),
372 To(F),
373}