feat(autorouter/autoroute): Add option to toggle permutation

Updated with the following command in Fish shell:

```
for f in tests/**.cmd; jq ".done?.[].Autoroute[1].permutate |= false" $f | sponge $f; end
```
This commit is contained in:
Mikolaj Wielgus 2025-07-19 13:06:02 +02:00
parent d181c7df1b
commit 09c98f2d17
12 changed files with 61 additions and 26 deletions

View File

@ -40,6 +40,7 @@ fn main() -> Result<(), std::io::Error> {
PinSelection::new_select_layer(&board, 0), PinSelection::new_select_layer(&board, 0),
AutorouterOptions { AutorouterOptions {
presort_by: PresortBy::RatlineIntersectionCountAndLength, presort_by: PresortBy::RatlineIntersectionCountAndLength,
permutate: true,
router_options: RouterOptions { router_options: RouterOptions {
wrap_around_bands: true, wrap_around_bands: true,
squeeze_through_under_bends: false, squeeze_through_under_bends: false,

View File

@ -336,6 +336,7 @@ impl RouteActions {
ui.selectable_value(&mut autorouter_options.presort_by, PresortBy::RatlineIntersectionCountAndLength, tr.text("tr-menu-route-options-presort-by-ratline-intersection-count-and-length")); ui.selectable_value(&mut autorouter_options.presort_by, PresortBy::RatlineIntersectionCountAndLength, tr.text("tr-menu-route-options-presort-by-ratline-intersection-count-and-length"));
ui.selectable_value(&mut autorouter_options.presort_by, PresortBy::PairwiseDetours, tr.text("tr-menu-route-options-presort-by-pairwise-detours")); ui.selectable_value(&mut autorouter_options.presort_by, PresortBy::PairwiseDetours, tr.text("tr-menu-route-options-presort-by-pairwise-detours"));
}); });
ui.checkbox(&mut autorouter_options.permutate, tr.text("tr-menu-route-options-permutate"));
ui.checkbox( ui.checkbox(
&mut autorouter_options &mut autorouter_options
.router_options .router_options

View File

@ -44,6 +44,7 @@ impl MenuBar {
Self { Self {
autorouter_options: AutorouterOptions { autorouter_options: AutorouterOptions {
presort_by: PresortBy::RatlineIntersectionCountAndLength, presort_by: PresortBy::RatlineIntersectionCountAndLength,
permutate: true,
router_options: RouterOptions { router_options: RouterOptions {
routed_band_width: 100.0, routed_band_width: 100.0,
wrap_around_bands: true, wrap_around_bands: true,
@ -318,7 +319,6 @@ impl MenuBar {
error_dialog.push_error("tr-module-invoker", format!("{}", err)); error_dialog.push_error("tr-module-invoker", format!("{}", err));
} }
} }
let opts = self.autorouter_options;
if actions.edit.remove_bands.consume_key_triggered(ctx, ui) { if actions.edit.remove_bands.consume_key_triggered(ctx, ui) {
schedule(error_dialog, workspace, |selection| { schedule(error_dialog, workspace, |selection| {
Command::RemoveBands(selection.band_selection) Command::RemoveBands(selection.band_selection)
@ -340,13 +340,16 @@ impl MenuBar {
selection: selection.pin_selection, selection: selection.pin_selection,
allowed_edges: BTreeSet::new(), allowed_edges: BTreeSet::new(),
active_layer, active_layer,
routed_band_width: opts.router_options.routed_band_width, routed_band_width: self
.autorouter_options
.router_options
.routed_band_width,
} }
}); });
} }
} else if actions.route.autoroute.consume_key_triggered(ctx, ui) { } else if actions.route.autoroute.consume_key_triggered(ctx, ui) {
schedule(error_dialog, workspace, |selection| { schedule(error_dialog, workspace, |selection| {
Command::Autoroute(selection.pin_selection, opts) Command::Autoroute(selection.pin_selection, self.autorouter_options)
}); });
} else if actions } else if actions
.inspect .inspect
@ -354,7 +357,10 @@ impl MenuBar {
.consume_key_triggered(ctx, ui) .consume_key_triggered(ctx, ui)
{ {
schedule(error_dialog, workspace, |selection| { schedule(error_dialog, workspace, |selection| {
Command::CompareDetours(selection.pin_selection, opts) Command::CompareDetours(
selection.pin_selection,
self.autorouter_options,
)
}); });
} else if actions } else if actions
.inspect .inspect

View File

@ -51,6 +51,8 @@ tr-menu-route-options-presort-by = Presort by
tr-menu-route-options-presort-by-ratline-intersection-count-and-length = Intersection Count and Length tr-menu-route-options-presort-by-ratline-intersection-count-and-length = Intersection Count and Length
tr-menu-route-options-presort-by-pairwise-detours = Pairwise Detours tr-menu-route-options-presort-by-pairwise-detours = Pairwise Detours
tr-menu-route-options-permutate = Permutate
## Continuously applied, so use imperfective aspect if possible, e.g. in Polish ## Continuously applied, so use imperfective aspect if possible, e.g. in Polish
## it should be "przeciskaj pod taśmami" instead of "przeciśnij pod taśmami". ## it should be "przeciskaj pod taśmami" instead of "przeciśnij pod taśmami".

View File

@ -234,6 +234,7 @@ impl AutorouteExecutionPermutator {
Ok(Self { Ok(Self {
stepper: AutorouteExecutionStepper::new(autorouter, ratlines.clone(), options)?, stepper: AutorouteExecutionStepper::new(autorouter, ratlines.clone(), options)?,
// Note: I assume here that the first permutation is the same as the original order.
permutations_iter: ratlines.into_iter().permutations(ratlines_len), permutations_iter: ratlines.into_iter().permutations(ratlines_len),
options, options,
}) })
@ -251,7 +252,11 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinue
) -> Result<ControlFlow<Option<BoardEdit>, AutorouteContinueStatus>, AutorouterError> { ) -> Result<ControlFlow<Option<BoardEdit>, AutorouteContinueStatus>, AutorouterError> {
match self.stepper.step(autorouter) { match self.stepper.step(autorouter) {
Ok(ok) => Ok(ok), Ok(ok) => Ok(ok),
Err(..) => { Err(err) => {
if !self.options.permutate {
return Err(err);
}
self.stepper.abort(autorouter); self.stepper.abort(autorouter);
let Some(new_permutation) = self.permutations_iter.next() else { let Some(new_permutation) = self.permutations_iter.next() else {

View File

@ -42,6 +42,7 @@ pub enum PresortBy {
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AutorouterOptions { pub struct AutorouterOptions {
pub presort_by: PresortBy, pub presort_by: PresortBy,
pub permutate: bool,
pub router_options: RouterOptions, pub router_options: RouterOptions,
} }

View File

@ -18,7 +18,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
}, },
@ -40,7 +41,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
} }

View File

@ -54,7 +54,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
}, },
@ -112,7 +113,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
}, },
@ -170,7 +172,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
}, },
@ -228,7 +231,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
} }

View File

@ -42,10 +42,11 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
} }
], ],
"undone": [] "undone": []
} }

View File

@ -34,7 +34,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
} }

View File

@ -18,7 +18,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -40,7 +41,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -62,7 +64,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -84,7 +87,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -106,7 +110,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -128,7 +133,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -150,7 +156,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -172,7 +179,8 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
}, },
@ -194,10 +202,11 @@
"routed_band_width": 100.0, "routed_band_width": 100.0,
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true "squeeze_through_under_bends": true
} },
"permutate": false
} }
] ]
} }
], ],
"undone": [] "undone": []
} }

View File

@ -54,7 +54,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
}, },
@ -76,7 +77,8 @@
"wrap_around_bands": true, "wrap_around_bands": true,
"squeeze_through_under_bends": true, "squeeze_through_under_bends": true,
"routed_band_width": 100.0 "routed_band_width": 100.0
} },
"permutate": false
} }
] ]
} }