render some circles

This commit is contained in:
Michael Zhang 2023-12-29 19:46:18 -05:00
parent 6050903c09
commit 936417a88d
14 changed files with 431 additions and 53 deletions

103
Cargo.lock generated
View file

@ -74,6 +74,54 @@ dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
]
[[package]]
name = "anyhow"
version = "1.0.76"
@ -203,9 +251,12 @@ dependencies = [
"anyhow",
"axum",
"chrono",
"clap",
"prisma-client-rust",
"serde",
"serde_json",
"tokio",
"triangle",
]
[[package]]
@ -517,6 +568,46 @@ dependencies = [
"libloading",
]
[[package]]
name = "clap"
version = "4.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"syn 2.0.43",
]
[[package]]
name = "clap_lex"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "cmake"
version = "0.1.50"
@ -526,6 +617,12 @@ dependencies = [
"cc",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "colored"
version = "2.1.0"
@ -4993,6 +5090,12 @@ dependencies = [
"user-facing-error-macros",
]
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.6.1"

View file

@ -4,9 +4,13 @@ version = "0.1.0"
edition = "2021"
[dependencies]
triangle = { path = "../triangle" }
anyhow = "1.0.76"
axum = { version = "0.7.2", features = ["http2"] }
chrono = "0.4.31"
clap = { version = "4.4.11", features = ["derive"] }
prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust", tag = "0.6.10" }
serde = { version = "1.0.193", features = ["derive"] }
tokio = { version = "1.35.1", features = ["full"] }
serde_json = "1.0.108"

View file

@ -1,19 +1,105 @@
#[macro_use]
extern crate serde_json;
#[allow(unused_imports, dead_code)]
pub mod prisma;
mod routes;
pub mod state;
use std::{f64::consts::PI, sync::Arc};
use anyhow::Result;
use axum::{routing::get, Router};
use clap::{Parser, Subcommand};
use prisma::PrismaClient;
use prisma_client_rust::serde_json::json;
use routes::{universe_list, universe_map};
use triangle::{triangulate, Point, TrianglulateOpts};
use crate::prisma::star_system;
#[derive(Debug, Parser)]
struct Opt {
#[clap(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
Run,
Seed,
}
#[derive(Clone)]
struct AppState {
prisma: Arc<PrismaClient>,
}
#[tokio::main]
async fn main() -> Result<()> {
let opt = Opt::parse();
let client = PrismaClient::_builder().build().await?;
let client = Arc::new(client);
let state = AppState {
prisma: client.clone(),
};
let app = Router::new().route("/", get(|| async { "Hello, World!" }));
match opt.command {
Command::Run => {
let app = Router::new()
.route("/", get(|| async { "Hello, World!" }))
.route("/universe", get(universe_list))
.route("/universe/:universe_id/map", get(universe_map))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:1440").await?;
axum::serve(listener, app).await?;
}
let listener = tokio::net::TcpListener::bind("0.0.0.0:1440").await?;
axum::serve(listener, app).await?;
Command::Seed => {
// Generate a new triangulation
let result = {
// Generate a circle of points
let radius = 50.0;
const NUM_POINTS: usize = 30;
let point_list = (0..NUM_POINTS)
.map(|n| n as f64 * (2.0 * PI) / NUM_POINTS as f64)
.map(|theta| Point {
x: radius * theta.cos(),
y: radius * theta.sin(),
});
triangulate(
TrianglulateOpts::builder().point_list(point_list).build()?,
)?
};
println!("Result: {result:?}");
// Insert into database
let universe = client.universe().create(json!({}), vec![]).exec().await?;
client
.star_system()
.create_many(
result
.point_list
.into_iter()
.map(|point| {
star_system::create_unchecked(
universe.id.clone(),
point.x as i32,
point.y as i32,
vec![],
)
})
.collect(),
)
.exec()
.await?;
println!("Done.");
}
}
Ok(())
}

40
backend/src/routes/mod.rs Normal file
View file

@ -0,0 +1,40 @@
use axum::{
extract::{Path, State},
Json,
};
use serde_json::Value;
use crate::{prisma::star_system, AppState};
pub async fn universe_list(state: State<AppState>) -> Json<Value> {
let universes = state
.prisma
.universe()
.find_many(vec![])
.exec()
.await
.unwrap();
Json(json!({
"universes": universes,
}))
}
pub async fn universe_map(
Path((universe_id,)): Path<(String,)>,
state: State<AppState>,
) -> Json<Value> {
println!("universe id {universe_id}");
let points = state
.prisma
.star_system()
.find_many(vec![star_system::universe_id::equals(universe_id.clone())])
.exec()
.await
.unwrap();
Json(json!({
"points": points,
}))
}

View file

@ -9,6 +9,9 @@
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"prisma": {
"seed": "cargo run -p seeder"
},
"dependencies": {
"@blueprintjs/core": "^5.7.2",
"@blueprintjs/icons": "^5.5.0",
@ -18,6 +21,7 @@
"normalize.css": "^8.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-query": "^3.39.3",
"react-router-dom": "^6.21.1",
"three": "^0.160.0"
},

View file

@ -29,6 +29,9 @@ dependencies:
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-query:
specifier: ^3.39.3
version: 3.39.3(react-dom@18.2.0)(react@18.2.0)
react-router-dom:
specifier: ^6.21.1
version: 6.21.1(react-dom@18.2.0)(react@18.2.0)
@ -971,12 +974,16 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/big-integer@1.6.52:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
engines: {node: '>=0.6'}
dev: false
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@ -987,7 +994,6 @@ packages:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: true
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
@ -1002,6 +1008,19 @@ packages:
fill-range: 7.0.1
dev: true
/broadcast-channel@3.7.0:
resolution: {integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==}
dependencies:
'@babel/runtime': 7.23.7
detect-node: 2.1.0
js-sha3: 0.8.0
microseconds: 0.2.0
nano-time: 1.0.0
oblivious-set: 1.0.0
rimraf: 3.0.2
unload: 2.2.0
dev: false
/buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
dependencies:
@ -1086,7 +1105,6 @@ packages:
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/constant-case@3.0.4:
resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
@ -1128,6 +1146,10 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
/detect-node@2.1.0:
resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
dev: false
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@ -1372,7 +1394,6 @@ packages:
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
/fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
@ -1405,7 +1426,6 @@ packages:
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
dev: true
/globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
@ -1473,11 +1493,9 @@ packages:
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: true
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
@ -1521,6 +1539,10 @@ packages:
react: 18.2.0
dev: false
/js-sha3@0.8.0:
resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
dev: false
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: false
@ -1589,6 +1611,13 @@ packages:
yallist: 4.0.0
dev: true
/match-sorter@6.3.1:
resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==}
dependencies:
'@babel/runtime': 7.23.7
remove-accents: 0.4.2
dev: false
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@ -1606,11 +1635,14 @@ packages:
picomatch: 2.3.1
dev: true
/microseconds@0.2.0:
resolution: {integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==}
dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
dev: true
/minimatch@9.0.3:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
@ -1623,6 +1655,12 @@ packages:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
/nano-time@1.0.0:
resolution: {integrity: sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==}
dependencies:
big-integer: 1.6.52
dev: false
/nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@ -1654,11 +1692,14 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
/oblivious-set@1.0.0:
resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==}
dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
/optionator@0.9.3:
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
@ -1722,7 +1763,6 @@ packages:
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
dev: true
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
@ -1816,6 +1856,25 @@ packages:
warning: 4.0.3
dev: false
/react-query@3.39.3(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: '*'
react-native: '*'
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
dependencies:
'@babel/runtime': 7.23.7
broadcast-channel: 3.7.0
match-sorter: 6.3.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/react-reconciler@0.27.0(react@18.2.0):
resolution: {integrity: sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==}
engines: {node: '>=0.10.0'}
@ -1893,6 +1952,10 @@ packages:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
dev: false
/remove-accents@0.4.2:
resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==}
dev: false
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@ -1908,7 +1971,6 @@ packages:
hasBin: true
dependencies:
glob: 7.2.3
dev: true
/rollup@4.9.1:
resolution: {integrity: sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==}
@ -2077,6 +2139,13 @@ packages:
hasBin: true
dev: true
/unload@2.2.0:
resolution: {integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==}
dependencies:
'@babel/runtime': 7.23.7
detect-node: 2.1.0
dev: false
/upper-case-first@2.0.2:
resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
dependencies:
@ -2147,7 +2216,6 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}

View file

@ -9,7 +9,7 @@ html,body,#root {
}
#root > main {
flex-shrink: 1;
min-height: 0;
flex-shrink: 1;
flex-grow: 1;
}

View file

@ -1,11 +1,17 @@
import "./App.css";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { QueryClient, QueryClientProvider } from "react-query";
import "./App.css";
import routes from "./routes";
const router = createBrowserRouter(routes);
const queryClient = new QueryClient();
function App() {
return <RouterProvider router={router} />;
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
</QueryClientProvider>
);
}
export default App;

View file

@ -1,22 +1,37 @@
import { Outlet, Link } from "react-router-dom";
import { Outlet, Link, useParams } from "react-router-dom";
import { Alignment, Icon, Navbar } from "@blueprintjs/core";
export default function Layout() {
const { universeId } = useParams();
return (
<>
<Navbar>
<Navbar.Group align={Alignment.LEFT}>
<Navbar.Heading>OpenStellaris</Navbar.Heading>
<Navbar.Heading>
<Link to="/">OpenStellaris</Link>
</Navbar.Heading>
<Navbar.Divider />
<Link className="bp5-button bp5-minimal" role="button" to="/">
<Icon icon="path-search" />
Map
</Link>
<Link className="bp5-button bp5-minimal" role="button" to="/planets">
<Icon icon="panel-table" />
Planets
</Link>
{universeId && (
<>
<Link
className="bp5-button bp5-minimal"
role="button"
to={`/universe/${universeId}`}
>
<Icon icon="home" />
{universeId}
</Link>
<Link
className="bp5-button bp5-minimal"
role="button"
to={`/universe/${universeId}/planets`}
>
<Icon icon="panel-table" />
Planets
</Link>
</>
)}
</Navbar.Group>
</Navbar>

View file

@ -0,0 +1,23 @@
import { useQuery } from "react-query";
import { Link } from "react-router-dom";
export default function HomeView() {
const { isLoading, data } = useQuery("universe list", () =>
fetch("/api/universe").then((res) => res.json()),
);
if (isLoading) return <>...</>;
return (
<>
<ul>
{data.universes.map((universe) => (
<li key={universe.id}>
<Link to={`/universe/${universe.id}`}>Go to universe</Link>{" "}
{JSON.stringify(universe)}
</li>
))}
</ul>
</>
);
}

View file

@ -1,28 +1,46 @@
import { useRef, useState } from "react";
import { useQuery } from "react-query";
import { Canvas, useFrame, type MeshProps } from "@react-three/fiber";
import styles from "./MapView.module.scss";
import { useParams } from "react-router-dom";
export default function MapView({}) {
const { universeId } = useParams();
const { isLoading, data } = useQuery(`universe ${universeId} points`, () =>
fetch(`/api/universe/${universeId}/map`).then((res) => res.json()),
);
if (isLoading) return <>...</>;
console.log("data", data);
export default function MapView() {
return (
<main className={styles.main}>
<Canvas>
<Canvas camera={{ position: [0, 20, 0] }}>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
<pointLight position={[0, 0, 0]} />
{data.points.map((point) => {
console.log("point", point);
return (
<Box
key={JSON.stringify([point.coordX, point.coordY])}
position={[point.coordX / 5.0, 0, point.coordY / 5.0]}
/>
);
})}
</Canvas>
</main>
);
}
function Box(props: MeshProps) {
// This reference will give us direct access to the mesh
const meshRef = useRef();
// Set up state for the hovered and active state
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));
useFrame((_state, delta) => {
meshRef.current.rotation.x += delta;
});
// Return view, these are regular three.js elements expressed in JSX
return (
<mesh
@ -33,7 +51,7 @@ function Box(props: MeshProps) {
onPointerOver={(_event) => setHover(true)}
onPointerOut={(_event) => setHover(false)}
>
<boxGeometry args={[1, 1, 1]} />
<sphereGeometry args={[0.5]} />
<meshStandardMaterial color={hovered ? "hotpink" : "orange"} />
</mesh>
);

View file

@ -2,6 +2,7 @@ import type { RouteObject } from "react-router-dom";
import Layout from "../Layout";
import MapView from "./MapView";
import PlanetsView from "./PlanetsView";
import HomeView from "./HomeView";
const routes: RouteObject[] = [
{
@ -9,12 +10,21 @@ const routes: RouteObject[] = [
element: <Layout />,
children: [
{
path: "/",
element: <MapView />,
path: "",
element: <HomeView />,
},
{
path: "/planets",
element: <PlanetsView />,
path: "universe/:universeId",
children: [
{
path: "",
element: <MapView />,
},
{
path: "planets",
element: <PlanetsView />,
},
],
},
],
},

View file

@ -1,10 +1,5 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
// Corresponds to the cargo alias created earlier
provider = "cargo prisma"
// The location to generate the client. Is relative to the position of the schema
output = "../backend/src/prisma.rs"
}

View file

@ -10,7 +10,7 @@ use std::{ffi::CString, mem::MaybeUninit, ptr};
use anyhow::Result;
#[derive(Builder)]
pub struct TrianglulateOpts<P> {
pub struct TrianglulateOpts<P = Vec<Point>> {
point_list: P,
/// Generates a Voronoi diagram
@ -26,8 +26,8 @@ impl<P: Clone> TrianglulateOpts<P> {
#[derive(Clone, Copy, Debug)]
pub struct Point {
x: f64,
y: f64,
pub x: f64,
pub y: f64,
}
#[derive(Debug)]
@ -53,27 +53,33 @@ where
.flat_map(|point| [point.x, point.y])
.collect::<Vec<_>>();
let input = MaybeUninit::<sys::triangulateio>::uninit();
let output = MaybeUninit::<sys::triangulateio>::uninit();
let mut vorout = ptr::null::<sys::triangulateio>();
let input = MaybeUninit::<sys::triangulateio>::zeroed();
let output = MaybeUninit::<sys::triangulateio>::zeroed();
let vorout = MaybeUninit::<sys::triangulateio>::zeroed();
let mut input = unsafe { input.assume_init() };
let mut output = unsafe { output.assume_init() };
let mut vorout = unsafe { vorout.assume_init() };
input.pointlist = flat_point_list.as_mut_ptr();
input.numberofpoints = point_list.len() as i32;
// TODO: Implement point attributes
input.numberofpointattributes = 0;
println!("Going to triangulate...");
unsafe {
sys::triangulate(
switches.as_ptr() as *mut _,
&mut input as *mut _,
&mut output as *mut _,
vorout as *mut _,
&mut vorout as *mut _,
)
};
println!("Triangulated.");
let flat_point_list = unsafe {
Vec::from_raw_parts(
output.pointlist,