1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 * // Copyright (c) 2021 Feng Yang
 * //
 * // I am making my contributions/submissions to this project solely in my
 * // personal capacity and am not conveying any rights to any intellectual
 * // property of any third parties.
 */

use crate::vector2::Vector2D;
use crate::field2::Field2;
use crate::vector_field2::VectorField2;
use std::sync::{RwLock, Arc};

/// # 2-D vector field with custom field function.
pub struct CustomVectorField2 {
    _custom_function: fn(&Vector2D) -> Vector2D,
    _custom_divergence_function: Option<fn(&Vector2D) -> f64>,
    _custom_curl_function: Option<fn(&Vector2D) -> f64>,
    _resolution: f64,
}

impl CustomVectorField2 {
    ///
    /// \brief Constructs a field with given function.
    ///
    /// This constructor creates a field with user-provided function object.
    /// To compute derivatives, such as gradient and Laplacian, finite
    /// differencing is used. Thus, the differencing resolution also can be
    /// provided as the last parameter.
    ///
    pub fn new(custom_function: fn(&Vector2D) -> Vector2D,
               custom_divergence_function: Option<fn(&Vector2D) -> f64>,
               custom_curl_function: Option<fn(&Vector2D) -> f64>,
               derivative_resolution: Option<f64>) -> CustomVectorField2 {
        return CustomVectorField2 {
            _custom_function: custom_function,
            _custom_divergence_function: custom_divergence_function,
            _custom_curl_function: custom_curl_function,
            _resolution: derivative_resolution.unwrap_or(1.0e-3),
        };
    }

    /// Returns builder fox CustomVectorField2.
    pub fn builder() -> Builder {
        return Builder::new();
    }
}

impl Field2 for CustomVectorField2 {}

impl VectorField2 for CustomVectorField2 {
    fn sample(&self, x: &Vector2D) -> Vector2D {
        return (self._custom_function)(x);
    }

    fn divergence(&self, x: &Vector2D) -> f64 {
        return match self._custom_divergence_function {
            None => {
                let left = (self._custom_function)(&(*x - Vector2D::new(0.5 * self._resolution, 0.0))).x;
                let right = (self._custom_function)(&(*x + Vector2D::new(0.5 * self._resolution, 0.0))).x;
                let bottom = (self._custom_function)(&(*x - Vector2D::new(0.0, 0.5 * self._resolution))).y;
                let top = (self._custom_function)(&(*x + Vector2D::new(0.0, 0.5 * self._resolution))).y;

                (right - left + top - bottom) / self._resolution
            }
            Some(func) => {
                func(x)
            }
        };
    }

    fn curl(&self, x: &Vector2D) -> f64 {
        match self._custom_curl_function {
            None => {
                let left = (self._custom_function)(&(*x - Vector2D::new(0.5 * self._resolution, 0.0))).y;
                let right = (self._custom_function)(&(*x + Vector2D::new(0.5 * self._resolution, 0.0))).y;
                let bottom = (self._custom_function)(&(*x - Vector2D::new(0.0, 0.5 * self._resolution))).x;
                let top = (self._custom_function)(&(*x + Vector2D::new(0.0, 0.5 * self._resolution))).x;

                return (top - bottom - right + left) / self._resolution;
            }
            Some(func) => {
                return func(x);
            }
        }
    }
}

/// Shared pointer type for the CustomVectorField2.
pub type CustomVectorField2Ptr = Arc<RwLock<CustomVectorField2>>;

///
/// # Front-end to create CustomVectorField2 objects step by step.
///
pub struct Builder {
    _custom_function: Option<fn(&Vector2D) -> Vector2D>,
    _custom_divergence_function: Option<fn(&Vector2D) -> f64>,
    _custom_curl_function: Option<fn(&Vector2D) -> f64>,
    _resolution: f64,
}

impl Builder {
    /// Returns builder with field function.
    pub fn with_function(&mut self,
                         func: fn(&Vector2D) -> Vector2D) -> &mut Self {
        self._custom_function = Some(func);
        return self;
    }

    /// Returns builder with divergence function.
    pub fn with_divergence_function(&mut self,
                                    func: fn(&Vector2D) -> f64) -> &mut Self {
        self._custom_divergence_function = Some(func);
        return self;
    }

    /// Returns builder with curl function.
    pub fn with_curl_function(&mut self,
                              func: fn(&Vector2D) -> f64) -> &mut Self {
        self._custom_curl_function = Some(func);
        return self;
    }

    /// Returns builder with derivative resolution.
    pub fn with_derivative_resolution(&mut self, resolution: f64) -> &mut Self {
        self._resolution = resolution;
        return self;
    }

    /// Builds CustomVectorField2.
    pub fn build(&mut self) -> CustomVectorField2 {
        return CustomVectorField2::new(self._custom_function.unwrap(),
                                       self._custom_divergence_function,
                                       self._custom_curl_function,
                                       Some(self._resolution));
    }

    /// Builds shared pointer of CustomVectorField2 instance.
    pub fn make_shared(&mut self) -> CustomVectorField2Ptr {
        return CustomVectorField2Ptr::new(RwLock::new(self.build()));
    }

    /// constructor
    pub fn new() -> Builder {
        return Builder {
            _custom_function: None,
            _custom_divergence_function: None,
            _custom_curl_function: None,
            _resolution: 1.0e-3,
        };
    }
}