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
//! Optical material.

use crate::{
    data::Table,
    err::Error,
    file::{Build, Load},
    geom::{Emitter, MeshBuilder, Ray},
    math::{Dir3, Pos3},
    ord::{X, Y, Z},
};
use arctk_attr::load;
use std::path::{Path, PathBuf};

/// Ray emission structure.
#[load]
pub enum EmitterBuilder {
    /// Single beam.
    Beam(Pos3, Dir3),
    /// Point list.
    Points(PathBuf),
    /// Weighted point list.
    WeightedPoints(PathBuf, PathBuf),
    /// Surface mesh.
    Surface(MeshBuilder),
}

impl Build for EmitterBuilder {
    type Inst = Emitter;

    #[inline]
    fn build(self, in_dir: &Path) -> Result<Self::Inst, Error> {
        Ok(match self {
            Self::Beam(pos, dir) => Self::Inst::new_beam(Ray::new(pos, dir)),
            Self::Points(points_path) => {
                let table = Table::load(&in_dir.join(points_path))?;
                let points = table
                    .into_inner()
                    .iter()
                    .map(|row| Pos3::new(row[X], row[Y], row[Z]))
                    .collect();

                Self::Inst::new_points(points)
            }
            Self::WeightedPoints(points_path, weight_path) => {
                let points_data = Table::load(&in_dir.join(points_path))?;
                let points = points_data
                    .into_inner()
                    .iter()
                    .map(|row| Pos3::new(row[X], row[Y], row[Z]))
                    .collect();

                let weights_data = Table::load(&in_dir.join(weight_path))?;
                let weights: Vec<_> = weights_data.into_inner().iter().map(|row| row[X]).collect();

                Self::Inst::new_weighted_points(points, &weights)
            }
            Self::Surface(mesh) => Self::Inst::new_surface(mesh.build(in_dir)?),
        })
    }
}