Turn area functions into methods

master
random-geek 2021-03-09 00:14:54 -08:00
parent 98cec33c81
commit 6db7c73ff0
8 changed files with 129 additions and 156 deletions

View File

@ -1,8 +1,7 @@
use super::{Command, BLOCK_CACHE_SIZE};
use crate::{unwrap_or, opt_unwrap_or};
use crate::spatial::{Vec3, area_rel_block_overlap,
area_abs_block_overlap};
use crate::spatial::Vec3;
use crate::map_database::MapDatabase;
use crate::map_block::{MapBlock, MapBlockError, is_valid_generated,
NodeMetadataList, NodeMetadataListExt};
@ -68,8 +67,7 @@ fn clone(inst: &mut InstBundle) {
);
let dst_pos = Vec3::from_block_key(dst_key);
let dst_part_abs = area_abs_block_overlap(&dst_area, dst_pos)
.unwrap();
let dst_part_abs = dst_area.abs_block_overlap(dst_pos).unwrap();
let src_part_abs = dst_part_abs - offset;
let src_blocks_needed = src_part_abs.to_touching_block_area();
@ -89,11 +87,11 @@ fn clone(inst: &mut InstBundle) {
continue
);
let src_frag_abs = area_abs_block_overlap(&src_part_abs, src_pos)
let src_frag_abs = src_part_abs.abs_block_overlap(src_pos)
.unwrap();
let src_frag_rel = src_frag_abs - src_pos * 16;
let dst_frag_rel = area_rel_block_overlap(
&(src_frag_abs + offset), dst_pos).unwrap();
let dst_frag_rel = (src_frag_abs + offset)
.rel_block_overlap(dst_pos).unwrap();
{
let _t = tk.get_timer("merge");

View File

@ -1,7 +1,7 @@
use super::Command;
use crate::unwrap_or;
use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
use crate::spatial::{Vec3, Area};
use crate::instance::{ArgType, InstBundle};
use crate::map_block::MapBlock;
use crate::block_utils::clean_name_id_map;
@ -42,7 +42,7 @@ fn fill(inst: &mut InstBundle) {
continue;
});
if area_contains_block(&area, pos) {
if area.contains_block(pos) {
let nd = block.node_data.get_mut();
for x in &mut nd.nodes {
*x = 0;
@ -51,7 +51,7 @@ fn fill(inst: &mut InstBundle) {
block.nimap.0.insert(0, node.to_vec());
count += nd.nodes.len() as u64;
} else {
let slice = area_rel_block_overlap(&area, pos).unwrap();
let slice = area.rel_block_overlap(pos).unwrap();
let fill_id = block.nimap.get_id(&node).unwrap_or_else(|| {
let next = block.nimap.get_max_id().unwrap() + 1;
block.nimap.0.insert(next, node.to_vec());

View File

@ -1,8 +1,7 @@
use super::{Command, BLOCK_CACHE_SIZE};
use crate::{unwrap_or, opt_unwrap_or};
use crate::spatial::{Vec3, Area, area_rel_block_overlap,
area_abs_block_overlap, area_contains_block, area_touches_block};
use crate::spatial::{Vec3, Area};
use crate::instance::{ArgType, InstArgs, InstBundle};
use crate::map_database::MapDatabase;
use crate::map_block::{MapBlock, MapBlockError, is_valid_generated,
@ -44,8 +43,8 @@ fn overlay_no_offset(inst: &mut InstBundle) {
if let Some(area) = inst.args.area {
let pos = Vec3::from_block_key(key);
if (!invert && area_contains_block(&area, pos))
|| (invert && !area_touches_block(&area, pos))
if (!invert && area.contains_block(pos))
|| (invert && !area.touches_block(pos))
{ // If possible, copy whole map block.
let data = idb.get_block(key).unwrap();
if is_valid_generated(&data) {
@ -66,8 +65,7 @@ fn overlay_no_offset(inst: &mut InstBundle) {
let mut dst_meta = NodeMetadataList::deserialize(
&dst_block.metadata.get_ref())?;
let block_part = area_rel_block_overlap(&area, pos)
.unwrap();
let block_part = area.rel_block_overlap(pos).unwrap();
if invert {
// For inverted selections, reverse the order of the
// overlay operations.
@ -157,7 +155,7 @@ fn overlay_with_offset(inst: &mut InstBundle) {
let dst_part_abs = dst_area.map_or(
Area::new(dst_pos * 16, dst_pos * 16 + 15),
|ref a| area_abs_block_overlap(a, dst_pos).unwrap()
|ref a| a.abs_block_overlap(dst_pos).unwrap()
);
let src_part_abs = dst_part_abs - offset;
let src_blocks_needed = src_part_abs.to_touching_block_area();
@ -177,11 +175,11 @@ fn overlay_with_offset(inst: &mut InstBundle) {
continue
);
let src_frag_abs = area_abs_block_overlap(&src_part_abs, src_pos)
let src_frag_abs = src_part_abs.abs_block_overlap(src_pos)
.unwrap();
let src_frag_rel = src_frag_abs - src_pos * 16;
let dst_frag_rel = area_rel_block_overlap(
&(src_frag_abs + offset), dst_pos).unwrap();
let dst_frag_rel = (src_frag_abs + offset)
.rel_block_overlap(dst_pos).unwrap();
merge_blocks(&src_block, &mut dst_block,
src_frag_rel, dst_frag_rel);

View File

@ -1,7 +1,6 @@
use super::Command;
use crate::spatial::{Vec3, Area, area_contains_block, area_touches_block,
area_rel_block_overlap};
use crate::spatial::{Vec3, Area};
use crate::instance::{ArgType, InstArgs, InstBundle};
use crate::map_block::MapBlock;
use crate::time_keeper::TimeKeeper;
@ -22,12 +21,11 @@ fn do_replace(
let mut count = 0;
// Replace nodes in a portion of a map block.
if area.is_some() && area_contains_block(&area.unwrap(), block_pos) !=
area_touches_block(&area.unwrap(), block_pos)
if area.is_some() && area.unwrap().contains_block(block_pos) !=
area.unwrap().touches_block(block_pos)
{
let _t = tk.get_timer("replace (partial block)");
let node_area = area_rel_block_overlap(&area.unwrap(), block_pos)
.unwrap();
let node_area = area.unwrap().rel_block_overlap(block_pos).unwrap();
let mut new_replace_id = false;
let replace_id = block.nimap.get_id(new_node)

View File

@ -1,6 +1,6 @@
use super::Command;
use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
use crate::spatial::{Vec3, Area};
use crate::instance::{ArgType, InstArgs, InstBundle};
use crate::map_block::MapBlock;
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
@ -66,9 +66,9 @@ fn set_param2(inst: &mut InstBundle) {
let nd = block.node_data.get_mut();
if let Some(area) = inst.args.area
.filter(|a| !area_contains_block(&a, pos))
.filter(|a| !a.contains_block(pos))
{ // Modify part of block
let overlap = area_rel_block_overlap(&area, pos).unwrap();
let overlap = area.rel_block_overlap(pos).unwrap();
if let Some(nid) = node_id {
count +=
set_in_area_node(&mut block, overlap, nid, param2_val);

View File

@ -69,6 +69,10 @@ impl Area {
}
}
pub fn iterate(&self) -> AreaIterator {
AreaIterator::new(self.min, self.max)
}
pub fn volume(&self) -> u64 {
(self.max.x - self.min.x + 1) as u64 *
(self.max.y - self.min.y + 1) as u64 *
@ -81,8 +85,18 @@ impl Area {
&& self.min.z <= pos.z && pos.z <= self.max.z
}
pub fn iterate(&self) -> AreaIterator {
AreaIterator::new(self.min, self.max)
pub fn contains_block(&self, block_pos: Vec3) -> bool {
let corner = block_pos * 16;
self.min.x <= corner.x && corner.x + 15 <= self.max.x
&& self.min.y <= corner.y && corner.y + 15 <= self.max.y
&& self.min.z <= corner.z && corner.z + 15 <= self.max.z
}
pub fn touches_block(&self, block_pos: Vec3) -> bool {
let corner = block_pos * 16;
self.min.x <= corner.x + 15 && corner.x <= self.max.x
&& self.min.y <= corner.y + 15 && corner.y <= self.max.y
&& self.min.z <= corner.z + 15 && corner.z <= self.max.z
}
pub fn to_contained_block_area(&self) -> Self {
@ -112,6 +126,55 @@ impl Area {
);
Self {min, max}
}
pub fn abs_block_overlap(&self, block_pos: Vec3) -> Option<Area> {
let block_min = block_pos * 16;
let block_max = block_min + 15;
let node_min = Vec3 {
x: max(self.min.x, block_min.x),
y: max(self.min.y, block_min.y),
z: max(self.min.z, block_min.z)
};
let node_max = Vec3 {
x: min(self.max.x, block_max.x),
y: min(self.max.y, block_max.y),
z: min(self.max.z, block_max.z)
};
if node_min.x <= node_max.x
&& node_min.y <= node_max.y
&& node_min.z <= node_max.z
{
Some(Self {min: node_min, max: node_max})
} else {
None
}
}
pub fn rel_block_overlap(&self, block_pos: Vec3) -> Option<Area> {
let corner = block_pos * 16;
let rel_min = self.min - corner;
let rel_max = self.max - corner;
let node_min = Vec3 {
x: max(rel_min.x, 0),
y: max(rel_min.y, 0),
z: max(rel_min.z, 0)
};
let node_max = Vec3 {
x: min(rel_max.x, 15),
y: min(rel_max.y, 15),
z: min(rel_max.z, 15)
};
if node_min.x <= node_max.x
&& node_min.y <= node_max.y
&& node_min.z <= node_max.z
{
Some(Self {min: node_min, max: node_max})
} else {
None
}
}
}
impl std::ops::Add<Vec3> for Area {
@ -175,4 +238,33 @@ mod tests {
iter_area(Area::new(Vec3::new(10, -99, 11), Vec3::new(10, -99, 12)));
iter_area(Area::new(Vec3::new(0, -1, -2), Vec3::new(5, 7, 11)));
}
#[test]
fn test_area_containment() {
let area = Area::new(Vec3::new(-1, -32, 16), Vec3::new(30, -17, 54));
let contained = Area::new(Vec3::new(0, -2, 1), Vec3::new(0, -2, 2));
let touching = Area::new(Vec3::new(-1, -2, 1), Vec3::new(1, -2, 3));
for pos in Area::new(touching.min - 2, touching.max + 2).iterate() {
assert_eq!(area.touches_block(pos), touching.contains(pos));
assert_eq!(area.contains_block(pos), contained.contains(pos));
}
}
#[test]
fn test_area_block_overlap() {
let area = Area::new(Vec3::new(-3, -3, -3), Vec3::new(15, 15, 15));
let pairs = vec![
(Vec3::new(-1, -1, -1),
Some(Area::new(Vec3::new(13, 13, 13), Vec3::new(15, 15, 15)))),
(Vec3::new(0, 0, 0),
Some(Area::new(Vec3::new(0, 0, 0), Vec3::new(15, 15, 15)))),
(Vec3::new(1, 1, 1), None),
(Vec3::new(-1, 0, 0),
Some(Area::new(Vec3::new(13, 0, 0), Vec3::new(15, 15, 15)))),
];
for pair in pairs {
assert_eq!(area.rel_block_overlap(pair.0), pair.1);
}
}
}

View File

@ -1,130 +1,5 @@
use std::cmp::{min, max};
mod vec3;
mod area;
pub use vec3::Vec3;
pub use area::Area;
// TODO: Should these go in the area impl?
pub fn area_contains_block(area: &Area, block_pos: Vec3) -> bool {
let corner = block_pos * 16;
area.min.x <= corner.x && corner.x + 15 <= area.max.x
&& area.min.y <= corner.y && corner.y + 15 <= area.max.y
&& area.min.z <= corner.z && corner.z + 15 <= area.max.z
}
pub fn area_touches_block(area: &Area, block_pos: Vec3) -> bool {
let corner = block_pos * 16;
area.min.x <= corner.x + 15 && corner.x <= area.max.x
&& area.min.y <= corner.y + 15 && corner.y <= area.max.y
&& area.min.z <= corner.z + 15 && corner.z <= area.max.z
}
pub fn area_abs_block_overlap(area: &Area, block_pos: Vec3) -> Option<Area> {
let block_min = block_pos * 16;
let block_max = block_min + 15;
let node_min = Vec3 {
x: max(area.min.x, block_min.x),
y: max(area.min.y, block_min.y),
z: max(area.min.z, block_min.z)
};
let node_max = Vec3 {
x: min(area.max.x, block_max.x),
y: min(area.max.y, block_max.y),
z: min(area.max.z, block_max.z)
};
if node_min.x <= node_max.x
&& node_min.y <= node_max.y
&& node_min.z <= node_max.z
{
Some(Area {min: node_min, max: node_max})
} else {
None
}
}
pub fn area_rel_block_overlap(area: &Area, block_pos: Vec3) -> Option<Area> {
let corner = block_pos * 16;
let rel_min = area.min - corner;
let rel_max = area.max - corner;
let node_min = Vec3 {
x: max(rel_min.x, 0),
y: max(rel_min.y, 0),
z: max(rel_min.z, 0)
};
let node_max = Vec3 {
x: min(rel_max.x, 15),
y: min(rel_max.y, 15),
z: min(rel_max.z, 15)
};
if node_min.x <= node_max.x
&& node_min.y <= node_max.y
&& node_min.z <= node_max.z
{
Some(Area {min: node_min, max: node_max})
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_area_containment() {
let area = Area::new(Vec3::new(-1, -32, 16), Vec3::new(30, -17, 54));
let test_blocks = vec![
// Fully contained
(Vec3::new(0, -2, 1), true, true),
(Vec3::new(0, -2, 2), true, true),
// Partially contained
(Vec3::new(-1, -2, 1), true, false),
(Vec3::new(-1, -2, 2), true, false),
(Vec3::new(-1, -2, 3), true, false),
(Vec3::new(0, -2, 3), true, false),
(Vec3::new(1, -2, 3), true, false),
(Vec3::new(1, -2, 3), true, false),
(Vec3::new(1, -2, 2), true, false),
(Vec3::new(1, -2, 1), true, false),
// Not contained
(Vec3::new(-1, -2, 0), false, false),
(Vec3::new(0, -2, 0), false, false),
(Vec3::new(1, -2, 0), false, false),
(Vec3::new(2, -2, 0), false, false),
(Vec3::new(2, -2, 1), false, false),
(Vec3::new(2, -2, 2), false, false),
(Vec3::new(2, -2, 3), false, false),
];
for (pos, touches, contains) in test_blocks {
assert_eq!(area_touches_block(&area, pos), touches);
assert_eq!(area_contains_block(&area, pos), contains);
}
}
#[test]
fn test_area_block_overlap() {
let area = Area::new(Vec3::new(-3, -3, -3), Vec3::new(15, 15, 15));
let pairs = vec![
(Vec3::new(-1, -1, -1),
Some(Area::new(Vec3::new(13, 13, 13), Vec3::new(15, 15, 15)))),
(Vec3::new(0, 0, 0),
Some(Area::new(Vec3::new(0, 0, 0), Vec3::new(15, 15, 15)))),
(Vec3::new(1, 1, 1), None),
(Vec3::new(-1, 0, 0),
Some(Area::new(Vec3::new(13, 0, 0), Vec3::new(15, 15, 15)))),
];
for pair in pairs {
assert_eq!(area_rel_block_overlap(&area, pair.0), pair.1);
}
}
}

View File

@ -99,6 +99,18 @@ impl std::ops::Sub<Self> for Vec3 {
}
}
impl std::ops::Sub<i32> for Vec3 {
type Output = Self;
fn sub(self, rhs: i32) -> Self {
Self {
x: self.x - rhs,
y: self.y - rhs,
z: self.z - rhs
}
}
}
impl std::ops::Mul<Self> for Vec3 {
type Output = Self;