glow/src/main.rs

835 lines
23 KiB
Rust

pub mod util;
use macroquad::prelude::DVec2;
use macroquad::prelude::Rect;
use macroquad::prelude::Camera2D;
use core::mem::swap;
use std::collections::HashMap;
use core::fmt;
use core::cell::Cell;
use std::collections::hash_map::Entry;
use macroquad::prelude::draw_circle_lines;
use core::f64::consts::PI;
use macroquad::prelude::mouse_position;
use macroquad::prelude::is_mouse_button_pressed;
use macroquad::prelude::Vec2;
use core::ops::DerefMut;
use core::ops::Deref;
use macroquad::prelude::draw_line;
use core::hash::Hasher;
use core::hash::Hash;
use macroquad::prelude::screen_height;
use macroquad::prelude::next_frame;
use macroquad::prelude::screen_width;
use macroquad::prelude::draw_circle;
use macroquad::prelude::clear_background;
use macroquad::prelude::Color;
use macroquad::input::MouseButton;
use std::sync::Arc;
const BG: Color = Color::new(0.16863, 0.23922, 0.21176, 1.0);
const FG: Color = Color::new(0.91569, 0.71765, 0.00000, 1.0);
const DIM_FG: Color = Color::new(0.29412, 0.27451, 0.13333, 1.0);
const HIL_FG: Color = Color::new(0.25806, 0.61290, 1.09032, 1.0);
const SPEED: f64 = 0.1;
const BOING_RADIUS: f64 = 30.0;
const HILITE: bool = false;
#[macroquad::main("BasicShapes")]
async fn main() {
let mut dd = DelaunayDemo::default();
loop {
if is_mouse_button_pressed(MouseButton::Left) {
dd.click(mouse_position().into())
}
if is_mouse_button_pressed(MouseButton::Right) {
let mouse_position: Vec2 = mouse_position().into();
println!("{}", mouse_position);
for triangle in &dd.triangles {
if triangle.invalidated_by_point(mouse_position.as_f64()) {
println!(
"{:?} has center {} with r={}",
triangle,
triangle.circumcenter().0,
triangle.circumcenter().1,
);
}
}
}
dd.update();
//dd.draw_delaunay();
dd.draw_voronoi();
next_frame().await;
}
}
pub struct DelaunayDemo {
pub nodes: Vec<NodeRef>,
pub triangles: Vec<Triangle>,
adjacency: HashMap<Edge, (NeighborOne, NeighborTwo)>,
poisoned: bool,
random_state: u128
}
#[derive(Debug)]
enum NeighborOne {
Occupant(Triangle),
Border,
}
#[derive(Debug)]
enum NeighborTwo {
Friend(Triangle),
Hole,
}
use NeighborOne::*;
use NeighborTwo::*;
impl From<Triangle> for NeighborOne {
fn from(triangle: Triangle) -> NeighborOne {
Occupant(triangle)
}
}
impl From<&Triangle> for NeighborOne {
fn from(triangle: &Triangle) -> NeighborOne {
triangle.clone().into()
}
}
impl From<Triangle> for NeighborTwo {
fn from(triangle: Triangle) -> NeighborTwo {
Friend(triangle)
}
}
impl From<&Triangle> for NeighborTwo {
fn from(triangle: &Triangle) -> NeighborTwo {
triangle.clone().into()
}
}
impl NeighborTwo {
fn unwrap_mut(&mut self) -> &mut Triangle {
if let Friend(triangle) = self {
triangle
} else {
panic!("Tried to unwrap a neighbor that wasn't a friend");
}
}
}
impl Default for DelaunayDemo {
fn default() -> Self {
let height = screen_height() as f64;
let width = screen_width() as f64;
let nodes: Vec<NodeRef> = vec![
Arc::new(Cell::new((-5.0 - BOING_RADIUS, 0.0 - BOING_RADIUS).into())),
Arc::new(Cell::new((0.0 - BOING_RADIUS, height + BOING_RADIUS).into())),
Arc::new(Cell::new((width + BOING_RADIUS, 0.0 - BOING_RADIUS).into())),
Arc::new(Cell::new((width + BOING_RADIUS, height + BOING_RADIUS).into())),
];
let edges = (
Edge(nodes[2].clone(), nodes[0].clone()),
Edge(nodes[0].clone(), nodes[1].clone()),
Edge(nodes[1].clone(), nodes[2].clone()),
Edge(nodes[2].clone(), nodes[3].clone()),
Edge(nodes[3].clone(), nodes[1].clone()),
);
let triangles = vec![
Triangle::new(
[edges.0.clone(), edges.1.clone(), edges.2.clone()],
),
Triangle::new(
[edges.2.clone(), edges.3.clone(), edges.4.clone()],
),
];
let adjacency = [
(edges.0, (Border, (&triangles[0]).into())),
(edges.1, (Border, (&triangles[0]).into())),
(edges.2, ((&triangles[0]).into(), (&triangles[1]).into())),
(edges.3, (Border, (&triangles[1]).into())),
(edges.4, (Border, (&triangles[1]).into())),
].into();
let mut dd = DelaunayDemo {
nodes, adjacency, triangles, random_state: 1312_1312_1312, poisoned: false,
};
/*let n_v_nodes = ((height / 50.0) - 1.0).round();
let v_inc = height / n_v_nodes;
for i in 0..(n_v_nodes as usize) {
println!("A");
let random = util::pcg64(&mut dd.random_state);
let offset = (random as f64) / (u64::MAX as f64) * 10.0;
dd.add_point((offset, (i + 1) as f64 * v_inc).into()).unwrap();
println!("B");
dd.add_point((width - offset, (i + 1) as f64 * v_inc).into()).unwrap();
}
let n_h_nodes = ((width / 50.0) - 1.0).round();
let h_inc = width / n_h_nodes;
for i in 0..(n_h_nodes as usize) {
println!("C");
let random = util::pcg64(&mut dd.random_state);
let offset = (random as f64) / (u64::MAX as f64) * 10.0;
dd.add_point(((i + 1) as f64 * h_inc, offset).into()).unwrap();
println!("D");
dd.add_point(((i + 1) as f64 * h_inc, height - offset).into()).unwrap();
}*/
dd
}
}
#[derive(Copy, Clone, Debug)]
pub struct Node(DVec2, DVec2);
impl Deref for Node {
type Target = DVec2;
fn deref(&self) -> &DVec2 {
&self.0
}
}
impl DerefMut for Node {
fn deref_mut(&mut self) -> &mut DVec2 {
&mut self.0
}
}
impl From<(f64, f64)> for Node {
fn from((x, y): (f64, f64)) -> Node {
Node(DVec2::new(x, y), DVec2::ZERO)
}
}
type NodeRef = Arc<Cell<Node>>;
#[derive(Clone)]
pub struct Edge(NodeRef, NodeRef);
impl PartialEq for Edge {
fn eq(&self, other: &Edge) -> bool {
let mut our_ptrs = [
Arc::as_ptr(&self.0),
Arc::as_ptr(&self.1),
];
let mut other_ptrs = [
Arc::as_ptr(&other.0),
Arc::as_ptr(&other.1),
];
our_ptrs.sort_unstable();
other_ptrs.sort_unstable();
our_ptrs[0] == other_ptrs[0] && our_ptrs[1] == other_ptrs[1]
}
}
impl Eq for Edge {}
impl Hash for Edge {
fn hash<H: Hasher>(&self, state: &mut H) {
let mut ptrs = [
Arc::as_ptr(&self.0),
Arc::as_ptr(&self.1),
];
ptrs.sort_unstable();
ptrs.hash(state);
}
}
impl fmt::Debug for Edge {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"Edge({},{} -> {},{})",
self.0.get().x,
self.0.get().y,
self.1.get().x,
self.1.get().y,
)
}
}
#[derive(Clone)]
pub struct Triangle {
nodes: [NodeRef; 3],
edges: [Edge; 3],
}
impl Triangle {
pub fn new(edges: [Edge; 3]) -> Triangle {
let nodes = [
edges[0].0.clone(),
edges[0].1.clone(),
if Arc::ptr_eq(&edges[1].0, &edges[0].0) || Arc::ptr_eq(&edges[1].0, &edges[0].1) {
edges[1].1.clone()
} else {
edges[1].0.clone()
}
];
Triangle {
nodes,
edges,
}
}
pub fn new_from_points(nodes: [NodeRef; 3]) -> Triangle {
let edges = [
Edge(nodes[0].clone(), nodes[1].clone()),
Edge(nodes[1].clone(), nodes[2].clone()),
Edge(nodes[2].clone(), nodes[0].clone()),
];
Triangle {
nodes,
edges,
}
}
pub fn circumcenter(&self) -> (DVec2, f64) {
Self::calc_circumcenter(*self.nodes[0].get(), *self.nodes[1].get(), *self.nodes[2].get())
}
fn calc_circumcenter(a: DVec2, b: DVec2, c: DVec2) -> (DVec2, f64) {
let len_a = b.distance(c);
let len_b = c.distance(a);
let len_c = a.distance(b);
let cos_a = (len_b.powf(2.0) + len_c.powf(2.0) - len_a.powf(2.0)) / (2.0 * len_b * len_c );
let cos_b = (len_c.powf(2.0) + len_a.powf(2.0) - len_b.powf(2.0)) / (2.0 * len_c * len_a );
let ang_a = f64::acos(cos_a);
let ang_b = f64::acos(cos_b);
let ang_c = PI - ang_a - ang_b;
let sin_2a = f64::sin(2.0 * ang_a);
let sin_2b = f64::sin(2.0 * ang_b);
let sin_2c = f64::sin(2.0 * ang_c);
let circumcenter = DVec2::new(
(a.x * sin_2a + b.x * sin_2b + c.x * sin_2c) / (sin_2a + sin_2b + sin_2c),
(a.y * sin_2a + b.y * sin_2b + c.y * sin_2c) / (sin_2a + sin_2b + sin_2c),
);
let radius = circumcenter.distance(a);
(circumcenter, radius)
}
pub fn invalidated_by_point(&self, point: DVec2) -> bool {
let (c, r) = self.circumcenter();
c.distance(point) < r
}
pub fn common_edge(&self, other: &Triangle) -> Result<&Edge, String> {
let common_edge = self.edges.iter()
.filter(|e| other.edges.contains(e))
.collect::<Vec<_>>();
if common_edge.len() > 1 {
Err(format!(
"Tried to call common_edge on two triangles which share more \
than one common edge?: {:?} and {:?}.",
self, other
))
} else if let Some(common_edge) = common_edge.first() {
Ok(common_edge)
} else {
Err(format!(
"Tried to call common_edge on two triangles which don't \
share a common edges: {:?} and {:?}.",
self, other
))
}
}
pub fn point_not_on(&self, edge: &Edge) -> Result<&NodeRef, String> {
self.nodes.iter()
.filter(|n|
!Arc::ptr_eq(n, &edge.0) &&
!Arc::ptr_eq(n, &edge.1)
)
.next()
.ok_or_else(||format!(
".point_not_on called on {:?} with edge {:?}, but no points were found \
not on this edge",
self, edge
))
}
pub fn invalidated_by_neighbor(&self, other: &Triangle) -> Result<bool, String> {
let common_edge = self.common_edge(other)?;
let self_point = self.point_not_on(common_edge)?;
let othr_point = other.point_not_on(common_edge)?;
let common_distance = common_edge.0.get().distance(*common_edge.1.get());
let self_sidea = common_edge.0.get().distance(*self_point.get());
let self_sideb = common_edge.1.get().distance(*self_point.get());
let othr_sidea = common_edge.0.get().distance(*othr_point.get());
let othr_sideb = common_edge.1.get().distance(*othr_point.get());
let self_angle = f64::acos(
(
self_sidea.powf(2.0)
+ self_sideb.powf(2.0)
- common_distance.powf(2.0)
) / (2.0 * self_sidea * self_sideb)
);
let othr_angle = f64::acos(
(
othr_sidea.powf(2.0)
+ othr_sideb.powf(2.0)
- common_distance.powf(2.0)
) / (2.0 * othr_sidea * othr_sideb)
);
return Ok(self_angle + othr_angle > PI)
}
}
impl PartialEq for Triangle {
fn eq(&self, other: &Triangle) -> bool {
let mut our_ptrs = [
Arc::as_ptr(&self.nodes[0]),
Arc::as_ptr(&self.nodes[1]),
Arc::as_ptr(&self.nodes[2]),
];
let mut other_ptrs = [
Arc::as_ptr(&other.nodes[0]),
Arc::as_ptr(&other.nodes[1]),
Arc::as_ptr(&other.nodes[2]),
];
our_ptrs.sort_unstable();
other_ptrs.sort_unstable();
our_ptrs[0] == other_ptrs[0] &&
our_ptrs[1] == other_ptrs[1] &&
our_ptrs[2] == other_ptrs[2]
}
}
impl Eq for Triangle {}
impl Hash for Triangle {
fn hash<H: Hasher>(&self, state: &mut H) {
let mut ptrs = [
Arc::as_ptr(&self.nodes[0]),
Arc::as_ptr(&self.nodes[1]),
Arc::as_ptr(&self.nodes[2]),
];
ptrs.sort_unstable();
ptrs.hash(state);
}
}
impl fmt::Debug for Triangle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let coords: Vec<_> = self.nodes.iter()
.flat_map(|n| [n.get().x, n.get().y])
.collect();
write!(
f,
"Triangle[({}, {}), ({}, {}), ({}, {}))",
coords[0],
coords[1],
coords[2],
coords[3],
coords[4],
coords[5],
)
}
}
impl DelaunayDemo {
fn draw_delaunay(&self) {
clear_background(BG);
let mut highlight_segments = Vec::new();
for triangle in &self.triangles {
let (c, r) = triangle.circumcenter();
let mpos: Vec2 = mouse_position().into();
let color = if c.distance(mpos.as_f64()) < r && HILITE {
highlight_segments.extend(&triangle.edges);
HIL_FG
} else {
DIM_FG
};
draw_circle_lines(c.x as f32, c.y as f32, r as f32, 1.0, color);
}
for edge in self.adjacency.keys() {
let color = if highlight_segments.contains(&edge) {
HIL_FG
} else {
FG
};
let edge_0 = edge.0.get().as_f32();
let edge_1 = edge.1.get().as_f32();
if
edge_0.x < 0.0 || edge_0.x > screen_width()
|| edge_0.y < 0.0 || edge_0.y > screen_height()
|| edge_1.x < 0.0 || edge_1.x > screen_width()
|| edge_1.y < 0.0 || edge_1.y > screen_height()
{
continue; //don't draw container nodes
}
draw_line(
edge_0.x,
edge_0.y,
edge_1.x,
edge_1.y,
3.0, color
);
}
for node in &self.nodes {
let pos = node.get().as_f32();
draw_circle(pos.x, pos.y, 10.0, FG);
}
}
fn draw_voronoi(&self) {
clear_background(BG);
for neighbors in self.adjacency.values() {
if let (Occupant(tri1), Friend(tri2)) = neighbors {
let (center1, _) = tri1.circumcenter();
let (center2, _) = tri2.circumcenter();
draw_line(
center1.x as f32,
center1.y as f32,
center2.x as f32,
center2.y as f32,
3.0, FG
);
}
}
}
fn update(&mut self) {
if self.poisoned {
return
}
for node in self.nodes.clone() {
if node.get().1 != DVec2::ZERO {
self.move_point(node);
}
}
if let Err(msg) = self.re_delaunize() {
eprintln!("POISONED: {}", msg);
self.poisoned = true;
}
}
fn click(&mut self, pos: Vec2) {
let random = util::pcg64(&mut self.random_state);
let angle = (random as f64) / (u64::MAX as f64) * (2.0 * std::f64::consts::PI);
let direction = DVec2::new(
f64::cos(angle),
f64::sin(angle),
);
if let Err(msg) = self.add_point(Node(pos.as_f64(), direction * SPEED)) {
self.poisoned = true;
eprintln!("POISONED: {}", msg);
}
}
fn add_point(&mut self, node: Node) -> Result<(), String> {
// Remove invalid triangles and coalesce their edges
let mut orphaned_edges: Vec<_> = Vec::with_capacity(self.triangles.len() * 3);
let mut i = 0;
while i < self.triangles.len() {
let triangle = &self.triangles[i];
if triangle.invalidated_by_point(*node) {
orphaned_edges.extend(
self.remove_triangle(i)?.edges
);
} else {
i = i + 1;
}
}
orphaned_edges.retain(|e| self.adjacency.contains_key(e));
// For every edge form a new triangle with that edge and this point
let node = Arc::new(Cell::new(node));
for edge in orphaned_edges {
self.create_triangle([
Edge(edge.0.clone(), node.clone()),
Edge(edge.1.clone(), node.clone()),
edge,
])?;
}
self.nodes.push(node);
Ok(())
}
fn remove_triangle(&mut self, index: usize) -> Result<Triangle, String> {
let triangle = self.triangles.remove(index);
for edge in &triangle.edges {
match self.adjacency.get_mut(edge) {
Some((Occupant(side1), side2 @ Friend(_))) => {
let side2_inner = side2.unwrap_mut();
if side1 == &triangle {
swap(side1, side2_inner);
} else if side2_inner != &triangle {
return Err(format!(
"{:?} does not contain triangle \
{:?}, but this triangle's list of edges includes this \
edge. Triangle was in the triangle index until now.",
edge, triangle
));
}
*side2 = Hole;
},
Some((Occupant(our_side), Hole)) => {
if our_side != &triangle {
return Err(format!(
"{:?} does not contain triangle \
{:?}, but this triangle's list of edges includes this \
edge. Triangle was in the triangle index until now.",
edge, triangle
));
}
self.adjacency.remove(&edge);
},
Some((Border, our_side @ Friend(_))) => {
*our_side = Hole;
},
Some((Border, Hole)) => {
return Err(format!(
"{:?} removed from graph, but it's edge {:?} is \
already marked as a border-hole edge", triangle, edge
));
}
None => {
return Err(format!(
"{:?} removed from graph, but it's edge {:?} was \
missing from adjacency graph", triangle, edge
));
},
}
}
Ok(triangle)
}
fn create_triangle(&mut self, edges: [Edge; 3]) -> Result<&Triangle, String> {
let triangle = Triangle::new(edges.clone());
for edge in edges {
match self.adjacency.entry(edge) {
Entry::Occupied(mut entry) => {
match entry.get_mut() {
(Occupant(tri1), Friend(tri2)) => {
let (tri1, tri2) = (tri1.clone(), tri2.clone());
return Err(format!(
"Tried to create a triangle with edge {:?}, \
but this edge is already in use by triangles {:?} and \
{:?}.",
entry.key(), tri1, tri2
));
},
(Border, Friend(tri)) => {
let tri = tri.clone();
return Err(format!(
"Tried to create a triangle with edge {:?}, \
but this edge is already in use by triangle {:?} and \
is a border.",
entry.key(), tri
));
},
(Occupant(_) | Border, new_home @ Hole) => {
*new_home = Friend(triangle.clone());
},
}
},
Entry::Vacant(entry) => {
entry.insert(((&triangle).into(), Hole));
}
}
}
self.triangles.push(triangle);
Ok(self.triangles.last().unwrap())
}
fn move_point(&mut self, node: NodeRef) {
// Update position
let mut node_inner = node.get();
node_inner.0 = node_inner.0 + node_inner.1;
// Check if it is going to hit another point
for other in &self.nodes {
if
!Arc::ptr_eq(other, &node)
&& node_inner.distance(other.get().0) < BOING_RADIUS
{
let mut node_inner = node.get();
let mut other_inner = other.get();
swap(&mut other_inner.1, &mut node_inner.1);
other.set(other_inner);
node.set(node_inner);
return;
}
}
// Check for a bounce
let height = screen_height() as f64;
let width = screen_width() as f64;
if node_inner.0.y > height {
node_inner.0.y = 2.0 * height - node_inner.0.y;
node_inner.1.y = -node_inner.1.y;
}
if node_inner.0.y < 0.0 {
node_inner.0.y = -node_inner.0.y;
node_inner.1.y = -node_inner.1.y;
}
if node_inner.0.x > width {
node_inner.0.x = 2.0 * width - node_inner.0.x;
node_inner.1.x = -node_inner.1.x;
}
if node_inner.0.x < 0.0 {
node_inner.0.x = -node_inner.0.x;
node_inner.1.x = -node_inner.1.x;
}
node.set(node_inner);
}
fn get_neighbors(&self, triangle: &Triangle) -> Result<Vec<&Triangle>, String> {
triangle.edges.iter()
.filter_map(|e|
match self.adjacency.get(e) {
Some((Occupant(a), Friend(b))) => {
if a != triangle && b == triangle {
Some(Ok(a))
} else if a == triangle && b != triangle {
Some(Ok(b))
} else if a == triangle && b == triangle {
Some(Err(format!(
"{:?} has {:?} in adjacency graph which lists itself as \
its own neighbor",
triangle, e
)))
} else {
Some(Err(format!(
"{:?} has {:?}, but the adjacency graph reports that the \
triangles next to this edge are {:?} and {:?}",
triangle, e, a, b
)))
}
},
Some((Border, Friend(tri))) => {
if tri == triangle {
None
} else {
Some(Err(format!(
"{:?} has {:?}, but the adjacency graph reports that \
this edge is an edge between the graph hull and {:?}",
triangle, e, tri
)))
}
},
Some((Occupant(tri), Hole)) => {
if tri == triangle {
None
} else {
Some(Err(format!(
"{:?} has {:?}, but the adjacency graph reports that \
this edge is an edge between a polygonal hole and {:?}",
triangle, e, tri
)))
}
},
Some((Border, Hole)) => {
Some(Err(format!(
"{:?} has {:?}, but the adjacency graph lists this edge as \
being between the graph hull and a polygonal hole (aka, it \
has no neighbors",
triangle, e
)))
},
None => {
Some(Err(format!(
"get_neighbors called on {:?}, but its edge {:?} is not \
present in the adjacency graph.",
triangle, e
)))
},
}
)
.collect()
}
fn flip_triangles(
&mut self,
tri1: &Triangle,
tri2: &Triangle
) -> Result<(Triangle, &Triangle), String> {
let mut indices = self.triangles.iter()
.enumerate()
.filter(|(_, t)| t == &tri1 || t == &tri2)
.map(|(i, _)| i);
let err = || format!(
"flip_triangles called on {:?} and {:?}, but not both of these were found in \
the list of triangles",
tri1, tri2
);
let mut indices = [
indices.next().ok_or_else(err)?,
indices.next().ok_or_else(err)?,
];
indices.sort_unstable();
let tri1 = self.remove_triangle(indices[1])?;
let tri2 = self.remove_triangle(indices[0])?;
let common_edge = tri1.common_edge(&tri2)?;
let tri1_point = tri1.point_not_on(common_edge)?;
let tri2_point = tri2.point_not_on(common_edge)?;
Ok((
self.create_triangle([
Edge(tri1_point.clone(), common_edge.0.clone()),
Edge(tri2_point.clone(), common_edge.0.clone()),
Edge(tri1_point.clone(), tri2_point.clone()),
])?.clone(),
self.create_triangle([
Edge(tri1_point.clone(), common_edge.1.clone()),
Edge(tri2_point.clone(), common_edge.1.clone()),
Edge(tri1_point.clone(), tri2_point.clone()),
])?,
))
}
fn re_delaunize(&mut self) -> Result<(), String> {
let mut i = 0;
while i < self.triangles.len() {
let triangle = &self.triangles[i];
let neighbors: Vec<_> = self.get_neighbors(triangle)?
.into_iter()
.cloned()
.collect();
let mut flipped = false;
for neighbor in neighbors {
if triangle.invalidated_by_neighbor(&neighbor)? {
let triangle = triangle.clone();
self.flip_triangles(&triangle, &neighbor)?;
i = 0;
flipped = true;
break;
}
}
if !flipped {
i = i + 1;
}
}
Ok(())
}
}