From 88bb954676b16f184c37b5b60bd3ea8ad6737228 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Sat, 30 Dec 2023 02:36:34 -0500 Subject: [PATCH] draw connections --- backend/src/main.rs | 59 ++++++++++++++++++++++++++++++-- backend/src/routes/mod.rs | 21 ++++++++++-- frontend/src/routes/MapView.tsx | 60 ++++++++++++++++++++++++--------- prisma/schema.prisma | 7 ++-- triangle/src/lib.rs | 49 ++++++++++++++++++++++----- 5 files changed, 166 insertions(+), 30 deletions(-) diff --git a/backend/src/main.rs b/backend/src/main.rs index 8cad709..8746638 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -6,7 +6,7 @@ pub mod prisma; mod routes; pub mod state; -use std::{f64::consts::PI, sync::Arc}; +use std::{collections::HashMap, f64::consts::PI, sync::Arc}; use anyhow::Result; use axum::{routing::get, Router}; @@ -16,7 +16,7 @@ use prisma_client_rust::serde_json::json; use routes::{universe_list, universe_map}; use triangle::{triangulate, Point, TrianglulateOpts}; -use crate::prisma::star_system; +use crate::prisma::{star_system, star_system_edges}; #[derive(Debug, Parser)] struct Opt { @@ -73,6 +73,7 @@ async fn main() -> Result<()> { TrianglulateOpts::builder() .point_list(point_list) .voronoi(true) + .maximum_triangle_area(4000.0) .build()?, )? }; @@ -87,9 +88,11 @@ async fn main() -> Result<()> { result .point_list .into_iter() - .map(|point| { + .enumerate() + .map(|(idx, point)| { star_system::create_unchecked( universe.id.clone(), + idx as i32, point.x, point.y, vec![], @@ -100,6 +103,56 @@ async fn main() -> Result<()> { .exec() .await?; + // Get the idx -> star system id mapping + let star_system_map = client + .star_system() + .find_many(vec![]) + .select(star_system::select!({ id gen_index })) + .exec() + .await? + .into_iter() + .map(|star_system| (star_system.gen_index as usize, star_system.id)) + .collect::>(); + + // Insert edges into database + macro_rules! create_edge { + ($from:expr, $to:expr) => {{ + println!("WTF? {}, {}", $from, $to); + star_system_edges::create_unchecked( + universe.id.clone(), + star_system_map.get(&$from).unwrap().to_owned(), + $from as i32, + star_system_map.get(&$to).unwrap().to_owned(), + $to as i32, + vec![], + ) + }}; + } + client + .star_system_edges() + .create_many( + result + .triangle_list + .into_iter() + .flat_map(|points| { + let a = points[0]; + let b = points[1]; + let c = points[2]; + [ + create_edge!(a, b), + create_edge!(a, c), + create_edge!(b, a), + create_edge!(b, c), + create_edge!(c, a), + create_edge!(c, b), + ] + }) + .collect(), + ) + .skip_duplicates() + .exec() + .await?; + println!("Done."); } } diff --git a/backend/src/routes/mod.rs b/backend/src/routes/mod.rs index 3d8f764..8f8041c 100644 --- a/backend/src/routes/mod.rs +++ b/backend/src/routes/mod.rs @@ -2,9 +2,13 @@ use axum::{ extract::{Path, State}, Json, }; +use prisma_client_rust::Direction; use serde_json::Value; -use crate::{prisma::star_system, AppState}; +use crate::{ + prisma::{star_system, star_system_edges}, + AppState, +}; pub async fn universe_list(state: State) -> Json { let universes = state @@ -30,12 +34,25 @@ pub async fn universe_map( .prisma .star_system() .find_many(vec![star_system::universe_id::equals(universe_id.clone())]) - .select(star_system::select!({ coord_x coord_y })) + .order_by(star_system::gen_index::order(Direction::Asc)) + .select(star_system::select!({ id coord_x coord_y })) + .exec() + .await + .unwrap(); + + let edges = state + .prisma + .star_system_edges() + .find_many(vec![star_system_edges::universe_id::equals( + universe_id.clone(), + )]) + .select(star_system_edges::select!({ from_system_id to_system_id from_index to_index })) .exec() .await .unwrap(); Json(json!({ "points": points, + "edges": edges, })) } diff --git a/frontend/src/routes/MapView.tsx b/frontend/src/routes/MapView.tsx index a50e7e7..f3d46ea 100644 --- a/frontend/src/routes/MapView.tsx +++ b/frontend/src/routes/MapView.tsx @@ -28,7 +28,6 @@ export default function MapView({}) {
- {/* */} @@ -39,25 +38,28 @@ export default function MapView({}) { {data.points.map((point) => { const x = point.coordX / 80; const y = point.coordY / 80; - console.log("point", x, y); - return ; + return ; + })} + + {data.edges.map((edge) => { + return ( + + ); })}
); } -function Box({ position, ...props }: MeshProps) { +function StarSystem({ position, ...props }: MeshProps) { const meshRef = useRef(); const [hovered, setHover] = useState(false); const [active, setActive] = useState(false); - // Subscribe this component to the render-loop, rotate the mesh every frame - useFrame((_state, delta) => { - meshRef.current.rotation.x += delta; - }); - - // Return view, these are regular three.js elements expressed in JSX return ( setHover(true)} onPointerOut={(_event) => setHover(false)} > - - + + + + ); +} + +function Hyperlane({ edge, points, ...props }) { + const fromPoint = points[edge.fromIndex]; + const toPoint = points[edge.toIndex]; + + const avgX = (fromPoint.coordX + toPoint.coordX) / 160; + const avgY = (fromPoint.coordY + toPoint.coordY) / 160; + + const length = Math.sqrt( + ((fromPoint.coordX - toPoint.coordX) / 80) ** 2 + + ((fromPoint.coordY - toPoint.coordY) / 80) ** 2, + ); + + const angle = + Math.PI - + Math.atan2( + toPoint.coordY - fromPoint.coordY, + toPoint.coordX - fromPoint.coordX, + ); + + return ( + + + ); } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d220d22..c25b7a7 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -59,8 +59,9 @@ model StarSystem { universeId String universe Universe @relation(fields: [universeId], references: [id]) - coordX Float - coordY Float + genIndex Int + coordX Float + coordY Float inbound StarSystemEdges[] @relation("inbound") outbound StarSystemEdges[] @relation("outbound") @@ -72,9 +73,11 @@ model StarSystemEdges { fromSystemId String from StarSystem @relation(fields: [fromSystemId], references: [id], name: "outbound") + fromIndex Int toSystemId String to StarSystem @relation(fields: [toSystemId], references: [id], name: "inbound") + toIndex Int @@id([universeId, fromSystemId, toSystemId]) } diff --git a/triangle/src/lib.rs b/triangle/src/lib.rs index e67b69f..30556c0 100644 --- a/triangle/src/lib.rs +++ b/triangle/src/lib.rs @@ -13,6 +13,12 @@ use anyhow::Result; pub struct TrianglulateOpts

> { point_list: P, + /// Imposes a maximum triangle area constraint. A fixed area constraint (that + /// applies to every triangle) may be specified after the `a', or varying area + /// constraints may be read from a .poly file or .area file. + #[builder(default, setter(strip_option))] + maximum_triangle_area: Option, + /// Generates a Voronoi diagram #[builder(default)] voronoi: bool, @@ -33,6 +39,9 @@ pub struct Point { #[derive(Debug)] pub struct TriangulateResult { pub point_list: Vec, + + /// A list of triangles + pub triangle_list: Vec>, pub voronoi_point_list: Vec, } @@ -41,14 +50,18 @@ where P: IntoIterator, { let mut switches = Vec::new(); - switches.push("p"); - switches.push("c"); - switches.push("z"); - switches.push("A"); - switches.push("e"); - switches.push("n"); + switches.push("p".to_owned()); + switches.push("c".to_owned()); + switches.push("z".to_owned()); + switches.push("A".to_owned()); + if let Some(maximum_triangle_area) = opts.maximum_triangle_area { + switches.push(format!("a{maximum_triangle_area}")); + } + switches.push("q".to_owned()); + switches.push("e".to_owned()); + switches.push("n".to_owned()); if opts.voronoi { - switches.push("v"); + switches.push("v".to_owned()); } let switches = CString::new(switches.join(""))?; @@ -92,6 +105,13 @@ where output.numberofpoints as usize * 2, ); + let triangle_list = triangle_list_from_flat_point_list( + output.trianglelist, + output.numberofcorners as usize, + output.numberoftriangles as usize * output.numberofcorners as usize, + ); + println!("aa {}", triangle_list.len()); + let voronoi_point_list = point_list_from_flat_point_list( vorout.pointlist, vorout.numberofpoints as usize * 2, @@ -99,6 +119,7 @@ where Ok(TriangulateResult { point_list, + triangle_list, voronoi_point_list, }) } @@ -106,10 +127,22 @@ where fn point_list_from_flat_point_list(ptr: *mut f64, len: usize) -> Vec { let flat_point_list = unsafe { Vec::from_raw_parts(ptr, len, len) }; flat_point_list - .chunks(2) + .chunks_exact(2) .map(|points| Point { x: points[0], y: points[1], }) .collect::>() } + +fn triangle_list_from_flat_point_list( + ptr: *mut i32, + num_corners: usize, + len: usize, +) -> Vec> { + let flat_point_list = unsafe { Vec::from_raw_parts(ptr, len, len) }; + flat_point_list + .chunks_exact(num_corners) + .map(|points| points.iter().map(|point| *point as usize).collect()) + .collect::>() +}