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
use crate::Scalar;
use serde::{Deserialize, Serialize};
use std::{num::ParseFloatError, ops::Range, str::FromStr};

/// Point separation source.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum PointsSeparation {
    /// Each point has constant point separation.
    Constant(Scalar),
    /// Each point has local point separation that depends on the steepness value.
    /// When steepness is in range from 0 to 1, then steepness 0 maps to max and 1 maps to min.
    /// `(min, max)`
    SteepnessMapping(Scalar, Scalar),
}

impl PointsSeparation {
    /// Returns maximum of possible values.
    pub fn maximum(&self) -> Scalar {
        match self {
            Self::Constant(v) => *v,
            Self::SteepnessMapping(_, v) => *v,
        }
    }
}

impl From<Scalar> for PointsSeparation {
    fn from(value: Scalar) -> Self {
        Self::Constant(value)
    }
}

impl From<(Scalar, Scalar)> for PointsSeparation {
    fn from(value: (Scalar, Scalar)) -> Self {
        Self::SteepnessMapping(value.0, value.1)
    }
}

impl From<[Scalar; 2]> for PointsSeparation {
    fn from(value: [Scalar; 2]) -> Self {
        Self::SteepnessMapping(value[0], value[1])
    }
}

impl From<Range<Scalar>> for PointsSeparation {
    fn from(value: Range<Scalar>) -> Self {
        Self::SteepnessMapping(value.start, value.end)
    }
}

impl FromStr for PointsSeparation {
    type Err = ParseFloatError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some(found) = s.find("..") {
            let f = &s[..found];
            let t = &s[(found + 2)..];
            Ok(Self::SteepnessMapping(
                f.parse::<Scalar>()?,
                t.parse::<Scalar>()?,
            ))
        } else {
            Ok(Self::Constant(s.parse::<Scalar>()?))
        }
    }
}

impl ToString for PointsSeparation {
    fn to_string(&self) -> String {
        match self {
            Self::Constant(v) => v.to_string(),
            Self::SteepnessMapping(f, t) => format!("{}..{}", f, t),
        }
    }
}

/// Settings of density mesh generation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct GenerateDensityMeshSettings {
    /// Minimal points separation.
    #[serde(default = "GenerateDensityMeshSettings::default_points_separation")]
    pub points_separation: PointsSeparation,
    /// Minimal visibility treshold.
    #[serde(default = "GenerateDensityMeshSettings::default_visibility_threshold")]
    pub visibility_threshold: Scalar,
    /// Minimal steepness treshold.
    #[serde(default = "GenerateDensityMeshSettings::default_steepness_threshold")]
    pub steepness_threshold: Scalar,
    /// Limit of iterations when cannot find next available point.
    #[serde(default = "GenerateDensityMeshSettings::default_max_iterations")]
    pub max_iterations: usize,
    /// Optional extrude size.
    #[serde(default)]
    pub extrude_size: Option<Scalar>,
    #[serde(default)]
    pub is_chunk: bool,
    #[serde(default)]
    pub keep_invisible_triangles: bool,
}

impl Default for GenerateDensityMeshSettings {
    fn default() -> Self {
        Self {
            points_separation: Self::default_points_separation(),
            visibility_threshold: Self::default_visibility_threshold(),
            steepness_threshold: Self::default_steepness_threshold(),
            max_iterations: Self::default_max_iterations(),
            extrude_size: None,
            is_chunk: false,
            keep_invisible_triangles: false,
        }
    }
}

impl GenerateDensityMeshSettings {
    fn default_points_separation() -> PointsSeparation {
        PointsSeparation::Constant(10.0)
    }

    fn default_visibility_threshold() -> Scalar {
        0.01
    }

    fn default_steepness_threshold() -> Scalar {
        0.01
    }

    fn default_max_iterations() -> usize {
        32
    }
}