Skip to main content

geop_ops_assembly/
settle.rs

1//! [`Settler`]: what settles a program's state after every edit (see
2//! [`Settle`]) — moves its placed parts, and every other value a step says
3//! a solve moves, so that its mates hold — and the constraints the last
4//! settle found conflicting, for the joints panel to show
5//! ([`crate::panel`]).
6
7use std::{cell::RefCell, rc::Rc};
8
9use geop_core_editor::{editing::Pull, editor::Rerun, registry::Settle};
10use geop_core_math::geop_error::GeopResult;
11use geop_core_program::{reader::Reader, values::StateValues};
12
13use crate::solving::{self, check, conflicting, solved_states};
14
15/// What the settler and the joints panel share: what the last settle
16/// found.
17#[derive(Default)]
18pub(crate) struct Settled {
19    /// A smallest set of the constraints that cannot all hold together, as
20    /// the last settle found them: none where they all hold.
21    pub(crate) conflicting: RefCell<Vec<String>>,
22}
23
24/// Settles a program's state by solving its mates (see [`solving`]).
25pub struct Settler {
26    pub(crate) settled: Rc<Settled>,
27}
28
29impl Settle for Settler {
30    /// What the program pulls ([`Pull`]) pulls first, every part that is
31    /// not fixed free to give way — a linkage follows the link dragged.
32    /// Otherwise the parts move only if a mate does not hold: the step
33    /// `own`'s part first, the others held — mating a new part moves it,
34    /// not the part it is mated to — and every part that is not fixed only
35    /// where that is not enough. Which constraints conflict is asked only
36    /// where they do not all hold: a solve, and an enclosure of each group
37    /// that fails.
38    fn settle(
39        &self,
40        rerun: &mut Rerun,
41        pulls: &[Pull],
42        own: Option<&str>,
43    ) -> GeopResult<StateValues> {
44        let state = rerun.program.state.clone();
45        let holds = check(&rerun.reader()).is_ok_and(|report| report.converged);
46        let solved = if !pulls.is_empty() {
47            solving::solve(rerun, &state, pulls, None, true, None).ok()
48        } else if holds {
49            None
50        } else {
51            let own_first = own
52                .and_then(|own| solving::solve(rerun, &state, &[], Some(own), true, None).ok())
53                .filter(|(_, report)| report.converged);
54            own_first.or_else(|| solving::solve(rerun, &state, &[], None, true, None).ok())
55        };
56        *self.settled.conflicting.borrow_mut() = match &solved {
57            Some((_, report)) if !report.converged => {
58                conflicting(rerun, &state).unwrap_or_default()
59            }
60            _ => Vec::new(),
61        };
62        Ok(solved.map(|(moved, _)| moved).unwrap_or_default())
63    }
64
65    fn solvable(&self, reader: &Reader) -> GeopResult<Vec<String>> {
66        solved_states(reader)
67    }
68}