Quadtrees are up and running! Let's render them!

This commit is contained in:
Isaac Clayton 2022-01-22 14:22:08 +01:00
parent 0628e1bc68
commit 7add9d30bd
4 changed files with 94 additions and 37 deletions

View file

@ -1,32 +1,74 @@
use std::marker::PhantomData;
use crate::quad::{Quad, Node, Embed};
/// Represents a context with shared state.
#[derive(Default, Debug)]
pub struct Ctx<A: Embed, B: Embed> {
_phantom_a: PhantomData<A>,
_phantom_b: PhantomData<B>,
pub trait Approx<A: Embed, B: Embed, S>: Default {
fn color_base(state: &mut S, base: A) -> [u8; 4];
fn compress_node(state: &mut S, compr: [B; 4]) -> B;
fn expand_node(state: &mut S, compr: B) -> [B; 4];
fn compress_base(state: &mut S, embed: A) -> B;
fn expand_base(state: &mut S, compr: B) -> A;
}
impl<A: Embed, B: Embed> Ctx<A, B> {
/// Creates a new uninitialized context.
pub fn new_empty() -> Self {
Default::default()
#[derive(Default)]
pub struct Basic;
impl Approx<u8, u8, ()> for Basic {
fn color_base(state: &mut (), base: u8) -> [u8; 4] {
[base;4]
}
/// Combines 4 child node representations into a single representation
/// Using a neural network.
pub fn combine(&mut self, compr: [B; 4]) -> B {
todo!("Build new B from 4 child B");
fn compress_node(state: &mut (), c: [u8; 4]) -> u8 {
c[0]/4 + c[1]/4 + c[2]/4 + c[3]/4
}
fn expand_node(state: &mut (), compr: u8) -> [u8; 4] {
[compr;4]
}
fn compress_base(state: &mut (), embed: u8) -> u8 {
embed
}
fn expand_base(state: &mut (), compr: u8) -> u8 {
compr
}
}
/// Represents a context with shared state.
#[derive(Debug)]
pub struct Ctx<A: Embed, B: Embed, S, N: Approx<A, B, S>> {
_phantom_a: PhantomData<A>,
_phantom_b: PhantomData<B>,
state: S,
networks: N,
}
impl<A: Embed, B: Embed, S, N: Approx<A, B, S>> Ctx<A, B, S, N> {
/// Creates a new uninitialized context.
pub fn new(state: S, networks: N) -> Self {
Ctx {
_phantom_a: PhantomData,
_phantom_b: PhantomData,
state,
networks,
}
}
pub fn color_base(&mut self, base: A) -> [u8; 4] {
N::color_base(&mut self.state, base)
}
/// Compresses a base-level cell into a vector.
pub fn compress_base(&mut self, base: A) -> B {
todo!("Turn Base Cell into a vector B");
N::compress_base(&mut self.state, base)
}
pub fn color_base(&mut self, base: &A) -> [u8; 4] {
todo!();
/// Combines 4 child node representations into a single representation
/// Using a neural network.
pub fn compress_node(&mut self, compr: [B; 4]) -> B {
N::compress_node(&mut self.state, compr)
}
/// Compresses a single node into a vector representation.
@ -36,7 +78,7 @@ impl<A: Embed, B: Embed> Ctx<A, B> {
match quad {
Quad::Base(b) => Some(self.compress_base(*b)),
Quad::Node(n) => Some(
self.combine([
self.compress_node([
n[0].compr,
n[1].compr,
n[2].compr,
@ -48,12 +90,12 @@ impl<A: Embed, B: Embed> Ctx<A, B> {
}
/// Compresses a base-level cell into a vector.
fn expand_base(&mut self, compr: B) -> A {
todo!("Turn compressed B into the A that made it");
pub fn expand_base(&mut self, compr: B) -> A {
N::expand_base(&mut self.state, compr)
}
fn expand_node(&mut self, compr: B) -> [B; 4] {
todo!("Turn compressed B into 4 child B that made it");
pub fn expand_node(&mut self, compr: B) -> [B; 4] {
N::expand_node(&mut self.state, compr)
}
/// Expands the compressed representation of a node into a node with 4 children.

View file

@ -6,9 +6,15 @@ mod render;
fn main() {
println!("Warming up...");
let mut ctx = ctx::Ctx::new_empty();
let mut ctx = ctx::Ctx::new((), ctx::Basic);
let mut base = vec![];
for i in 0..16 {
base.push(i);
}
let quad: quad::Node<u8, u8> = quad::Node::new_from_square(
&mut ctx, vec![0xFF;64],
&mut ctx, base,
);
// render::graphics();

View file

@ -1,7 +1,7 @@
use crate::ctx::Ctx;
use crate::ctx::{Ctx, Approx};
pub trait Embed: Default + Copy + Sized + std::fmt::Debug {
}
/// Represents the data present in a quad-tree node.
@ -32,7 +32,12 @@ pub struct Node<A: Embed, B: Embed> {
}
impl<A: Embed, B: Embed> Node<A, B> {
pub fn sample_color(self, ctx: &mut Ctx<A, B>, x: isize, y: isize) -> (Self, [u8; 4]) {
pub fn sample_color<S, N: Approx<A, B, S>>(
self,
ctx: &mut Ctx<A, B, S, N>,
x: isize,
y: isize,
) -> (Self, [u8; 4]) {
// self = ctx.expand(self);
// if let Quad::Base(b) = self.data {
// return (self, ctx.color_base(&b));
@ -54,12 +59,12 @@ impl<A: Embed, B: Embed> Node<A, B> {
}
/// Creates a new tree with a single empty base node
pub fn new_empty(ctx: &mut Ctx<A, B>) -> Self {
pub fn new_empty<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>) -> Self {
Self::new_base(ctx, Default::default())
}
/// Creates a new tree from a single base node
pub fn new_base(ctx: &mut Ctx<A, B>, base: A) -> Self {
pub fn new_base<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>, base: A) -> Self {
Node {
depth: 0,
compr: ctx.compress_base(base),
@ -67,7 +72,7 @@ impl<A: Embed, B: Embed> Node<A, B> {
}
}
pub fn new_node(ctx: &mut Ctx<A, B>, children: [Node<A, B>;4]) -> Self {
pub fn new_node<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>, children: [Node<A, B>;4]) -> Self {
// Make sure the depths check out
assert_eq!(children[0].depth, children[1].depth);
assert_eq!(children[1].depth, children[2].depth);
@ -88,8 +93,8 @@ impl<A: Embed, B: Embed> Node<A, B> {
}
}
fn build_square(
ctx: &mut Ctx<A, B>,
fn build_square<S, N: Approx<A, B, S>>(
ctx: &mut Ctx<A, B, S, N>,
square: &[A],
abs_size: usize,
depth: usize,
@ -106,16 +111,17 @@ impl<A: Embed, B: Embed> Node<A, B> {
let half = size / 2;
// in a z-like pattern
let children = [
Self::build_square(ctx, square, abs_size, depth - 1, x + half, y ),
Self::build_square(ctx, square, abs_size, depth - 1, x , y ),
Self::build_square(ctx, square, abs_size, depth - 1, x + half, y + half),
Self::build_square(ctx, square, abs_size, depth - 1, x + half, y ),
Self::build_square(ctx, square, abs_size, depth - 1, x , y + half),
Self::build_square(ctx, square, abs_size, depth - 1, x + half, y + half),
];
Self::new_node(ctx, children)
}
}
pub fn new_from_square(ctx: &mut Ctx<A, B>, square: Vec<A>) -> Self {
pub fn new_from_square<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>, square: Vec<A>) -> Self {
// get the side length, ensure this is a pow2 square
let area = square.len();
let size = ((area as f64).sqrt() + 0.5) as usize;
@ -135,7 +141,7 @@ impl<A: Embed, B: Embed> Node<A, B> {
/// Creates a new node double the size by centering the current node
/// on a node double the size.
pub fn pad_empty(self, ctx: &mut Ctx<A, B>) -> Self {
pub fn pad_empty<S, N: Approx<A, B, S>>(self, ctx: &mut Ctx<A, B, S, N>) -> Self {
todo!()
}
}

View file

@ -1,7 +1,10 @@
use crate::ctx::Ctx;
use crate::ctx::{Ctx, Approx};
use crate::quad::{Node, Embed};
pub fn step<A: Embed, B: Embed>(ctx: &mut Ctx<A, B>, node: Node<A, B>) -> Node<A, B> {
pub fn step<A: Embed, B: Embed, S, N: Approx<A, B, S>>(
ctx: &mut Ctx<A, B, S, N>,
node: Node<A, B>
) -> Node<A, B> {
// pad the graph if needed.
// if we're at the base, run the cellular automation rule: