mirror of https://codeberg.org/topola/topola.git
Keep track of primitive id associated with navpolygon
This commit is contained in:
parent
4afd0d7e3d
commit
965080b8db
|
|
@ -187,6 +187,7 @@ impl Displayer {
|
||||||
if workspace.appearance_panel.visible[layer] {
|
if workspace.appearance_panel.visible[layer] {
|
||||||
for navmesh in workspace.navmesher_board.navmesher().layers()[layer].navmeshes() {
|
for navmesh in workspace.navmesher_board.navmesher().layers()[layer].navmeshes() {
|
||||||
for edge_geom in navmesh
|
for edge_geom in navmesh
|
||||||
|
.triangulator()
|
||||||
.triangulation()
|
.triangulation()
|
||||||
.rtreed_dcel()
|
.rtreed_dcel()
|
||||||
.edges_rtree()
|
.edges_rtree()
|
||||||
|
|
@ -194,17 +195,20 @@ impl Displayer {
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
let (from_vertex, to_vertex) = navmesh
|
let (from_vertex, to_vertex) = navmesh
|
||||||
|
.triangulator()
|
||||||
.triangulation()
|
.triangulation()
|
||||||
.rtreed_dcel()
|
.rtreed_dcel()
|
||||||
.dcel()
|
.dcel()
|
||||||
.edge_endpoints(edge_geom.data);
|
.edge_endpoints(edge_geom.data);
|
||||||
let from = navmesh
|
let from = navmesh
|
||||||
|
.triangulator()
|
||||||
.triangulation()
|
.triangulation()
|
||||||
.rtreed_dcel()
|
.rtreed_dcel()
|
||||||
.dcel()
|
.dcel()
|
||||||
.vertex_weight(from_vertex)
|
.vertex_weight(from_vertex)
|
||||||
.position();
|
.position();
|
||||||
let to = navmesh
|
let to = navmesh
|
||||||
|
.triangulator()
|
||||||
.triangulation()
|
.triangulation()
|
||||||
.rtreed_dcel()
|
.rtreed_dcel()
|
||||||
.dcel()
|
.dcel()
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bimap = "0.6"
|
bimap = "0.6"
|
||||||
dearcut = { version = "0.1", features = ["undoredo"] }
|
dearcut = { version = "0.2", features = ["undoredo"] }
|
||||||
derive-getters.workspace = true
|
derive-getters.workspace = true
|
||||||
derive_more.workspace = true
|
derive_more.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
mod board;
|
mod board;
|
||||||
mod layout;
|
mod layout;
|
||||||
mod math;
|
mod math;
|
||||||
|
mod navmesh;
|
||||||
mod navmesher;
|
mod navmesher;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
mod selection;
|
mod selection;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 Topola contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
use dearcut::RecordingTriangulator;
|
||||||
|
use derive_getters::Getters;
|
||||||
|
|
||||||
|
use crate::primitives::PrimitiveId;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Getters)]
|
||||||
|
pub struct Navmesh {
|
||||||
|
boundary: Vec<[i64; 2]>,
|
||||||
|
triangulator: RecordingTriangulator<i64>,
|
||||||
|
navpolygon_primitives: Vec<PrimitiveId>,
|
||||||
|
inflation_factor: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Navmesh {
|
||||||
|
pub fn new(boundary: impl IntoIterator<Item = [i64; 2]>) -> Self {
|
||||||
|
Self {
|
||||||
|
boundary: boundary.into_iter().collect(),
|
||||||
|
triangulator: RecordingTriangulator::new(),
|
||||||
|
navpolygon_primitives: Vec::new(),
|
||||||
|
inflation_factor: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_polygon(
|
||||||
|
&mut self,
|
||||||
|
primitive_id: PrimitiveId,
|
||||||
|
polygon: impl IntoIterator<Item = [i64; 2]>,
|
||||||
|
) {
|
||||||
|
let navpolygon_index = self.triangulator.insert_polygon_and_rebuild(
|
||||||
|
Self::inflate_polygon(polygon, self.inflation_factor),
|
||||||
|
self.boundary.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.navpolygon_primitives
|
||||||
|
.resize(navpolygon_index + 1, primitive_id);
|
||||||
|
self.navpolygon_primitives[navpolygon_index] = primitive_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inflate_polygon(
|
||||||
|
polygon: impl IntoIterator<Item = [i64; 2]>,
|
||||||
|
inflation_factor: f64,
|
||||||
|
) -> impl IntoIterator<Item = [i64; 2]> {
|
||||||
|
let polygon: Vec<[i64; 2]> = polygon.into_iter().collect();
|
||||||
|
|
||||||
|
// Centroid.
|
||||||
|
let cx = polygon.iter().map(|p| p[0] as f64).sum::<f64>() / polygon.len() as f64;
|
||||||
|
let cy = polygon.iter().map(|p| p[1] as f64).sum::<f64>() / polygon.len() as f64;
|
||||||
|
|
||||||
|
polygon.into_iter().map(move |[px, py]| {
|
||||||
|
// Delta.
|
||||||
|
let dx = px as f64 - cx;
|
||||||
|
let dy = py as f64 - cy;
|
||||||
|
let d = (dx * dx + dy * dy).sqrt();
|
||||||
|
|
||||||
|
// Normalize delta.
|
||||||
|
let nx = dx / d;
|
||||||
|
let ny = dy / d;
|
||||||
|
|
||||||
|
// Shift away from centroid.
|
||||||
|
let fx = px as f64 + nx * inflation_factor;
|
||||||
|
let fy = py as f64 + ny * inflation_factor;
|
||||||
|
|
||||||
|
// Round away from centroid.
|
||||||
|
let rx = if fx >= cx { fx.ceil() } else { fx.floor() };
|
||||||
|
let ry = if fy >= cy { fy.ceil() } else { fy.floor() };
|
||||||
|
|
||||||
|
[rx as i64, ry as i64]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,72 +2,41 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
use dearcut::RecordingTriangulator;
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Board,
|
Board,
|
||||||
primitives::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId},
|
navmesh::Navmesh,
|
||||||
|
primitives::{Joint, JointId, Polygon, PolygonId, PrimitiveId, Segment, SegmentId, Via, ViaId},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Getters)]
|
#[derive(Clone, Debug, Getters)]
|
||||||
pub struct LayerNavmesher {
|
pub struct LayerNavmesher {
|
||||||
boundary: Vec<[i64; 2]>,
|
boundary: Vec<[i64; 2]>,
|
||||||
navmeshes: Vec<RecordingTriangulator<i64>>,
|
navmeshes: Vec<Navmesh>,
|
||||||
inflation_factors: Vec<f64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayerNavmesher {
|
impl LayerNavmesher {
|
||||||
pub fn new(boundary: impl IntoIterator<Item = [i64; 2]>) -> Self {
|
fn new(boundary: impl IntoIterator<Item = [i64; 2]>) -> Self {
|
||||||
|
let boundary: Vec<[i64; 2]> = boundary.into_iter().collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
boundary: boundary.into_iter().collect(),
|
boundary: boundary.clone(),
|
||||||
navmeshes: vec![RecordingTriangulator::new()],
|
navmeshes: vec![Navmesh::new(boundary)],
|
||||||
inflation_factors: vec![0.0],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_polygon(&mut self, polygon: impl IntoIterator<Item = [i64; 2]>) {
|
fn insert_primitive_in_polygon(
|
||||||
|
&mut self,
|
||||||
|
primitive_id: PrimitiveId,
|
||||||
|
polygon: impl IntoIterator<Item = [i64; 2]>,
|
||||||
|
) {
|
||||||
let polygon: Vec<[i64; 2]> = polygon.into_iter().collect();
|
let polygon: Vec<[i64; 2]> = polygon.into_iter().collect();
|
||||||
|
|
||||||
for i in 0..self.navmeshes.len() {
|
for i in 0..self.navmeshes.len() {
|
||||||
self.navmeshes[i].insert_polygon_and_rebuild(
|
self.navmeshes[i].insert_polygon(primitive_id, polygon.clone());
|
||||||
Self::inflate_polygon(polygon.clone(), self.inflation_factors[i]),
|
|
||||||
self.boundary.clone(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inflate_polygon(
|
|
||||||
polygon: impl IntoIterator<Item = [i64; 2]>,
|
|
||||||
inflation_factor: f64,
|
|
||||||
) -> impl IntoIterator<Item = [i64; 2]> {
|
|
||||||
let polygon: Vec<[i64; 2]> = polygon.into_iter().collect();
|
|
||||||
|
|
||||||
// Centroid.
|
|
||||||
let cx = polygon.iter().map(|p| p[0] as f64).sum::<f64>() / polygon.len() as f64;
|
|
||||||
let cy = polygon.iter().map(|p| p[1] as f64).sum::<f64>() / polygon.len() as f64;
|
|
||||||
|
|
||||||
polygon.into_iter().map(move |[px, py]| {
|
|
||||||
// Delta.
|
|
||||||
let dx = px as f64 - cx;
|
|
||||||
let dy = py as f64 - cy;
|
|
||||||
let d = (dx * dx + dy * dy).sqrt();
|
|
||||||
|
|
||||||
// Normalize delta.
|
|
||||||
let nx = dx / d;
|
|
||||||
let ny = dy / d;
|
|
||||||
|
|
||||||
// Shift away from centroid.
|
|
||||||
let fx = px as f64 + nx * inflation_factor;
|
|
||||||
let fy = py as f64 + ny * inflation_factor;
|
|
||||||
|
|
||||||
// Round away from centroid.
|
|
||||||
let rx = if fx >= cx { fx.ceil() } else { fx.floor() };
|
|
||||||
let ry = if fy >= cy { fy.ceil() } else { fy.floor() };
|
|
||||||
|
|
||||||
[rx as i64, ry as i64]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Getters)]
|
#[derive(Clone, Debug, Getters)]
|
||||||
|
|
@ -76,7 +45,7 @@ pub struct Navmesher {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Navmesher {
|
impl Navmesher {
|
||||||
pub fn new(boundary: impl IntoIterator<Item = [i64; 2]>, layer_count: usize) -> Self {
|
fn new(boundary: impl IntoIterator<Item = [i64; 2]>, layer_count: usize) -> Self {
|
||||||
let boundary: Vec<[i64; 2]> = boundary.into_iter().collect();
|
let boundary: Vec<[i64; 2]> = boundary.into_iter().collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -86,46 +55,9 @@ impl Navmesher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_polygon(&mut self, layer: usize, polygon: impl IntoIterator<Item = [i64; 2]>) {
|
fn insert_joint(&mut self, joint_id: JointId, joint: Joint) {
|
||||||
self.layers[layer].insert_polygon(polygon);
|
self.layers[joint.layer]
|
||||||
}
|
.insert_primitive_in_polygon(joint_id.into(), Self::joint_circumscribed_octagon(joint));
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Getters)]
|
|
||||||
pub struct NavmesherBoard {
|
|
||||||
navmesher: Navmesher,
|
|
||||||
board: Board,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NavmesherBoard {
|
|
||||||
pub fn with_board(board: Board) -> Self {
|
|
||||||
let mut navmesher = Navmesher::new(
|
|
||||||
board.layout().boundary().clone(),
|
|
||||||
*board.layout().layer_count(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (_, joint) in board.layout().joints().collection() {
|
|
||||||
Self::insert_joint_in_navmesher(&mut navmesher, *joint);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, segment) in board.layout().segments().collection() {
|
|
||||||
Self::insert_segment_in_navmesher(&mut navmesher, &board, SegmentId::new(i), *segment);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (_, polygon) in board.layout().polygons().collection() {
|
|
||||||
Self::insert_polygon_in_navmesher(&mut navmesher, polygon.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
Self { navmesher, board }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_joint(&mut self, joint: Joint) -> JointId {
|
|
||||||
Self::insert_joint_in_navmesher(&mut self.navmesher, joint);
|
|
||||||
self.board.add_joint(joint)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_joint_in_navmesher(navmesher: &mut Navmesher, joint: Joint) {
|
|
||||||
navmesher.insert_polygon(joint.layer, Self::joint_circumscribed_octagon(joint));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn joint_circumscribed_octagon(joint: Joint) -> [[i64; 2]; 8] {
|
fn joint_circumscribed_octagon(joint: Joint) -> [[i64; 2]; 8] {
|
||||||
|
|
@ -145,23 +77,11 @@ impl NavmesherBoard {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_segment(&mut self, segment: Segment) -> SegmentId {
|
fn insert_segment(&mut self, board: &Board, segment_id: SegmentId, segment: Segment) {
|
||||||
let segment_id = self.board.add_segment(segment);
|
|
||||||
Self::insert_segment_in_navmesher(&mut self.navmesher, &self.board, segment_id, segment);
|
|
||||||
|
|
||||||
segment_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_segment_in_navmesher(
|
|
||||||
navmesher: &mut Navmesher,
|
|
||||||
board: &Board,
|
|
||||||
segment_id: SegmentId,
|
|
||||||
segment: Segment,
|
|
||||||
) {
|
|
||||||
let endpoints = board.layout().segment_endpoints(segment_id);
|
let endpoints = board.layout().segment_endpoints(segment_id);
|
||||||
|
|
||||||
navmesher.insert_polygon(
|
self.layers[segment.layer].insert_primitive_in_polygon(
|
||||||
segment.layer,
|
segment_id.into(),
|
||||||
Self::inflated_segment(
|
Self::inflated_segment(
|
||||||
endpoints[0][0],
|
endpoints[0][0],
|
||||||
endpoints[0][1],
|
endpoints[0][1],
|
||||||
|
|
@ -191,17 +111,65 @@ impl NavmesherBoard {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn insert_polygon(&mut self, polygon_id: PolygonId, polygon: Polygon) {
|
||||||
|
self.layers[polygon.layer].insert_primitive_in_polygon(polygon_id.into(), polygon.vertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Getters)]
|
||||||
|
pub struct NavmesherBoard {
|
||||||
|
navmesher: Navmesher,
|
||||||
|
board: Board,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NavmesherBoard {
|
||||||
|
pub fn with_board(board: Board) -> Self {
|
||||||
|
let mut navmesher = Navmesher::new(
|
||||||
|
board.layout().boundary().clone(),
|
||||||
|
*board.layout().layer_count(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (i, joint) in board.layout().joints().collection() {
|
||||||
|
navmesher.insert_joint(JointId::new(i).into(), *joint);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, segment) in board.layout().segments().collection() {
|
||||||
|
navmesher.insert_segment(&board, SegmentId::new(i), *segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Vias.
|
||||||
|
|
||||||
|
for (i, polygon) in board.layout().polygons().collection() {
|
||||||
|
navmesher.insert_polygon(PolygonId::new(i), polygon.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { navmesher, board }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_joint(&mut self, joint: Joint) -> JointId {
|
||||||
|
let joint_id = self.board.add_joint(joint);
|
||||||
|
self.navmesher.insert_joint(joint_id, joint);
|
||||||
|
|
||||||
|
joint_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_segment(&mut self, segment: Segment) -> SegmentId {
|
||||||
|
let segment_id = self.board.add_segment(segment);
|
||||||
|
self.navmesher
|
||||||
|
.insert_segment(&self.board, segment_id, segment);
|
||||||
|
|
||||||
|
segment_id
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert_via(&mut self, via: Via) -> ViaId {
|
pub fn insert_via(&mut self, via: Via) -> ViaId {
|
||||||
// TODO: Insert into navmesh.
|
// TODO: Insert into navmesh.
|
||||||
self.board.add_via(via)
|
self.board.add_via(via)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_polygon(&mut self, polygon: Polygon) -> PolygonId {
|
pub fn insert_polygon(&mut self, polygon: Polygon) -> PolygonId {
|
||||||
Self::insert_polygon_in_navmesher(&mut self.navmesher, polygon.clone());
|
let polygon_id = self.board.add_polygon(polygon.clone());
|
||||||
self.board.add_polygon(polygon)
|
self.navmesher.insert_polygon(polygon_id, polygon);
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_polygon_in_navmesher(navmesher: &mut Navmesher, polygon: Polygon) {
|
polygon_id
|
||||||
navmesher.insert_polygon(polygon.layer, polygon.vertices);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue