pub struct DensitySet {
pub characters: Vec<char>,
pub name: String,
}Expand description
Character density set for intensity-based rendering
Maps intensity values [0.0, 1.0] to characters ordered from sparse (low intensity) to dense (high intensity). Provides smooth gradient effects for ASCII-art style visualizations.
§Algorithm
The mapping algorithm uses linear interpolation:
- Clamp intensity to [0.0, 1.0] range
- Calculate index:
round(intensity * (length - 1)) - Return character at calculated index
This ensures:
- Intensity 0.0 always maps to first character (sparsest)
- Intensity 1.0 always maps to last character (densest)
- Intermediate values distribute linearly across character array
§Examples
use dotmax::density::DensitySet;
// Create custom density set
let density = DensitySet::new(
"Custom".to_string(),
vec![' ', '.', ':', '#', '@']
).unwrap();
// Map intensity values
assert_eq!(density.map(0.0), ' '); // First character
assert_eq!(density.map(0.5), ':'); // Middle character
assert_eq!(density.map(1.0), '@'); // Last character
// Out-of-range intensities are clamped
assert_eq!(density.map(-0.5), ' '); // Clamped to 0.0
assert_eq!(density.map(1.5), '@'); // Clamped to 1.0Fields§
§characters: Vec<char>Characters ordered from sparse (low intensity) to dense (high intensity)
name: StringDescriptive name for this density set
Implementations§
Source§impl DensitySet
impl DensitySet
Sourcepub fn new(name: String, characters: Vec<char>) -> Result<Self, DotmaxError>
pub fn new(name: String, characters: Vec<char>) -> Result<Self, DotmaxError>
Create custom density set with validation
Creates a new density set from a character array. Characters must be ordered from sparse (low visual density) to dense (high visual density).
§Arguments
name: Descriptive name for the density setcharacters: Character array ordered sparse to dense
§Validation Rules
- Character list must not be empty (at least 1 character required)
- Character list must not exceed 256 characters (performance limit)
- No validation of character ordering (user responsibility)
§Errors
Returns DotmaxError::EmptyDensitySet if characters is empty.
Returns DotmaxError::TooManyCharacters if characters.len() > 256.
§Examples
use dotmax::density::DensitySet;
// Valid: Create custom density set
let density = DensitySet::new(
"Emoji".to_string(),
vec!['🌑', '🌒', '🌓', '🌔', '🌕']
).unwrap();
assert_eq!(density.characters.len(), 5);
// Error: Empty character list
let result = DensitySet::new("Empty".to_string(), vec![]);
assert!(result.is_err());
// Error: Too many characters (>256)
let too_many: Vec<char> = (0..300).map(|i| (i as u8) as char).collect();
let result = DensitySet::new("TooMany".to_string(), too_many);
assert!(result.is_err());Sourcepub fn map(&self, intensity: f32) -> char
pub fn map(&self, intensity: f32) -> char
Map intensity value [0.0, 1.0] to character
Maps a floating-point intensity value to a character from the density set using linear interpolation. Intensity values are clamped to [0.0, 1.0] range, so out-of-range values are handled gracefully.
§Algorithm
- Clamp intensity:
clamped = intensity.clamp(0.0, 1.0) - Calculate index:
index = round(clamped * (len - 1)) - Return:
characters[index]
§Arguments
intensity: Intensity value, ideally in [0.0, 1.0] range- 0.0 = darkest (first character)
- 1.0 = brightest (last character)
- Out-of-range values are clamped
§Examples
use dotmax::density::DensitySet;
let density = DensitySet::simple();
// Boundary values
assert_eq!(density.map(0.0), ' '); // First character (sparsest)
assert_eq!(density.map(1.0), '@'); // Last character (densest)
// Middle value
let mid_char = density.map(0.5);
assert!(mid_char == '+' || mid_char == '*'); // Approximate middle
// Out-of-range values are clamped
assert_eq!(density.map(-0.5), ' '); // Clamped to 0.0 → first char
assert_eq!(density.map(1.5), '@'); // Clamped to 1.0 → last char
assert_eq!(density.map(f32::NAN), ' '); // NaN clamped to 0.0Sourcepub fn ascii() -> Self
pub fn ascii() -> Self
Create predefined ASCII density set (69 characters)
Returns a density set with the full ASCII gradient, providing maximum smoothness for detailed visualizations. Works on all terminals with 7-bit ASCII support.
§Examples
use dotmax::density::DensitySet;
let density = DensitySet::ascii();
assert_eq!(density.name, "ASCII");
assert_eq!(density.characters.len(), 69);Sourcepub fn simple() -> Self
pub fn simple() -> Self
Create predefined simple density set (10 characters)
Returns a density set with a simple 10-character gradient, ideal for quick prototypes and minimalist visualizations.
§Examples
use dotmax::density::DensitySet;
let density = DensitySet::simple();
assert_eq!(density.name, "Simple");
assert_eq!(density.characters.len(), 10);Sourcepub fn blocks() -> Self
pub fn blocks() -> Self
Create predefined Unicode blocks density set (5 characters)
Returns a density set using Unicode block drawing characters for smooth gradients. Requires modern terminal with Unicode support.
§Examples
use dotmax::density::DensitySet;
let density = DensitySet::blocks();
assert_eq!(density.name, "Blocks");
assert_eq!(density.characters.len(), 5);Sourcepub fn braille() -> Self
pub fn braille() -> Self
Create predefined braille density set (9 characters)
Returns a density set using braille Unicode characters for density progression. Unique to dotmax, combines density rendering with braille theme.
§Examples
use dotmax::density::DensitySet;
let density = DensitySet::braille();
assert_eq!(density.name, "Braille");
assert_eq!(density.characters.len(), 9);Trait Implementations§
Source§impl Clone for DensitySet
impl Clone for DensitySet
Auto Trait Implementations§
impl Freeze for DensitySet
impl RefUnwindSafe for DensitySet
impl Send for DensitySet
impl Sync for DensitySet
impl Unpin for DensitySet
impl UnsafeUnpin for DensitySet
impl UnwindSafe for DensitySet
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more