topola 0.1.0

Work-in-progress free and open-source topological (rubberband) router and autorouter for printed circuit boards (PCBs)
Documentation
// SPDX-FileCopyrightText: 2026 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use std::ops::ControlFlow;

use derive_getters::Getters;

use crate::{
    AutoplacerSchedule, Interactor, Vector2,
    autoplacer::Jostler,
    board::{
        Board,
        interactors::{BoardMasterInteractor, SelectInteractor},
    },
    layout::LayerId,
    selections::PersistableSelection,
};

#[derive(Getters)]
pub struct JostlerMasterInteractor {
    board_master: BoardMasterInteractor,
    jostler: Jostler,
    prev_pointer: Option<Vector2<i64>>,
}

impl JostlerMasterInteractor {
    pub fn new(board: &mut Board, board_master: BoardMasterInteractor) -> Self {
        let selection = board_master.selection().components.clone();

        Self {
            board_master,
            jostler: Jostler::new(
                board,
                selection,
                AutoplacerSchedule {
                    initial_temperature: 500.0,
                    temperature_common_ratio: 0.95,
                    initial_std_dev: 500.0,
                    std_dev_common_ratio: 0.995,
                    max_steps: 3000,
                },
            ),
            prev_pointer: None,
        }
    }

    pub fn selection(&self) -> &PersistableSelection {
        self.board_master.selection()
    }

    pub fn select_interactor(&self) -> &Option<SelectInteractor> {
        self.board_master.select_interactor()
    }
}

impl Interactor for JostlerMasterInteractor {
    fn step(&mut self, board: &mut Board) -> ControlFlow<()> {
        crate::profile_function!();

        self.jostler.step(board);
        ControlFlow::Continue(())
    }

    fn press(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
        self.board_master.press(board, layer, pointer);
    }

    fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
        if let Some(prev_pointer) = self.prev_pointer {
            if pointer != prev_pointer {
                self.jostler.abort(board);
                self.jostler = Jostler::new(
                    board,
                    self.board_master.selection().components.clone(),
                    AutoplacerSchedule {
                        initial_temperature: 500.0,
                        temperature_common_ratio: 0.95,
                        initial_std_dev: 500.0,
                        std_dev_common_ratio: 0.995,
                        max_steps: 300,
                    },
                );
            }
        }

        self.prev_pointer = Some(pointer);

        //self.jostler.hold(board, layer, pointer);
        self.board_master.hold(board, layer, pointer);
    }

    fn release(
        &mut self,
        board: &mut Board,
        layer: LayerId,
        pointer: Vector2<i64>,
    ) -> ControlFlow<()> {
        self.board_master.release(board, layer, pointer)
    }

    fn abort(&mut self, board: &mut Board) {
        self.board_master.abort(board);
    }
}