Skip to content

Commit

Permalink
feat: partial layout
Browse files Browse the repository at this point in the history
still has bugs
  • Loading branch information
zxch3n committed Jun 9, 2022
1 parent 602d3c0 commit bd4e40b
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 99 deletions.
10 changes: 10 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/crates/tidy-tree/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"

[dependencies]
num = "0.4.0"
tinyset = "0.4.10"

[dev-dependencies]
rand = "0.8.5"
151 changes: 121 additions & 30 deletions rust/crates/tidy-tree/src/layout/tidy_layout.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{ptr::NonNull, thread::panicking};
use std::{collections::HashSet, hash::BuildHasher, ptr::NonNull, thread::panicking};

use tinyset::SetUsize;

use crate::{geometry::Coord, node::TidyData, utils::nocheck_mut, Layout, Node};

Expand Down Expand Up @@ -164,6 +166,8 @@ impl Node {
speed += child.shift_acceleration;
delta += speed + child.shift_change;
child.modifier_to_subtree += delta;
child.shift_acceleration = 0.;
child.shift_change = 0.;
}
}
}
Expand Down Expand Up @@ -273,17 +277,21 @@ impl TidyLayout {
}
}

fn set_y(&self, root: &mut Node) {
fn set_y_recursive(&self, root: &mut Node) {
root.pre_order_traversal_mut(|node| {
node.y = if let Some(parent) = node.parent {
let parent_bottom = unsafe { parent.as_ref().bottom() };
parent_bottom + self.parent_child_margin
} else {
0.
};
self.set_y(node);
});
}

fn set_y(&self, node: &mut Node) {
node.y = if let Some(parent) = node.parent {
let parent_bottom = unsafe { parent.as_ref().bottom() };
parent_bottom + self.parent_child_margin
} else {
0.
};
}

fn first_walk(&mut self, node: &mut Node) {
if node.children.len() == 0 {
node.set_extreme();
Expand All @@ -304,6 +312,33 @@ impl TidyLayout {
node.set_extreme();
}

fn first_walk_with_filter(&mut self, node: &mut Node, set: &SetUsize) {
if !set.contains(node as *const _ as usize) {
node.set_extreme();
invalidate_extreme_thread(node);
return;
}

invalidate_extreme_thread(node);
if node.children.len() == 0 {
node.set_extreme();
return;
}

self.first_walk_with_filter(node.children.first_mut().unwrap(), set);
let mut y_list = LinkedYList::new(0, node.children[0].extreme_right().bottom());
for i in 1..node.children.len() {
let current_child = node.children.get_mut(i).unwrap();
self.first_walk_with_filter(current_child, set);
let max_y = current_child.extreme_left().bottom();
y_list = self.separate(node, i, y_list);
y_list = y_list.update(i, max_y);
}

node.position_root();
node.set_extreme();
}

fn second_walk(&mut self, node: &mut Node, mut mod_sum: Coord) {
mod_sum += node.tidy_mut().modifier_to_subtree;
node.x = node.relative_x + mod_sum;
Expand All @@ -313,31 +348,27 @@ impl TidyLayout {
self.second_walk(child, mod_sum);
}
}

fn second_walk_with_filter(&mut self, node: &mut Node, mut mod_sum: Coord, set: &SetUsize) {
mod_sum += node.tidy_mut().modifier_to_subtree;
let new_x = node.relative_x + mod_sum;
if !set.contains(node as *const _ as usize) {
return;
}

node.x = new_x;
node.add_child_spacing();

for child in node.children.iter_mut() {
self.second_walk(child, mod_sum);
}
}
}

impl Layout for TidyLayout {
fn layout(&mut self, root: &mut Node) {
root.pre_order_traversal_mut(|node| {
node.tidy = Some(Box::new(TidyData {
extreme_left: None,
extreme_right: None,
shift_acceleration: 0.,
shift_change: 0.,
modifier_to_subtree: 0.,
modifier_extreme_left: 0.,
modifier_extreme_right: 0.,
thread_left: None,
thread_right: None,
modifier_thread_left: 0.,
modifier_thread_right: 0.,
test: TEST,
}));
node.x = 0.;
node.y = 0.;
node.relative_x = 0.;
node.relative_y = 0.;
});
self.set_y(root);
root.pre_order_traversal_mut(|node| init_node(node));
self.set_y_recursive(root);
self.first_walk(root);
self.second_walk(root, 0.);
}
Expand All @@ -347,10 +378,70 @@ impl Layout for TidyLayout {
root: &mut crate::Node,
changed: &[std::ptr::NonNull<crate::Node>],
) {
todo!()
for node in changed.iter() {
let node = unsafe { &mut *node.as_ptr() };
if node.tidy.is_none() {
init_node(node);
}
}

// TODO: optimize
self.set_y_recursive(root);
let mut set: SetUsize = SetUsize::new();
for node in changed.iter() {
set.insert(node.as_ptr() as usize);
let mut node = unsafe { &mut *node.as_ptr() };
while node.parent.is_some() {
set.insert(node.parent.unwrap().as_ptr() as usize);
node = node.parent();
}
}

self.first_walk_with_filter(root, &set);
// TODO: optimize
// self.second_walk_with_filter(root, 0., &set);
self.second_walk(root, 0.);
}
}

fn init_node(node: &mut Node) {
node.tidy = Some(Box::new(TidyData {
extreme_left: None,
extreme_right: None,
shift_acceleration: 0.,
shift_change: 0.,
modifier_to_subtree: 0.,
modifier_extreme_left: 0.,
modifier_extreme_right: 0.,
thread_left: None,
thread_right: None,
modifier_thread_left: 0.,
modifier_thread_right: 0.,
test: TEST,
}));
node.x = 0.;
node.y = 0.;
node.relative_x = 0.;
node.relative_y = 0.;
}

fn invalidate_extreme_thread(node: &mut Node) {
if node.tidy().extreme_left.is_none() {
node.set_extreme();
}

let mut e_left = node.extreme_left().tidy_mut();
e_left.thread_left = None;
e_left.thread_right = None;
e_left.modifier_thread_left = 0.;
e_left.modifier_thread_right = 0.;
let mut e_right = node.extreme_right().tidy_mut();
e_right.thread_left = None;
e_right.thread_right = None;
e_right.modifier_thread_left = 0.;
e_right.modifier_thread_right = 0.;
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
39 changes: 35 additions & 4 deletions rust/crates/tidy-tree/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::ptr::NonNull;

use crate::{geometry::Coord, layout::BoundingBox};

#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct TidyData {
pub thread_left: Option<NonNull<Node>>,
pub thread_right: Option<NonNull<Node>>,
Expand Down Expand Up @@ -35,7 +35,7 @@ pub struct TidyData {
pub modifier_extreme_right: Coord,
}

#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Node {
pub id: usize,
pub width: Coord,
Expand All @@ -53,6 +53,35 @@ pub struct Node {
pub tidy: Option<Box<TidyData>>,
}

impl Clone for Node {
fn clone(&self) -> Self {
let mut root = Self {
id: self.id.clone(),
width: self.width.clone(),
height: self.height.clone(),
x: self.x.clone(),
y: self.y.clone(),
relative_x: self.relative_x.clone(),
relative_y: self.relative_y.clone(),
bbox: self.bbox.clone(),
parent: None,
children: self.children.clone(),
tidy: None,
};

if self.parent.is_none() {
root.post_order_traversal_mut(|node| {
let node_ptr = node.into();
for child in node.children.iter_mut() {
child.parent = Some(node_ptr);
}
});
}

root
}
}

impl Default for Node {
fn default() -> Self {
Self {
Expand Down Expand Up @@ -87,9 +116,11 @@ impl Node {
tidy: None,
}
}
}

impl Node {
pub fn parent(&mut self) -> &mut Self {
unsafe { self.parent.unwrap().as_mut() }
}

pub fn bottom(&self) -> Coord {
self.height + self.y
}
Expand Down
7 changes: 1 addition & 6 deletions rust/crates/tidy-tree/tests/aesthetic_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub fn check_y_position_in_same_level(root: &Node) {
let mut prev = None;
for child in node.children.iter() {
if let Some(prev) = prev {
assert!(prev == child.y);
assert_eq!(prev, child.y);
}

prev = Some(child.y);
Expand Down Expand Up @@ -124,11 +124,6 @@ fn mirror(root: &Node) -> Node {
for i in 0..n / 2 {
node.children.swap(i, n - i - 1);
}

let node_ptr = node.into();
for child in node.children.iter_mut() {
child.parent = Some(node_ptr);
}
});
root
}
Loading

0 comments on commit bd4e40b

Please sign in to comment.