fold MaterialSim into GenericSim trait
This commit is contained in:
@@ -17,116 +17,6 @@ use spirv::{CpuBackend, SpirvSim};
|
||||
pub type StaticSim = SpirvSim<f32, Vacuum, CpuBackend>;
|
||||
|
||||
|
||||
pub trait MaterialSim: GenericSim {
|
||||
type Material: PartialEq;
|
||||
|
||||
fn put_material<C: Coord, M: Into<Self::Material>>(&mut self, pos: C, mat: M);
|
||||
fn get_material<C: Coord>(&self, pos: C) -> &Self::Material;
|
||||
|
||||
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S);
|
||||
fn step(&mut self) {
|
||||
// XXX: try not to exercise this path! NoopStimulus is probably a lot of waste.
|
||||
self.step_multiple(1, &NoopStimulus);
|
||||
}
|
||||
|
||||
fn fill_region_using<C, Reg, F, M>(&mut self, region: &Reg, f: F)
|
||||
where
|
||||
Reg: Region,
|
||||
F: Fn(C) -> M,
|
||||
C: Coord,
|
||||
M: Into<Self::Material>
|
||||
{
|
||||
for z in 0..self.depth() {
|
||||
for y in 0..self.height() {
|
||||
for x in 0..self.width() {
|
||||
let loc = Index((x, y, z).into());
|
||||
let meters = loc.to_meters(self.feature_size());
|
||||
if region.contains(meters) {
|
||||
self.put_material(loc, f(C::from_either(loc, meters)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_region<Reg: Region, M: Into<Self::Material> + Clone>(&mut self, region: &Reg, mat: M) {
|
||||
self.fill_region_using(region, |_idx: Index| mat.clone());
|
||||
}
|
||||
|
||||
fn examine_region<C, Reg, F>(&self, region: &Reg, mut f: F)
|
||||
where
|
||||
Reg: Region,
|
||||
F: FnMut(C, &Self::Material),
|
||||
C: Coord
|
||||
{
|
||||
for z in 0..self.depth() {
|
||||
for y in 0..self.height() {
|
||||
for x in 0..self.width() {
|
||||
let loc = Index((x, y, z).into());
|
||||
let meters = loc.to_meters(self.feature_size());
|
||||
if region.contains(meters) {
|
||||
f(C::from_either(loc, meters), self.get_material(loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if the given region is filled exclusively with the provided material.
|
||||
fn test_region_filled<Reg: Region, M: Into<Self::Material> + Clone>(&self, region: &Reg, mat: M) -> bool {
|
||||
let mut all = true;
|
||||
self.examine_region(region, |_idx: Index, m: &Self::Material| {
|
||||
all = all && m == &mat.clone().into();
|
||||
});
|
||||
all
|
||||
}
|
||||
|
||||
/// Fill the boundary, where `thickness` describes how far the boundary extends in each
|
||||
/// direction, and `f` takes a vec where each coordinate represents how far into the boundary
|
||||
/// the location being queried is, in each direction.
|
||||
/// e.g. `f((1.0, 0.0, 0.2))` means the location being queried is at either extreme end on the
|
||||
/// x axis, is not inside the y axis boundary, and is 20% of the way from the onset of the z
|
||||
/// boundary to the edge of the z world.
|
||||
fn fill_boundary_using<C, F, M>(&mut self, thickness: C, f: F)
|
||||
where
|
||||
C: Coord,
|
||||
F: Fn(Vec3<f32>) -> M,
|
||||
M: Into<Self::Material>,
|
||||
{
|
||||
// TODO: maybe this function belongs on the Driver?
|
||||
let feat = self.feature_size();
|
||||
let upper_left = thickness.to_index(feat);
|
||||
let size = self.size();
|
||||
let lower_right = size - upper_left - Index::new(1, 1, 1);
|
||||
let region = InvertedRegion::new(Cube::new(upper_left.to_meters(feat), lower_right.to_meters(feat)));
|
||||
self.fill_region_using(®ion, |loc: Index| {
|
||||
let depth_x = if loc.x() < upper_left.x() {
|
||||
(upper_left.x() - loc.x()) as f32 / upper_left.x() as f32
|
||||
} else if loc.x() > lower_right.x() {
|
||||
(loc.x() - lower_right.x()) as f32 / upper_left.x() as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let depth_y = if loc.y() < upper_left.y() {
|
||||
(upper_left.y() - loc.y()) as f32 / upper_left.y() as f32
|
||||
} else if loc.y() > lower_right.y() {
|
||||
(loc.y() - lower_right.y()) as f32 / upper_left.y() as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let depth_z = if loc.z() < upper_left.z() {
|
||||
(upper_left.z() - loc.z()) as f32 / upper_left.z() as f32
|
||||
} else if loc.z() > lower_right.z() {
|
||||
(loc.z() - lower_right.z()) as f32 / upper_left.z() as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
// println!("{} {}", loc, Vec3::new(depth_x, depth_y, depth_z));
|
||||
f(Vec3::new(depth_x, depth_y, depth_z))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Conceptually, one cell looks like this (in 2d):
|
||||
///
|
||||
/// +-------.-------+
|
||||
@@ -219,6 +109,7 @@ impl<R: Real> CellStateWithM<R> {
|
||||
|
||||
// TODO: the Send/Sync bounds here could be removed with some refactoring
|
||||
pub trait GenericSim: Send + Sync {
|
||||
type Material;
|
||||
fn meta(&self) -> SimMeta<f32>;
|
||||
fn step_no(&self) -> u64;
|
||||
fn sample(&self, pos: Meters) -> Sample;
|
||||
@@ -226,6 +117,15 @@ pub trait GenericSim: Send + Sync {
|
||||
/// Take a "snapshot" of the simulation, dropping all material-specific information.
|
||||
fn to_static(&self) -> StaticSim;
|
||||
|
||||
fn put_material<C: Coord, M: Into<Self::Material>>(&mut self, pos: C, mat: M);
|
||||
fn get_material<C: Coord>(&self, pos: C) -> &Self::Material;
|
||||
|
||||
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S);
|
||||
fn step(&mut self) {
|
||||
// XXX: try not to exercise this path! NoopStimulus is probably a lot of waste.
|
||||
self.step_multiple(1, &NoopStimulus);
|
||||
}
|
||||
|
||||
fn size(&self) -> Index {
|
||||
Index(self.meta().dim)
|
||||
}
|
||||
@@ -325,4 +225,105 @@ pub trait GenericSim: Send + Sync {
|
||||
fn current<C: Coord>(&self, c: C) -> Vec3<f32> {
|
||||
self.get(c).current_density() * self.feature_size() * self.feature_size()
|
||||
}
|
||||
|
||||
fn fill_region_using<C, Reg, F, M>(&mut self, region: &Reg, f: F)
|
||||
where
|
||||
Reg: Region,
|
||||
F: Fn(C) -> M,
|
||||
C: Coord,
|
||||
M: Into<Self::Material>
|
||||
{
|
||||
for z in 0..self.depth() {
|
||||
for y in 0..self.height() {
|
||||
for x in 0..self.width() {
|
||||
let loc = Index((x, y, z).into());
|
||||
let meters = loc.to_meters(self.feature_size());
|
||||
if region.contains(meters) {
|
||||
self.put_material(loc, f(C::from_either(loc, meters)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_region<Reg: Region, M: Into<Self::Material> + Clone>(&mut self, region: &Reg, mat: M) {
|
||||
self.fill_region_using(region, |_idx: Index| mat.clone());
|
||||
}
|
||||
|
||||
fn examine_region<C, Reg, F>(&self, region: &Reg, mut f: F)
|
||||
where
|
||||
Reg: Region,
|
||||
F: FnMut(C, &Self::Material),
|
||||
C: Coord
|
||||
{
|
||||
for z in 0..self.depth() {
|
||||
for y in 0..self.height() {
|
||||
for x in 0..self.width() {
|
||||
let loc = Index((x, y, z).into());
|
||||
let meters = loc.to_meters(self.feature_size());
|
||||
if region.contains(meters) {
|
||||
f(C::from_either(loc, meters), self.get_material(loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if the given region is filled exclusively with the provided material.
|
||||
fn test_region_filled<Reg: Region, M>(&self, region: &Reg, mat: M) -> bool
|
||||
where
|
||||
M: Into<Self::Material> + Clone,
|
||||
Self::Material: PartialEq,
|
||||
{
|
||||
let mut all = true;
|
||||
self.examine_region(region, |_idx: Index, m: &Self::Material| {
|
||||
all = all && m == &mat.clone().into();
|
||||
});
|
||||
all
|
||||
}
|
||||
|
||||
/// Fill the boundary, where `thickness` describes how far the boundary extends in each
|
||||
/// direction, and `f` takes a vec where each coordinate represents how far into the boundary
|
||||
/// the location being queried is, in each direction.
|
||||
/// e.g. `f((1.0, 0.0, 0.2))` means the location being queried is at either extreme end on the
|
||||
/// x axis, is not inside the y axis boundary, and is 20% of the way from the onset of the z
|
||||
/// boundary to the edge of the z world.
|
||||
fn fill_boundary_using<C, F, M>(&mut self, thickness: C, f: F)
|
||||
where
|
||||
C: Coord,
|
||||
F: Fn(Vec3<f32>) -> M,
|
||||
M: Into<Self::Material>,
|
||||
{
|
||||
// TODO: maybe this function belongs on the Driver?
|
||||
let feat = self.feature_size();
|
||||
let upper_left = thickness.to_index(feat);
|
||||
let size = self.size();
|
||||
let lower_right = size - upper_left - Index::new(1, 1, 1);
|
||||
let region = InvertedRegion::new(Cube::new(upper_left.to_meters(feat), lower_right.to_meters(feat)));
|
||||
self.fill_region_using(®ion, |loc: Index| {
|
||||
let depth_x = if loc.x() < upper_left.x() {
|
||||
(upper_left.x() - loc.x()) as f32 / upper_left.x() as f32
|
||||
} else if loc.x() > lower_right.x() {
|
||||
(loc.x() - lower_right.x()) as f32 / upper_left.x() as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let depth_y = if loc.y() < upper_left.y() {
|
||||
(upper_left.y() - loc.y()) as f32 / upper_left.y() as f32
|
||||
} else if loc.y() > lower_right.y() {
|
||||
(loc.y() - lower_right.y()) as f32 / upper_left.y() as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let depth_z = if loc.z() < upper_left.z() {
|
||||
(upper_left.z() - loc.z()) as f32 / upper_left.z() as f32
|
||||
} else if loc.z() > lower_right.z() {
|
||||
(loc.z() - lower_right.z()) as f32 / upper_left.z() as f32
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
// println!("{} {}", loc, Vec3::new(depth_x, depth_y, depth_z));
|
||||
f(Vec3::new(depth_x, depth_y, depth_z))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user