vox_geometry_rust 0.1.2

Geometry Tools for Rust
Documentation
/*
 * // 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 std::sync::{RwLock, Arc};
use crate::field2::Field2;
use crate::scalar_field2::ScalarField2;

/// # 2-D scalar field with custom field function.
pub struct CustomScalarField2 {
    _custom_function: fn(&Vector2D) -> f64,
    _custom_gradient_function: Option<fn(&Vector2D) -> Vector2D>,
    _custom_laplacian_function: Option<fn(&Vector2D) -> f64>,
    _resolution: f64,
}

impl CustomScalarField2 {
    ///
    /// \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) -> f64,
               custom_gradient_function: Option<fn(&Vector2D) -> Vector2D>,
               custom_laplacian_function: Option<fn(&Vector2D) -> f64>,
               derivative_resolution: Option<f64>) -> CustomScalarField2 {
        return CustomScalarField2 {
            _custom_function: custom_function,
            _custom_gradient_function: custom_gradient_function,
            _custom_laplacian_function: custom_laplacian_function,
            _resolution: derivative_resolution.unwrap_or(1.0e-3),
        };
    }

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

impl Field2 for CustomScalarField2 {}

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

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

                Vector2D::new(
                    (right - left) / self._resolution,
                    (top - bottom) / self._resolution)
            }
            Some(func) => {
                func(x)
            }
        };
    }

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

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

/// Shared pointer type for the CustomScalarField2.
pub type CustomScalarField2Ptr = Arc<RwLock<CustomScalarField2>>;

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

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

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

    /// Returns builder with curl function.
    pub fn with_laplacian_function(&mut self, func: fn(&Vector2D) -> f64) -> &mut Self {
        self._custom_laplacian_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 CustomScalarField2.
    pub fn build(&mut self) -> CustomScalarField2 {
        return CustomScalarField2::new(self._custom_function.unwrap(),
                                       self._custom_gradient_function,
                                       self._custom_laplacian_function,
                                       Some(self._resolution));
    }

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

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