Skip to content
2 changes: 1 addition & 1 deletion crates/ui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn Home() -> impl IntoView {
view! {
<PageLayout eyebrow="Station" title="ArkSync">
<p class="mt-3 max-w-xl text-sk-carbon-300">
"Centralisez les mesures, les alertes et les automatisations de votre station."
"Environmental monitoring and regulation system."
</p>
</PageLayout>
}
Expand Down
29 changes: 29 additions & 0 deletions crates/ui/src/components/grid/core/collision/aabb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#[derive(Clone, Copy, Debug)]
pub struct Aabb {
pub left: f64,
pub right: f64,
pub top: f64,
pub bottom: f64,
}

impl Aabb {
pub fn new(left: f64, top: f64, width: f64, height: f64) -> Self {
Self {
left,
right: left + width,
top,
bottom: top + height,
}
}

pub fn overlap(&self, other: &Self) -> Option<(f64, f64)> {
let width = self.right.min(other.right) - self.left.max(other.left);
let height = self.bottom.min(other.bottom) - self.top.max(other.top);

if width <= 0.0 || height <= 0.0 {
return None;
}

Some((width, height))
}
}
116 changes: 116 additions & 0 deletions crates/ui/src/components/grid/core/collision/grid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use crate::components::grid::core::collision::aabb::Aabb;
use crate::components::grid::core::item::GridItemData;
use ndarray::Array2;
use std::collections::HashSet;

pub fn item_ids_for_item(collision_grid: &Array2<Option<u32>>, item: &GridItemData) -> Vec<u32> {
let row_end = item.grid_pos.row_start + item.span.row_span;
let col_end = item.grid_pos.col_start + item.span.col_span;

collect_item_ids(
collision_grid,
item.grid_pos.row_start,
row_end,
item.grid_pos.col_start,
col_end,
item.id,
)
}

pub fn item_ids_for_aabb(
collision_grid: &Array2<Option<u32>>,
aabb: Aabb,
excluded_id: u32,
) -> Vec<u32> {
let row_start = aabb.top.floor().max(0.0) as usize;
let row_end = aabb.bottom.ceil().max(0.0) as usize;
let col_start = aabb.left.floor().max(0.0) as usize;
let col_end = aabb.right.ceil().max(0.0) as usize;

collect_item_ids(
collision_grid,
row_start,
row_end,
col_start,
col_end,
excluded_id,
)
}

pub fn item_fits_ignoring(
collision_grid: &Array2<Option<u32>>,
item: &GridItemData,
ignored_ids: &[u32],
) -> bool {
let ignored_ids = ignored_ids.iter().copied().collect::<HashSet<_>>();
let row_end = item.grid_pos.row_start + item.span.row_span;
let col_end = item.grid_pos.col_start + item.span.col_span;

for row_idx in item.grid_pos.row_start..row_end.min(collision_grid.nrows()) {
for col_idx in item.grid_pos.col_start..col_end.min(collision_grid.ncols()) {
if let Some(occupant_id) = collision_grid[[row_idx, col_idx]] {
if !ignored_ids.contains(&occupant_id) {
return false;
}
}
}
}

true
}

pub fn set_item(collision_grid: &mut Array2<Option<u32>>, item: &GridItemData) {
let row_start = item.grid_pos.row_start;
let row_end = row_start + item.span.row_span;
let col_start = item.grid_pos.col_start;
let col_end = col_start + item.span.col_span;

for row_idx in row_start..row_end {
for col_idx in col_start..col_end {
if row_idx < collision_grid.nrows() && col_idx < collision_grid.ncols() {
collision_grid[[row_idx, col_idx]] = Some(item.id);
}
}
}
}

pub fn clear_item(collision_grid: &mut Array2<Option<u32>>, item: &GridItemData) {
let row_start = item.grid_pos.row_start;
let row_end = row_start + item.span.row_span;
let col_start = item.grid_pos.col_start;
let col_end = col_start + item.span.col_span;

for row_idx in row_start..row_end {
for col_idx in col_start..col_end {
if row_idx < collision_grid.nrows()
&& col_idx < collision_grid.ncols()
&& collision_grid[[row_idx, col_idx]] == Some(item.id)
{
collision_grid[[row_idx, col_idx]] = None;
}
}
}
}

fn collect_item_ids(
collision_grid: &Array2<Option<u32>>,
row_start: usize,
row_end: usize,
col_start: usize,
col_end: usize,
excluded_id: u32,
) -> Vec<u32> {
let mut colliding_ids = HashSet::new();

for row_idx in row_start..row_end.min(collision_grid.nrows()) {
for col_idx in col_start..col_end.min(collision_grid.ncols()) {
if let Some(occupant_id) = collision_grid[[row_idx, col_idx]] {
if occupant_id != excluded_id {
colliding_ids.insert(occupant_id);
}
}
}
}

colliding_ids.into_iter().collect()
}
30 changes: 30 additions & 0 deletions crates/ui/src/components/grid/core/collision/item_aabb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::components::grid::core::collision::aabb::Aabb;
use crate::components::grid::core::item::GridItemData;
use crate::components::grid::core::size::Size;
use leptos_use::core::Position;

pub fn from_item(item: &GridItemData) -> Aabb {
Aabb::new(
item.grid_pos.col_start as f64,
item.grid_pos.row_start as f64,
item.span.col_span as f64,
item.span.row_span as f64,
)
}

pub fn from_drag(item: &GridItemData, drag_px_pos: Position, cell_size: Size) -> Aabb {
Aabb::new(
drag_px_pos.x / cell_size.width,
drag_px_pos.y / cell_size.height,
item.span.col_span as f64,
item.span.row_span as f64,
)
}

pub fn items_overlap(a: &GridItemData, b: &GridItemData) -> bool {
from_item(a).overlap(&from_item(b)).is_some()
}

pub fn overlap_item(aabb: Aabb, item: &GridItemData) -> Option<(f64, f64)> {
aabb.overlap(&from_item(item))
}
3 changes: 3 additions & 0 deletions crates/ui/src/components/grid/core/collision/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod aabb;
pub mod grid;
pub mod item_aabb;
Loading
Loading