Skip to content

Commit

Permalink
fix: align partial layout with full layout
Browse files Browse the repository at this point in the history
  • Loading branch information
zxch3n committed Jun 10, 2022
1 parent 51f40fd commit dcf9c41
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 9 deletions.
4 changes: 2 additions & 2 deletions rust/crates/tidy-tree/src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::Node;

struct Iter<'a> {
pub struct Iter<'a> {
node: &'a Node,
slot_stack: Vec<usize>,
finished: bool,
Expand Down Expand Up @@ -46,7 +46,7 @@ impl<'a> Iterator for Iter<'a> {

impl Node {
#[inline]
fn iter(&self) -> Iter {
pub fn iter(&self) -> Iter {
Iter {
node: self,
slot_stack: vec![],
Expand Down
2 changes: 1 addition & 1 deletion rust/crates/tidy-tree/src/layout/tidy_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ impl TidyLayout {
let mut left = Contour::new(false, &node.children[child_index - 1]);
// left contour of the right
let mut right = Contour::new(true, &node.children[child_index]);
// let mut i = 0;
while !left.is_none() && !right.is_none() {
if left.bottom() > y_list.bottom() {
y_list = y_list.pop().unwrap();
Expand Down Expand Up @@ -327,6 +326,7 @@ impl TidyLayout {
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();
current_child.tidy_mut().modifier_to_subtree = -current_child.relative_x;
self.first_walk_with_filter(current_child, set);
let max_y = current_child.extreme_left().bottom();
y_list = self.separate(node, i, y_list);
Expand Down
1 change: 1 addition & 0 deletions rust/crates/tidy-tree/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod iter;
mod layout;
mod node;
mod utils;
pub use iter::Iter;
use std::{any::Any, collections::HashMap, ptr::NonNull};

use geometry::Coord;
Expand Down
5 changes: 3 additions & 2 deletions rust/crates/tidy-tree/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,14 @@ impl Node {
let mut s = String::new();
if self.tidy.is_some() {
s.push_str(&format!(
"x: {}, y: {}, width: {}, height: {}, rx: {}, mod: {}\n",
"x: {}, y: {}, width: {}, height: {}, rx: {}, mod: {}, id: {}\n",
self.x,
self.y,
self.width,
self.height,
self.relative_x,
self.tidy().modifier_to_subtree
self.tidy().modifier_to_subtree,
self.id
));
} else {
s.push_str(&format!(
Expand Down
46 changes: 43 additions & 3 deletions rust/crates/tidy-tree/tests/layout_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ pub fn test_layout(layout: &mut dyn Layout) {
for _ in 0..100 {
let mut tree = gen_tree(&mut rng, 500);
layout.layout(&mut tree);
// let first: Vec<Coord> = tree.iter().map(|node| node.x).collect();
// layout.layout(&mut tree);
// let second: Vec<Coord> = tree.iter().map(|node| node.x).collect();
// assert_eq!(first, second);
aesthetic_rules::assert_no_overlap_nodes(&tree);
aesthetic_rules::assert_no_crossed_lines(&tree);
aesthetic_rules::check_nodes_order(&tree);
Expand Down Expand Up @@ -48,6 +52,41 @@ pub fn test_partial_layout(layout: &mut dyn Layout) {
}
}

pub fn align_partial_layout_with_full_layout(layout: &mut dyn Layout) {
let mut rng = StdRng::seed_from_u64(1001);
for _ in 0..100 {
let mut tree = gen_tree(&mut rng, 10);
layout.layout(&mut tree);
let mut nodes: Vec<NonNull<Node>> = vec![];
tree.pre_order_traversal(|node| nodes.push(node.into()));
for times in 0..100 {
let new_node = insert_random_node(&mut rng, &nodes);
let changed_node = change_random_node(&mut rng, &nodes);
layout.partial_layout(&mut tree, &[new_node, changed_node]);
let partial_str = tree.str();
let partial_x: Vec<Coord> = tree.iter().map(|node| node.x).collect();
aesthetic_rules::assert_no_overlap_nodes(&tree);
aesthetic_rules::assert_no_crossed_lines(&tree);
aesthetic_rules::check_nodes_order(&tree);
aesthetic_rules::check_y_position_in_same_level(&tree);
aesthetic_rules::assert_parent_centered(&tree);
layout.layout(&mut tree);
let full_x: Vec<Coord> = tree.iter().map(|node| node.x).collect();
for i in 0..partial_x.len() {
if (full_x[i] - partial_x[i]).abs() > 10. {
println!("NEW_NODE: {}", unsafe { new_node.as_ref().str() });
println!("{} != {}", full_x[i], partial_x[i]);
panic!("partial layout result does not equal full layout result. Times: {}.\nfull: {:?}\npartial: {:?}\n\nFULL\n{}\n\nPARTIAL\n{}",
times,
&full_x, &partial_x,
tree.str(), partial_str
);
}
}
}
}
}

fn change_random_node(rng: &mut StdRng, nodes: &[NonNull<Node>]) -> NonNull<Node> {
let node_index = rng.gen_range(0..nodes.len()) as usize;
let node = unsafe { &mut *nodes[node_index].as_ptr() };
Expand Down Expand Up @@ -80,8 +119,8 @@ pub fn gen_tree(rng: &mut StdRng, num: usize) -> Node {
fn gen_node(rng: &mut StdRng) -> Node {
Node {
id: rng.gen(),
width: rng.gen_range(1..10) as Coord,
height: rng.gen_range(1..10) as Coord,
width: rng.gen_range(5..50) as Coord,
height: rng.gen_range(5..50) as Coord,
x: 0.,
y: 0.,
relative_x: 0.,
Expand Down Expand Up @@ -165,6 +204,7 @@ mod test {
#[test]
fn test_tidy_partial_layout() {
let mut layout = TidyLayout::new(10., 10.);
test_partial_layout(&mut layout);
// test_partial_layout(&mut layout);
align_partial_layout_with_full_layout(&mut layout);
}
}
2 changes: 1 addition & 1 deletion src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class Renderer extends Disposable {
const scale = Math.min(
this.render.getWidth() / (gBox.width + 20),
this.render.getHeight() / (gBox.height + 20),
2,
5,
);
g.animateTo({ scaleX: scale, scaleY: scale });
}
Expand Down
86 changes: 86 additions & 0 deletions src/stories/DebugTree.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Renderer } from '../renderer';
import { Node } from '../tidy';
import { LayoutTypeStr } from '../TidyComponent';
import { createNode, createTree, visit } from '../utils';
import { debugStrToTree } from './debugToTree';

export default {
title: 'DebugTree',
component: DebugTree,
};

interface Props {
input: string;
}

function DebugTree({ input }: Props) {
const root = debugStrToTree(input);
const renderRef = useRef<Renderer>();
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const func = async () => {
renderRef.current = new Renderer(containerRef.current!);
renderRef.current.init(root);
};

func();
return () => {
renderRef.current?.dispose();
};
}, []);

return <div ref={containerRef} style={{ width: '100%', minHeight: 500 }} />;
}

/**
* Primary UI component for user interaction
*/
export const Debug = () => {
const partial = `x: 0, y: 0, width: 6, height: 34, rx: 78.6875, mod: -78.6875
x: -78.6875, y: 44, width: 29, height: 11, rx: 21.25, mod: -21.25
x: -99.9375, y: 65, width: 24, height: 34, rx: 30, mod: -30
x: -129.9375, y: 109, width: 6, height: 20, rx: 0, mod: 0
x: -129.9375, y: 139, width: 22, height: 48, rx: 0, mod: 0
x: -102.9375, y: 109, width: 12, height: 49, rx: 0, mod: 27
x: -69.9375, y: 109, width: 34, height: 27, rx: 0, mod: 60
x: -57.4375, y: 65, width: 41, height: 26, rx: 0, mod: 42.5
x: 25.40625, y: 44, width: 16, height: 15, rx: 0, mod: 104.09375
x: 78.6875, y: 44, width: 41, height: 37, rx: 61.875, mod: 95.5
x: 16.8125, y: 91, width: 45, height: 23, rx: 45.75, mod: -45.75
x: -28.9375, y: 124, width: 28, height: 39, rx: 0, mod: 0
x: -28.9375, y: 173, width: 19, height: 14, rx: 0, mod: 0
x: 19.5625, y: 124, width: 49, height: 42, rx: 0, mod: 48.5
x: 62.5625, y: 124, width: 17, height: 30, rx: 0, mod: 91.5
x: 96.5625, y: 91, width: 25, height: 10, rx: 0, mod: 79.75
x: 96.5625, y: 111, width: 31, height: 15, rx: 0, mod: 0
x: 140.5625, y: 91, width: 37, height: 15, rx: 0, mod: 123.75`;
const full = `x: 0, y: 0, width: 6, height: 34, rx: 78.6875, mod: -78.6875
x: -78.6875, y: 44, width: 29, height: 11, rx: 21.25, mod: -21.25
x: -99.9375, y: 65, width: 24, height: 34, rx: 30, mod: -30
x: -129.9375, y: 109, width: 6, height: 20, rx: 0, mod: 0
x: -129.9375, y: 139, width: 22, height: 48, rx: 0, mod: 0
x: -102.9375, y: 109, width: 12, height: 49, rx: 0, mod: 27
x: -69.9375, y: 109, width: 34, height: 27, rx: 0, mod: 60
x: -57.4375, y: 65, width: 41, height: 26, rx: 0, mod: 42.5
x: 10.625, y: 44, width: 16, height: 15, rx: 0, mod: 89.3125
x: 78.6875, y: 44, width: 41, height: 37, rx: 61.875, mod: 95.5
x: 16.8125, y: 91, width: 45, height: 23, rx: 45.75, mod: -45.75
x: -28.9375, y: 124, width: 28, height: 39, rx: 0, mod: 0
x: -28.9375, y: 173, width: 19, height: 14, rx: 0, mod: 0
x: 19.5625, y: 124, width: 49, height: 42, rx: 0, mod: 48.5
x: 62.5625, y: 124, width: 17, height: 30, rx: 0, mod: 91.5
x: 96.5625, y: 91, width: 25, height: 10, rx: 0, mod: 79.75
x: 96.5625, y: 111, width: 31, height: 15, rx: 0, mod: 0
x: 140.5625, y: 91, width: 37, height: 15, rx: 0, mod: 123.75`;
return (
<div>
<h2>Partial Layout</h2>
<DebugTree input={partial} />
<h2>Full Layout</h2>
<DebugTree input={full} />
</div>
);
};

Debug.args = {};
46 changes: 46 additions & 0 deletions src/stories/debugToTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { InnerNode } from '../tidy';
export function debugStrToTree(input: string): InnerNode {
const lines = input.split('\n');
return linesToNode(lines.map((line) => ({ line, indent: getIndent(line) })));
}

function linesToNode(lines: { line: string; indent: number }[]): InnerNode {
const currentIndent = lines[0].indent;
const node = lineToNode(lines[0].line);
for (let i = 1; i < lines.length; i++) {
const { line, indent } = lines[i];
if (indent === currentIndent + 1) {
const start = i;
let childIndent = lines[i + 1]?.indent;
while (childIndent != null && childIndent >= currentIndent + 2) {
i += 1;
childIndent = lines[i + 1]?.indent;
}

const child = linesToNode(lines.slice(start, i + 1));
node.children.push(child);
} else {
throw new Error();
}
}

return node;
}

function lineToNode(line: string): InnerNode {
const ans = line.match(
/x: ([-\d\.]+), y: ([-\d\.]+), width: ([\d\.]+), height: ([\d\.]+)/,
)!;
return {
id: (Math.random() * 1e9) | 0,
x: parseFloat(ans[1]),
y: parseFloat(ans[2]),
width: parseFloat(ans[3]),
height: parseFloat(ans[4]),
children: [],
};
}

function getIndent(line: string) {
return (line.match(/^ */s)![0].length / 4) | 0;
}
22 changes: 22 additions & 0 deletions test/tidy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TidyLayout, initWasm, LayoutType } from '../src/tidy';
import { describe, it } from 'vitest';
import { createTree } from '../src/utils';
import { readFile } from 'fs/promises';
import { debugStrToTree } from '../src/stories/debugToTree';
import * as path from 'path';

describe('tidy', () => {
Expand Down Expand Up @@ -35,4 +36,25 @@ describe('tidy', () => {
// nodes.push(node);
// });
});

it('debug', () => {
const tree =
debugStrToTree(`x: 0, y: 0, width: 2, height: 5, rx: 11.158500000000002, mod: -11.158500000000002
x: -11.1585, y: 5.001, width: 1, height: 5, rx: 13.315000000000001, mod: -13.315000000000001
x: -24.4735, y: 10.002, width: 9, height: 2, rx: 6.376, mod: -6.376
x: -30.849500000000003, y: 12.003, width: 7, height: 1, rx: 0, mod: 0
x: -30.849500000000003, y: 13.004, width: 9, height: 6, rx: 0, mod: 0
x: -23.4735, y: 12.003, width: 1, height: 6, rx: 0, mod: 7.376
x: -18.0975, y: 12.003, width: 5, height: 7, rx: 5.751, mod: 7.001
x: -23.8485, y: 19.004, width: 5, height: 7, rx: 0, mod: 0
x: -17.3475, y: 19.004, width: 8, height: 9, rx: 0, mod: 6.501
x: -12.3465, y: 19.004, width: 2, height: 7, rx: 0, mod: 11.502
x: -7.345500000000001, y: 10.002, width: 5, height: 7, rx: 0, mod: 17.128
x: -7.345500000000001, y: 17.003000000000004, width: 8, height: 6, rx: 0, mod: 0
x: -1.3445, y: 10.002, width: 2, height: 7, rx: 0, mod: 23.129
x: -1.3445, y: 17.003000000000004, width: 4, height: 9, rx: 0, mod: 0
x: 2.156500000000001, y: 10.002, width: 3, height: 9, rx: 0, mod: 26.630000000000003
x: 6.157500000000001, y: 5.001, width: 5, height: 6, rx: 0, mod: 17.316000000000003
x: 11.158500000000002, y: 5.001, width: 5, height: 7, rx: 0, mod: 22.317000000000004`);
});
});

0 comments on commit dcf9c41

Please sign in to comment.