mirror of https://codeberg.org/topola/topola.git
First crude attempt at autoplacing using simulated annealing
This commit is contained in:
parent
65f96f1fc2
commit
dabb82490e
|
|
@ -35,6 +35,7 @@ tr-menu-route-planar-autoroute = Planar Autoroute
|
|||
tr-menu-route-topo-autoroute = Topological planar Autoroute
|
||||
tr-menu-route-routed-band-width = Routed Band Width
|
||||
tr-menu-route-fanout-clearance = Fanout Clearance
|
||||
tr-menu-route-autoplace = Autoplace
|
||||
|
||||
tr-menu-debug = Debug
|
||||
tr-menu-debug-highlight-obstacles = Highlight Obstacles
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
|
||||
pub struct Actions {
|
||||
pub file: FileActions,
|
||||
pub run: RunActions,
|
||||
pub debug: DebugActions,
|
||||
}
|
||||
|
||||
|
|
@ -19,6 +20,7 @@ impl Actions {
|
|||
pub fn new(tr: &Translator) -> Self {
|
||||
Self {
|
||||
file: FileActions::new(tr),
|
||||
run: RunActions::new(tr),
|
||||
debug: DebugActions::new(tr),
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +76,29 @@ impl FileActions {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct RunActions {
|
||||
pub autoplace: Trigger,
|
||||
}
|
||||
|
||||
impl RunActions {
|
||||
pub fn new(tr: &Translator) -> Self {
|
||||
Self {
|
||||
autoplace: Action::new(
|
||||
tr.text("tr-menu-route-autoplace"),
|
||||
egui::Modifiers::NONE,
|
||||
egui::Key::Space,
|
||||
)
|
||||
.into_trigger(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_menu(&mut self, ctx: &egui::Context, ui: &mut egui::Ui, have_workspace: bool) {
|
||||
ui.add_enabled_ui(have_workspace, |ui| {
|
||||
self.autoplace.button(ctx, ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugActions {
|
||||
pub fix_step_rate: Switch,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,8 +125,12 @@ impl eframe::App for App {
|
|||
|
||||
/// Called each time the UI has to be repainted.
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
self.menu_bar
|
||||
.update(ctx, &mut self.translator, self.content_channel.0.clone());
|
||||
self.menu_bar.update(
|
||||
ctx,
|
||||
&mut self.translator,
|
||||
self.content_channel.0.clone(),
|
||||
self.controller.as_mut(),
|
||||
);
|
||||
|
||||
self.update_state();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,18 +11,19 @@ use crate::{layers_panel::LayersPanel, translator::Translator};
|
|||
pub struct Controller {
|
||||
pub workspace: Workspace,
|
||||
pub appearance_panel: LayersPanel,
|
||||
pub master_interactor: Option<MasterInteractor>,
|
||||
pub dt_accum: f64,
|
||||
pub master_interactor: MasterInteractor,
|
||||
dt_accum: f64,
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
pub fn new(board: Board, tr: &Translator) -> Self {
|
||||
let appearance_panel = LayersPanel::new(&board);
|
||||
let workspace = Workspace::new_board(board);
|
||||
|
||||
Self {
|
||||
workspace: Workspace::new_board(board),
|
||||
master_interactor: MasterInteractor::new(workspace.selection().clone()),
|
||||
workspace,
|
||||
appearance_panel,
|
||||
master_interactor: None,
|
||||
dt_accum: 0.0,
|
||||
}
|
||||
}
|
||||
|
|
@ -59,11 +60,8 @@ impl Controller {
|
|||
true
|
||||
}
|
||||
|
||||
pub fn step(&mut self, tr: &Translator) -> ControlFlow<()> {
|
||||
self.master_interactor
|
||||
.as_mut()
|
||||
.map(|master_interactor| master_interactor.step(self.workspace.board_mut()));
|
||||
ControlFlow::Continue(())
|
||||
pub fn step(&mut self, _tr: &Translator) -> ControlFlow<()> {
|
||||
self.master_interactor.step(self.workspace.board_mut())
|
||||
}
|
||||
|
||||
pub fn update_appearance_panel(&mut self, ctx: &egui::Context) {
|
||||
|
|
@ -87,13 +85,22 @@ impl Controller {
|
|||
ui: &mut egui::Ui,
|
||||
) {
|
||||
if ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
if let (Some(interactor), Workspace::Board(workspace)) =
|
||||
(&mut self.master_interactor, &mut self.workspace)
|
||||
{
|
||||
interactor.abort(&mut workspace.board);
|
||||
*self.workspace.selection_mut() = interactor.selection().clone();
|
||||
let board_master =
|
||||
if let MasterInteractor::Autoplacer(interactor) = &self.master_interactor {
|
||||
Some(interactor.board_master().clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
self.master_interactor.abort(&mut workspace.board);
|
||||
|
||||
if let Some(board_master) = board_master {
|
||||
self.master_interactor = MasterInteractor::Board(board_master);
|
||||
}
|
||||
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
}
|
||||
self.master_interactor = None;
|
||||
}
|
||||
|
||||
let primary_pressed = ctx.input(|i| i.pointer.button_pressed(egui::PointerButton::Primary));
|
||||
|
|
@ -110,21 +117,20 @@ impl Controller {
|
|||
maybe_pointer_on_scene = Some(pointer_on_scene);
|
||||
|
||||
if primary_pressed && scene_hovered {
|
||||
self.master_interactor =
|
||||
Some(MasterInteractor::new(self.workspace.selection().clone()));
|
||||
self.master_interactor = MasterInteractor::new(self.workspace.selection().clone());
|
||||
}
|
||||
|
||||
if let (Some(interactor), Workspace::Board(workspace)) =
|
||||
(&mut self.master_interactor, &mut self.workspace)
|
||||
{
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
if primary_down {
|
||||
interactor.hold(
|
||||
self.master_interactor.hold(
|
||||
&mut workspace.board,
|
||||
self.appearance_panel.active,
|
||||
pointer_on_scene,
|
||||
);
|
||||
|
||||
if let Some(select_interactor) = interactor.select_interactor().as_ref() {
|
||||
if let Some(select_interactor) =
|
||||
self.master_interactor.select_interactor().as_ref()
|
||||
{
|
||||
let origin = *select_interactor.origin();
|
||||
let drag_rect_scene = egui::Rect::from_min_max(
|
||||
egui::pos2(
|
||||
|
|
@ -160,27 +166,25 @@ impl Controller {
|
|||
}
|
||||
|
||||
if primary_released {
|
||||
if let Some(mut interactor) = self.master_interactor.take() {
|
||||
let active = self.appearance_panel.active;
|
||||
let pointer_for_scene = maybe_pointer_on_scene.unwrap_or_else(|| {
|
||||
interactor
|
||||
.select_interactor()
|
||||
.as_ref()
|
||||
.map(|select_interactor| *select_interactor.origin())
|
||||
.unwrap_or(Vector2::new(0, 0))
|
||||
});
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
interactor.release(&mut workspace.board, active, pointer_for_scene);
|
||||
*self.workspace.selection_mut() = interactor.selection().clone();
|
||||
}
|
||||
let active = self.appearance_panel.active;
|
||||
let pointer_for_scene = maybe_pointer_on_scene.unwrap_or_else(|| {
|
||||
self.master_interactor
|
||||
.select_interactor()
|
||||
.as_ref()
|
||||
.map(|select_interactor| *select_interactor.origin())
|
||||
.unwrap_or(Vector2::new(0, 0))
|
||||
});
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
self.master_interactor
|
||||
.release(&mut workspace.board, active, pointer_for_scene);
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
}
|
||||
}
|
||||
|
||||
if delete_pressed {
|
||||
let mut interactor = MasterInteractor::new(self.workspace.selection().clone());
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
interactor.delete(&mut workspace.board);
|
||||
*self.workspace.selection_mut() = interactor.selection().clone();
|
||||
self.master_interactor.delete(&mut workspace.board);
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,12 @@ use specctra::{
|
|||
read::ListTokenizer,
|
||||
structure::DsnFile,
|
||||
};
|
||||
use topola::AutoplacerSchedule;
|
||||
|
||||
use crate::{
|
||||
actions::Actions,
|
||||
app::{execute, handle_file},
|
||||
controller::Controller,
|
||||
translator::Translator,
|
||||
};
|
||||
|
||||
|
|
@ -40,17 +42,22 @@ impl MenuBar {
|
|||
ctx: &egui::Context,
|
||||
tr: &mut Translator,
|
||||
content_sender: Sender<Result<DsnFile, ParseErrorContext>>,
|
||||
controller: Option<&mut Controller>,
|
||||
) {
|
||||
let mut actions = Actions::new(tr);
|
||||
|
||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||
egui::MenuBar::new().ui(ui, |ui| {
|
||||
ui.menu_button("File", |ui| {
|
||||
actions.file.render_menu(ctx, ui, false);
|
||||
actions.file.render_menu(ctx, ui, controller.is_some());
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
actions.run.render_menu(ctx, ui, controller.is_some());
|
||||
|
||||
ui.separator();
|
||||
|
||||
MenuButton::new(tr.text("tr-menu-debug"))
|
||||
.config(
|
||||
MenuConfig::default()
|
||||
|
|
@ -95,6 +102,21 @@ impl MenuBar {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
if actions.run.autoplace.consume_key_triggered(ctx, ui) {
|
||||
if let Some(controller) = controller {
|
||||
controller.master_interactor.autoplace(
|
||||
controller.workspace.board_mut(),
|
||||
AutoplacerSchedule {
|
||||
initial_temperature: 1000.0,
|
||||
temperature_common_ratio: 0.99,
|
||||
initial_std_dev: 1000.0,
|
||||
std_dev_common_ratio: 0.99,
|
||||
max_steps: 2000,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use derive_getters::Getters;
|
||||
|
||||
use crate::{
|
||||
autoplacer::{Autoplacer, AutoplacerSchedule},
|
||||
board::{
|
||||
Board,
|
||||
interactors::{MasterInteractor as BoardMasterInteractor, SelectInteractor},
|
||||
interactors::{BoardMasterInteractor, SelectInteractor},
|
||||
selections::PersistableSelection,
|
||||
},
|
||||
interactor::Interactor,
|
||||
|
|
@ -14,20 +18,23 @@ use crate::{
|
|||
vector::Vector2,
|
||||
};
|
||||
|
||||
pub struct MasterInteractor {
|
||||
#[derive(Getters)]
|
||||
pub struct AutoplacerMasterInteractor {
|
||||
board_master: BoardMasterInteractor,
|
||||
autoplacer: Autoplacer,
|
||||
}
|
||||
|
||||
impl MasterInteractor {
|
||||
impl AutoplacerMasterInteractor {
|
||||
pub fn new(
|
||||
board: &mut Board,
|
||||
selection: PersistableSelection,
|
||||
board_master: BoardMasterInteractor,
|
||||
schedule: AutoplacerSchedule,
|
||||
) -> Self {
|
||||
let selection = board_master.selection().components.clone();
|
||||
|
||||
Self {
|
||||
board_master: BoardMasterInteractor::new(selection.clone()),
|
||||
autoplacer: Autoplacer::new(board, selection.components.clone(), schedule),
|
||||
board_master,
|
||||
autoplacer: Autoplacer::new(board, selection, schedule),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,9 +47,9 @@ impl MasterInteractor {
|
|||
}
|
||||
}
|
||||
|
||||
impl Interactor for MasterInteractor {
|
||||
fn step(&mut self, board: &mut Board) {
|
||||
self.autoplacer.step(board);
|
||||
impl Interactor for AutoplacerMasterInteractor {
|
||||
fn step(&mut self, board: &mut Board) -> ControlFlow<()> {
|
||||
self.autoplacer.step(board)
|
||||
}
|
||||
|
||||
fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
mod master;
|
||||
|
||||
pub use master::MasterInteractor;
|
||||
pub use master::AutoplacerMasterInteractor;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
pub mod interactors;
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rand::RngExt;
|
||||
use rand_distr::{Distribution, Normal};
|
||||
use undoredo::{FlushDelta, ResetDelta};
|
||||
|
|
@ -17,10 +19,11 @@ use crate::{
|
|||
};
|
||||
|
||||
pub struct AutoplacerSchedule {
|
||||
initial_temperature: f64,
|
||||
temperature_common_ratio: f64,
|
||||
initial_std_dev: f64,
|
||||
std_dev_common_ratio: f64,
|
||||
pub initial_temperature: f64,
|
||||
pub temperature_common_ratio: f64,
|
||||
pub initial_std_dev: f64,
|
||||
pub std_dev_common_ratio: f64,
|
||||
pub max_steps: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
|
@ -32,7 +35,7 @@ pub struct AutoplacerStepParams {
|
|||
pub struct Autoplacer {
|
||||
components: Vec<ComponentId>,
|
||||
schedule: AutoplacerSchedule,
|
||||
step_counter: u32,
|
||||
step_counter: u64,
|
||||
origin_delta: BoardDelta, //rng: ThreadRng,
|
||||
}
|
||||
|
||||
|
|
@ -50,22 +53,29 @@ impl Autoplacer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn step(&mut self, board: &mut Board) -> bool {
|
||||
self.step_with_params(
|
||||
board,
|
||||
AutoplacerStepParams {
|
||||
temperature: self.schedule.initial_temperature
|
||||
* self
|
||||
.schedule
|
||||
.temperature_common_ratio
|
||||
.powf(self.step_counter as f64),
|
||||
std_dev: self.schedule.initial_std_dev
|
||||
* self
|
||||
.schedule
|
||||
.std_dev_common_ratio
|
||||
.powf(self.step_counter as f64),
|
||||
},
|
||||
)
|
||||
pub fn step(&mut self, board: &mut Board) -> ControlFlow<()> {
|
||||
if self.step_counter < self.schedule.max_steps {
|
||||
let control_flow = self.step_with_params(
|
||||
board,
|
||||
AutoplacerStepParams {
|
||||
temperature: self.schedule.initial_temperature
|
||||
* self
|
||||
.schedule
|
||||
.temperature_common_ratio
|
||||
.powf(self.step_counter as f64),
|
||||
std_dev: self.schedule.initial_std_dev
|
||||
* self
|
||||
.schedule
|
||||
.std_dev_common_ratio
|
||||
.powf(self.step_counter as f64),
|
||||
},
|
||||
);
|
||||
|
||||
self.step_counter += 1;
|
||||
control_flow
|
||||
} else {
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO.
|
||||
|
|
@ -73,7 +83,11 @@ impl Autoplacer {
|
|||
|
||||
}*/
|
||||
|
||||
fn step_with_params(&mut self, board: &mut Board, params: AutoplacerStepParams) -> bool {
|
||||
fn step_with_params(
|
||||
&mut self,
|
||||
board: &mut Board,
|
||||
params: AutoplacerStepParams,
|
||||
) -> ControlFlow<()> {
|
||||
for &component in self.components.iter() {
|
||||
//self.step_component_with_params(component, params);
|
||||
let last_cost = self.cost(board, params);
|
||||
|
|
@ -100,7 +114,7 @@ impl Autoplacer {
|
|||
}
|
||||
}
|
||||
|
||||
true
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn cost(&self, board: &Board, params: AutoplacerStepParams) -> f64 {
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ use crate::{
|
|||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, Getters, PartialEq)]
|
||||
pub struct MasterInteractor {
|
||||
pub struct BoardMasterInteractor {
|
||||
select_interactor: Option<SelectInteractor>,
|
||||
drag_move_interactor: Option<DragMoveInteractor>,
|
||||
selection: PersistableSelection,
|
||||
}
|
||||
|
||||
impl MasterInteractor {
|
||||
impl BoardMasterInteractor {
|
||||
pub fn new(selection: PersistableSelection) -> Self {
|
||||
Self {
|
||||
select_interactor: None,
|
||||
|
|
@ -32,7 +32,7 @@ impl MasterInteractor {
|
|||
}
|
||||
}
|
||||
|
||||
impl Interactor for MasterInteractor {
|
||||
impl Interactor for BoardMasterInteractor {
|
||||
fn delete(&mut self, board: &mut Board) {
|
||||
board.delete_net_free_primitives(self.selection.nets.clone());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ mod select;
|
|||
|
||||
pub use drag_move::DragMoveInteractor;
|
||||
pub use drag_select::{DragSelectInteractor, DragSelectOptions};
|
||||
pub use master::MasterInteractor;
|
||||
pub use master::BoardMasterInteractor;
|
||||
pub use select::SelectInteractor;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,23 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::{
|
||||
board::{Board, interactors::SelectInteractor, selections::PersistableSelection},
|
||||
autoplacer::{AutoplacerSchedule, interactors::AutoplacerMasterInteractor},
|
||||
board::{
|
||||
Board,
|
||||
interactors::{BoardMasterInteractor, SelectInteractor},
|
||||
selections::PersistableSelection,
|
||||
},
|
||||
layout::LayerId,
|
||||
vector::Vector2,
|
||||
};
|
||||
|
||||
pub trait Interactor {
|
||||
fn step(&mut self, board: &mut Board) {}
|
||||
fn step(&mut self, _board: &mut Board) -> ControlFlow<()> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
fn delete(&mut self, board: &mut Board) {}
|
||||
fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {}
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {}
|
||||
|
|
@ -17,35 +26,57 @@ pub trait Interactor {
|
|||
}
|
||||
|
||||
pub enum MasterInteractor {
|
||||
Board(crate::board::interactors::MasterInteractor),
|
||||
Autoplacer(crate::autoplacer::interactors::MasterInteractor),
|
||||
Board(BoardMasterInteractor),
|
||||
Autoplacer(AutoplacerMasterInteractor),
|
||||
}
|
||||
|
||||
impl MasterInteractor {
|
||||
pub fn new(selection: PersistableSelection) -> Self {
|
||||
Self::Board(crate::board::interactors::MasterInteractor::new(selection))
|
||||
Self::Board(crate::board::interactors::BoardMasterInteractor::new(
|
||||
selection,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn autoplace(&mut self, board: &mut Board, schedule: AutoplacerSchedule) {
|
||||
match self {
|
||||
Self::Board(board_master) => {
|
||||
*self = Self::Autoplacer(AutoplacerMasterInteractor::new(
|
||||
board,
|
||||
board_master.clone(),
|
||||
schedule,
|
||||
));
|
||||
}
|
||||
_ => (),
|
||||
//_ => panic!("autoplacement can be only started from board at rest"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn selection(&self) -> &PersistableSelection {
|
||||
match self {
|
||||
Self::Board(interactor) => interactor.selection(),
|
||||
Self::Autoplacer(interactor) => interactor.selection(),
|
||||
Self::Board(board_master) => board_master.selection(),
|
||||
Self::Autoplacer(autoplacer_master) => autoplacer_master.selection(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_interactor(&self) -> &Option<SelectInteractor> {
|
||||
match self {
|
||||
Self::Board(interactor) => interactor.select_interactor(),
|
||||
Self::Autoplacer(interactor) => interactor.select_interactor(),
|
||||
Self::Board(board_master) => board_master.select_interactor(),
|
||||
Self::Autoplacer(autoplacer_master) => autoplacer_master.select_interactor(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Interactor for MasterInteractor {
|
||||
fn step(&mut self, board: &mut Board) {
|
||||
fn step(&mut self, board: &mut Board) -> ControlFlow<()> {
|
||||
match self {
|
||||
Self::Board(interactor) => interactor.step(board),
|
||||
Self::Autoplacer(interactor) => interactor.step(board),
|
||||
Self::Autoplacer(interactor) => {
|
||||
if interactor.step(board).is_break() {
|
||||
*self = Self::Board(interactor.board_master().clone());
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ mod specctra;
|
|||
mod vector;
|
||||
mod workspace;
|
||||
|
||||
pub use crate::autoplacer::AutoplacerSchedule;
|
||||
pub use crate::autorouter::Autorouter;
|
||||
pub use crate::board::selections;
|
||||
pub use crate::interactor::{Interactor, MasterInteractor};
|
||||
|
|
|
|||
Loading…
Reference in New Issue