607 lines
15 KiB
Rust
607 lines
15 KiB
Rust
pub mod util;
|
|
|
|
use core::mem::swap;
|
|
use std::collections::HashMap;
|
|
use core::fmt;
|
|
use core::cell::Cell;
|
|
use std::collections::hash_map::Entry;
|
|
use core::f32::consts::PI;
|
|
use macroquad::prelude::draw_circle_lines;
|
|
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);
|
|
|
|
#[macroquad::main("BasicShapes")]
|
|
async fn main() {
|
|
let mut dd = DelaunayDemo::default();
|
|
loop {
|
|
if is_mouse_button_pressed(MouseButton::Left) {
|
|
dd.click(mouse_position().into())
|
|
}
|
|
dd.update();
|
|
dd.draw();
|
|
next_frame().await;
|
|
}
|
|
}
|
|
|
|
pub struct DelaunayDemo {
|
|
pub nodes: Vec<NodeRef>,
|
|
pub triangles: Vec<Triangle>,
|
|
adjacency: HashMap<Edge, (NeighborOne, NeighborTwo)>,
|
|
poisoned: bool,
|
|
random_state: u128
|
|
}
|
|
|
|
enum NeighborOne {
|
|
Occupant(Triangle),
|
|
Border,
|
|
}
|
|
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 nodes: Vec<NodeRef> = vec![
|
|
Arc::new(Cell::new((0.0, 0.0).into())),
|
|
Arc::new(Cell::new((0.0, screen_height()).into())),
|
|
Arc::new(Cell::new((screen_width(), 0.0).into())),
|
|
Arc::new(Cell::new((screen_width(), screen_height()).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();
|
|
DelaunayDemo {
|
|
nodes, adjacency, triangles, random_state: 1312_1312_1312, poisoned: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct Node(Vec2, Vec2);
|
|
|
|
impl Deref for Node {
|
|
type Target = Vec2;
|
|
|
|
fn deref(&self) -> &Vec2 {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl DerefMut for Node {
|
|
fn deref_mut(&mut self) -> &mut Vec2 {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
impl From<(f32, f32)> for Node {
|
|
fn from((x, y): (f32, f32)) -> Node {
|
|
Node(Vec2::new(x, y), Vec2::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) -> (Vec2, f32) {
|
|
Self::calc_circumcenter(*self.nodes[0].get(), *self.nodes[1].get(), *self.nodes[2].get())
|
|
}
|
|
|
|
fn calc_circumcenter(a: Vec2, b: Vec2, c: Vec2) -> (Vec2, f32) {
|
|
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 = f32::acos(cos_a);
|
|
let ang_b = f32::acos(cos_b);
|
|
let ang_c = PI - ang_a - ang_b;
|
|
|
|
let sin_2a = f32::sin(2.0 * ang_a);
|
|
let sin_2b = f32::sin(2.0 * ang_b);
|
|
let sin_2c = f32::sin(2.0 * ang_c);
|
|
|
|
let circumcenter = Vec2::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: Vec2) -> bool {
|
|
let (c, r) = self.circumcenter();
|
|
c.distance(point) < r
|
|
}
|
|
}
|
|
|
|
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(&self) {
|
|
clear_background(BG);
|
|
for triangle in &self.triangles {
|
|
let (c, r) = triangle.circumcenter();
|
|
draw_circle_lines(c.x, c.y, r, 1.0, DIM_FG);
|
|
}
|
|
for edge in self.adjacency.keys() {
|
|
draw_line(
|
|
edge.0.get().x,
|
|
edge.0.get().y,
|
|
edge.1.get().x,
|
|
edge.1.get().y,
|
|
3.0, FG
|
|
);
|
|
}
|
|
for node in &self.nodes {
|
|
draw_circle(node.get().x, node.get().y, 10.0, FG);
|
|
}
|
|
}
|
|
|
|
fn update(&mut self) {
|
|
for node in self.nodes.clone() {
|
|
if node.get().1 != Vec2::ZERO {
|
|
self.move_point(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = Vec2::new(
|
|
f64::cos(angle) as f32,
|
|
f64::sin(angle) as f32,
|
|
);
|
|
if let Err(msg) = self.add_point(Node(pos, direction * 2.0)) {
|
|
self.poisoned = true;
|
|
eprintln!("{}", msg);
|
|
}
|
|
}
|
|
|
|
fn add_point(&mut self, node: Node) -> Result<(), String> {
|
|
|
|
println!("Adding point {:?}", node);
|
|
|
|
// 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));
|
|
println!("Orphaned Edges: {:?}", orphaned_edges);
|
|
|
|
// 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 {
|
|
println!("Creating triangle with: {:?}", edge);
|
|
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) {
|
|
|
|
if self.poisoned {
|
|
return
|
|
}
|
|
|
|
/*
|
|
// Update position
|
|
let mut node_inner = node.get();
|
|
node_inner.0 = node_inner.0 + node_inner.1;
|
|
|
|
// Check for a bounce
|
|
if node_inner.0.y > screen_height() {
|
|
node_inner.0.y = 2.0 * screen_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 > screen_width() {
|
|
node_inner.0.x = 2.0 * screen_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);
|
|
*/
|
|
|
|
// Check for broken triangles
|
|
|
|
// Remove triange
|
|
|
|
// Remove triangle consisting of common points + self
|
|
|
|
// Form triangle consisting of common point A + self + opposite
|
|
|
|
// Form triangle consisting of common point B + self + opposite
|
|
|
|
/*
|
|
let mut i = 0;
|
|
let mut needs_rerun = false;
|
|
while i < self.triangles.len() {
|
|
if i == 0 {
|
|
needs_rerun = false;
|
|
}
|
|
let triangle = &self.triangles[i];
|
|
if !triangle.nodes.iter().any(|n| Arc::ptr_eq(n, &node)) &&
|
|
triangle.invalidated_by_point(*node_inner)
|
|
{
|
|
|
|
println!("{:?} invalidated by {:?}", triangle, node_inner);
|
|
|
|
let pair_triangle_i = self.triangles.iter()
|
|
.position(|t| {
|
|
t.nodes.iter()
|
|
.filter(|n| triangle.nodes
|
|
.iter()
|
|
.any(|n2| Arc::ptr_eq(n, n2))
|
|
)
|
|
.count() == 2
|
|
});
|
|
let pair_triangle_i = if let Some(i) = pair_triangle_i {
|
|
i
|
|
} else {
|
|
i = (i + 1) % self.triangles.len();
|
|
needs_rerun = true;
|
|
continue
|
|
};
|
|
// .expect("Invariant violated: All triangles invalidated by a moved \
|
|
// point have a pair triangle");
|
|
let pair_triangle = self.triangles.remove(pair_triangle_i);
|
|
let triangle = self.triangles.remove(i);
|
|
let common_edge = pair_triangle.edges.iter()
|
|
.filter(|e|
|
|
!Arc::ptr_eq(&e.0, &node) &&
|
|
!Arc::ptr_eq(&e.1, &node)
|
|
)
|
|
.next()
|
|
.expect("Invariant violated: Triangles must be a closed polygon");
|
|
|
|
let opposite_point = triangle.nodes.into_iter()
|
|
.filter(|n|
|
|
!Arc::ptr_eq(&common_edge.0, n) &&
|
|
!Arc::ptr_eq(&common_edge.1, n)
|
|
)
|
|
.next()
|
|
.expect("Invariant violated: Triangles must have three unique points");
|
|
let new_common_edge = Edge(node.clone(), opposite_point.clone());
|
|
self.edges.push(new_common_edge);
|
|
|
|
let common_edge_i = self.edges.iter()
|
|
.position(|e| e == common_edge)
|
|
.expect("Invariant violated: Triangle edges must all be in the \
|
|
master database");
|
|
let common_edge = self.edges.remove(common_edge_i);
|
|
|
|
self.triangles.extend([
|
|
Triangle::new_from_points([node.clone(), opposite_point.clone(), common_edge.0]),
|
|
Triangle::new_from_points([node.clone(), opposite_point, common_edge.1]),
|
|
]);
|
|
} else {
|
|
if needs_rerun {
|
|
i = (i + 1) % self.triangles.len();
|
|
} else {
|
|
i = (i + 1);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
}
|