Skip to content

Commit

Permalink
fix: use float as coord & fix mirror bug
Browse files Browse the repository at this point in the history
  • Loading branch information
zxch3n committed Jun 3, 2022
1 parent 757c6f0 commit 558b5a2
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 97 deletions.
83 changes: 83 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 @@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
num = "0.4.0"

[dev-dependencies]
rand = "0.8.5"
81 changes: 42 additions & 39 deletions rust/crates/tidy-tree/src/geometry.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use num::Float;
use std::cmp::{max, min};

#[derive(PartialEq, Eq, Debug)]
pub type Coord = f64;

#[derive(PartialEq, Debug)]
pub struct Point {
pub x: isize,
pub y: isize,
pub x: Coord,
pub y: Coord,
}

#[derive(PartialEq, Eq, Debug)]
Expand All @@ -17,17 +20,17 @@ impl Point {
pub fn orientation(p: &Point, q: &Point, r: &Point) -> Orientation {
let val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);

if val == 0 {
if val.abs() < 1e-7 {
Orientation::Colinear
} else if val > 0 {
} else if val > 0. {
Orientation::ClockWise
} else {
Orientation::CounterClockWise
}
}
}

#[derive(PartialEq, Eq, Debug)]
#[derive(PartialEq, Debug)]
pub struct Line {
pub from: Point,
pub to: Point,
Expand All @@ -38,10 +41,10 @@ impl Line {
let from = &self.from;
let to = &self.to;

point.x >= min(from.x, to.x)
&& point.x <= max(from.x, to.x)
&& point.y >= min(from.y, to.y)
&& point.y <= max(from.y, to.y)
point.x >= Float::min(from.x, to.x)
&& point.x <= Float::max(from.x, to.x)
&& point.y >= Float::min(from.y, to.y)
&& point.y <= Float::max(from.y, to.y)
}

pub fn intersect(&self, other: &Self) -> bool {
Expand Down Expand Up @@ -82,72 +85,72 @@ mod test {
use super::*;
#[test]
fn orient() {
let a = Point { x: 0, y: 0 };
let b = Point { x: 1, y: 0 };
let c = Point { x: 0, y: 1 };
let a = Point { x: 0., y: 0. };
let b = Point { x: 1., y: 0. };
let c = Point { x: 0., y: 1. };
assert_eq!(
Point::orientation(&a, &b, &c),
Orientation::CounterClockWise
);
let a = Point { x: 0, y: 0 };
let b = Point { x: 0, y: 1 };
let c = Point { x: 1, y: 0 };
let a = Point { x: 0., y: 0. };
let b = Point { x: 0., y: 1. };
let c = Point { x: 1., y: 0. };
assert_eq!(Point::orientation(&a, &b, &c), Orientation::ClockWise);
let a = Point { x: 0, y: 0 };
let b = Point { x: 1, y: 1 };
let c = Point { x: 4, y: 4 };
let a = Point { x: 0., y: 0. };
let b = Point { x: 1., y: 1. };
let c = Point { x: 4., y: 4. };
assert_eq!(Point::orientation(&a, &b, &c), Orientation::Colinear);
}

#[test]
fn intersect() {
let a = Line {
from: Point { x: 0, y: 0 },
to: Point { x: 1, y: 0 },
from: Point { x: 0., y: 0. },
to: Point { x: 1., y: 0. },
};
let b = Line {
from: Point { x: 1, y: 1 },
to: Point { x: 1, y: -1 },
from: Point { x: 1., y: 1. },
to: Point { x: 1., y: -1. },
};
assert!(a.intersect(&b));

let a = Line {
from: Point { x: 0, y: 0 },
to: Point { x: 1, y: 0 },
from: Point { x: 0., y: 0. },
to: Point { x: 1., y: 0. },
};
let b = Line {
from: Point { x: 2, y: 1 },
to: Point { x: 1, y: -1 },
from: Point { x: 2., y: 1. },
to: Point { x: 1., y: -1. },
};
assert!(!a.intersect(&b));

let a = Line {
from: Point { x: 0, y: 0 },
to: Point { x: 1, y: 1 },
from: Point { x: 0., y: 0. },
to: Point { x: 1., y: 1. },
};
let b = Line {
from: Point { x: 0, y: 1 },
to: Point { x: 1, y: 0 },
from: Point { x: 0., y: 1. },
to: Point { x: 1., y: 0. },
};
assert!(a.intersect(&b));

let a = Line {
from: Point { x: 0, y: 0 },
to: Point { x: 1, y: 1 },
from: Point { x: 0., y: 0. },
to: Point { x: 1., y: 1. },
};
let b = Line {
from: Point { x: 1, y: 1 },
to: Point { x: 2, y: 2 },
from: Point { x: 1., y: 1. },
to: Point { x: 2., y: 2. },
};
assert!(a.intersect(&b));

let a = Line {
from: Point { x: 0, y: 0 },
to: Point { x: 1, y: 1 },
from: Point { x: 0., y: 0. },
to: Point { x: 1., y: 1. },
};
let b = Line {
from: Point { x: 2, y: 2 },
to: Point { x: 3, y: 3 },
from: Point { x: 2., y: 2. },
to: Point { x: 3., y: 3. },
};
assert!(!a.intersect(&b));
}
Expand Down
66 changes: 34 additions & 32 deletions rust/crates/tidy-tree/src/layout/basic_layout.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
use num::Float;

use super::Layout;
use crate::node::Node;
use crate::{geometry::Coord, node::Node};
use std::cmp::{max, min};

/// <img src="https://i.ibb.co/BLCfz0g/image.png" width="300" alt="Relative position"/>
///
/// Relative position illustration
pub struct BasicLayout {
pub parent_child_margin: isize,
pub peer_margin: isize,
pub parent_child_margin: Coord,
pub peer_margin: Coord,
}

/// <img src="https://i.ibb.co/BLCfz0g/image.png" width="300" alt="Relative position"/>
///
/// Relative position illustration
#[derive(Debug, Clone)]
pub struct BoundingBox {
pub total_width: isize,
pub total_height: isize,
pub relative_x: isize,
pub relative_y: isize,
pub total_width: Coord,
pub total_height: Coord,
pub relative_x: Coord,
pub relative_y: Coord,
}

impl Default for BoundingBox {
fn default() -> Self {
Self {
total_height: 0,
total_width: 0,
relative_x: 0,
relative_y: 0,
total_height: 0.,
total_width: 0.,
relative_x: 0.,
relative_y: 0.,
}
}
}
Expand All @@ -36,11 +38,11 @@ impl Layout for BasicLayout {
type Meta = BoundingBox;
fn layout(&mut self, root: &mut Node<Self::Meta>) {
root.post_order_traversal_mut(|node| {
self.update_children_meta(node);
self.update_meta(node);
});
root.pre_order_traversal_mut(|node| {
if let Some(mut parent) = node.parent {
let parent = unsafe { parent.as_mut() };
if let Some(parent) = node.parent {
let parent = unsafe { parent.as_ref() };
node.x = parent.x + node.meta.relative_x;
node.y = parent.y + node.meta.relative_y;
}
Expand All @@ -57,29 +59,29 @@ impl Layout for BasicLayout {
}

impl BasicLayout {
fn update_children_meta(&mut self, node: &mut Node<BoundingBox>) {
fn update_meta(&mut self, node: &mut Node<BoundingBox>) {
node.meta = BoundingBox {
total_height: node.height,
total_width: node.width,
relative_x: 0,
relative_y: 0,
relative_x: 0.,
relative_y: 0.,
};
let children: *mut _ = &mut node.children;
let children = unsafe { &mut *children };
let n = children.len() as isize;
if n > 0 {
let mut total_width: isize = 0;
let n = children.len() as Coord;
if n > 0. {
let mut total_width: Coord = 0.;
for child in children.iter() {
total_width += child.meta.total_width;
}
total_width += (n - 1) * self.peer_margin;
let mut relative_x = -total_width / 2;
let mut max_height = 0;
total_width += (n - 1.) * self.peer_margin;
let mut relative_x = -total_width / 2.;
let mut max_height = 0.;
for child in children.iter_mut() {
child.meta.relative_y = node.height + self.parent_child_margin;
child.meta.relative_x = relative_x + child.meta.total_width / 2;
child.meta.relative_x = relative_x + child.meta.total_width / 2.;
relative_x += child.meta.total_width + self.peer_margin;
max_height = max(child.meta.total_height, max_height);
max_height = Float::max(child.meta.total_height, max_height);
}

node.meta.total_width = total_width;
Expand All @@ -95,15 +97,15 @@ mod basic_layout_test {

#[test]
fn easy_test_0() {
let mut root = Node::<BoundingBox>::new(10, 10);
root.append_child(Node::new(10, 10));
let mut second = Node::new(10, 10);
second.append_child(Node::new(10, 10));
let mut root = Node::<BoundingBox>::new(10., 10.);
root.append_child(Node::new(10., 10.));
let mut second = Node::new(10., 10.);
second.append_child(Node::new(10., 10.));
root.append_child(second);
root.append_child(Node::new(10, 10));
root.append_child(Node::new(10., 10.));
let mut layout = BasicLayout {
parent_child_margin: 10,
peer_margin: 5,
parent_child_margin: 10.,
peer_margin: 5.,
};
layout.layout(&mut root);
println!("{:#?}", root);
Expand Down
Loading

0 comments on commit 558b5a2

Please sign in to comment.