draw connections
This commit is contained in:
parent
9faef57203
commit
88bb954676
5 changed files with 166 additions and 30 deletions
|
@ -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::<HashMap<_, _>>();
|
||||
|
||||
// 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.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AppState>) -> Json<Value> {
|
||||
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,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ export default function MapView({}) {
|
|||
<main className={styles.main}>
|
||||
<Canvas camera={{ position: [0, 20, 0] }}>
|
||||
<ambientLight />
|
||||
{/* <pointLight position={[0, 0, 0]} /> */}
|
||||
<MapControls />
|
||||
|
||||
<mesh>
|
||||
|
@ -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 <Box key={JSON.stringify([x, y])} position={[x, 0, y]} />;
|
||||
return <StarSystem key={point.id} position={[x, 0, y]} />;
|
||||
})}
|
||||
|
||||
{data.edges.map((edge) => {
|
||||
return (
|
||||
<Hyperlane
|
||||
key={`${edge.fromIndex}:${edge.toIndex}`}
|
||||
edge={edge}
|
||||
points={data.points}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Canvas>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<mesh
|
||||
{...props}
|
||||
|
@ -68,11 +70,39 @@ function Box({ position, ...props }: MeshProps) {
|
|||
onPointerOver={(_event) => setHover(true)}
|
||||
onPointerOut={(_event) => setHover(false)}
|
||||
>
|
||||
<sphereGeometry args={[0.5]} />
|
||||
<meshStandardMaterial
|
||||
color={hovered ? "hotpink" : "orange"}
|
||||
emissive={"white"}
|
||||
/>
|
||||
<sphereGeometry args={[0.05]} />
|
||||
<meshStandardMaterial color={hovered ? "white" : "skyblue"} />
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<mesh
|
||||
{...props}
|
||||
position={[avgX, 0, avgY]}
|
||||
rotation={[0, angle, Math.PI / 2]}
|
||||
>
|
||||
<cylinderGeometry args={[0.005, 0.005, length]} />
|
||||
<meshStandardMaterial color={"skyblue"} />
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ model StarSystem {
|
|||
universeId String
|
||||
universe Universe @relation(fields: [universeId], references: [id])
|
||||
|
||||
genIndex Int
|
||||
coordX Float
|
||||
coordY Float
|
||||
|
||||
|
@ -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])
|
||||
}
|
||||
|
|
|
@ -13,6 +13,12 @@ use anyhow::Result;
|
|||
pub struct TrianglulateOpts<P = Vec<Point>> {
|
||||
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<f64>,
|
||||
|
||||
/// Generates a Voronoi diagram
|
||||
#[builder(default)]
|
||||
voronoi: bool,
|
||||
|
@ -33,6 +39,9 @@ pub struct Point {
|
|||
#[derive(Debug)]
|
||||
pub struct TriangulateResult {
|
||||
pub point_list: Vec<Point>,
|
||||
|
||||
/// A list of triangles
|
||||
pub triangle_list: Vec<Vec<usize>>,
|
||||
pub voronoi_point_list: Vec<Point>,
|
||||
}
|
||||
|
||||
|
@ -41,14 +50,18 @@ where
|
|||
P: IntoIterator<Item = Point>,
|
||||
{
|
||||
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<Point> {
|
||||
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::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn triangle_list_from_flat_point_list(
|
||||
ptr: *mut i32,
|
||||
num_corners: usize,
|
||||
len: usize,
|
||||
) -> Vec<Vec<usize>> {
|
||||
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::<Vec<_>>()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue