topola/src/tracer.rs

236 lines
6.9 KiB
Rust

use contracts::debug_ensures;
use crate::{
draw::{BareHead, Draw, Head, SegbendHead},
graph::{FixedDotIndex, GetNet, LooseBendIndex},
layout::{Band, Layout},
mesh::{Mesh, VertexIndex},
primitive::{GetFirstRail, GetInnerOuter},
rules::Rules,
};
#[derive(Debug)]
pub struct Trace {
pub path: Vec<VertexIndex>,
head: Head,
}
pub struct Tracer<'a> {
pub layout: &'a mut Layout,
pub rules: &'a Rules,
pub mesh: &'a Mesh,
}
impl<'a> Tracer<'a> {
pub fn new(layout: &'a mut Layout, rules: &'a Rules, mesh: &'a Mesh) -> Self {
Tracer {
layout,
rules,
mesh,
}
}
pub fn start(&mut self, from: FixedDotIndex, width: f64) -> Trace {
let band = self.layout.bands.insert(Band {
width,
net: self.layout.primitive(from).net(),
});
Trace {
path: vec![from.into()],
head: BareHead { dot: from, band }.into(),
}
}
pub fn finish(&mut self, trace: &mut Trace, into: FixedDotIndex, width: f64) -> Result<(), ()> {
self.draw().finish_in_dot(trace.head, into, width)
}
#[debug_ensures(ret.is_ok() -> trace.path.len() == path.len())]
pub fn rework_path(
&mut self,
trace: &mut Trace,
path: &[VertexIndex],
width: f64,
) -> Result<(), ()> {
let prefix_length = trace
.path
.iter()
.zip(path)
.take_while(|(v1, v2)| v1 == v2)
.count();
let length = trace.path.len();
self.undo_path(trace, length - prefix_length)?;
self.path(trace, &path[prefix_length..], width)
}
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))]
pub fn path(&mut self, trace: &mut Trace, path: &[VertexIndex], width: f64) -> Result<(), ()> {
for (i, vertex) in path.iter().enumerate() {
if let Err(err) = self.step(trace, *vertex, width) {
self.undo_path(trace, i)?;
return Err(err);
}
}
Ok(())
}
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - step_count))]
pub fn undo_path(&mut self, trace: &mut Trace, step_count: usize) -> Result<(), ()> {
for _ in 0..step_count {
self.undo_step(trace)?;
}
Ok(())
}
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + 1))]
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn step(&mut self, trace: &mut Trace, to: VertexIndex, width: f64) -> Result<(), ()> {
trace.head = self.wrap(trace.head, to, width)?.into();
trace.path.push(to);
Ok(())
}
fn wrap(&mut self, head: Head, around: VertexIndex, width: f64) -> Result<SegbendHead, ()> {
match around {
VertexIndex::FixedDot(dot) => self.wrap_around_fixed_dot(head, dot, width),
VertexIndex::FixedBend(_fixed_bend) => todo!(),
VertexIndex::LooseBend(loose_bend) => {
self.wrap_around_loose_bend(head, loose_bend, width)
}
}
}
fn wrap_around_fixed_dot(
&mut self,
head: Head,
around: FixedDotIndex,
width: f64,
) -> Result<SegbendHead, ()> {
let head = self.draw().segbend_around_dot(head, around.into(), width)?;
if let Some(first_rail) = self.layout.primitive(around).first_rail() {
self.layout.reattach_bend(first_rail, head.segbend.bend);
self.update_outward(head.segbend.bend);
}
Ok(head)
}
fn wrap_around_loose_bend(
&mut self,
head: Head,
around: LooseBendIndex,
width: f64,
) -> Result<SegbendHead, ()> {
let maybe_outer = self.layout.primitive(around).outer();
let head = self
.draw()
.segbend_around_bend(head, around.into(), width)?;
if let Some(outer) = maybe_outer {
self.layout.reattach_bend(outer, head.segbend.bend);
self.update_outward(head.segbend.bend);
}
Ok(head)
}
fn update_outward(&mut self, bend: LooseBendIndex) {
let mut rail = bend;
while let Some(outer) = self.layout.primitive(rail).outer() {
self.draw().update_bow(bend);
rail = outer;
}
}
/*fn redraw_outward(&mut self, bend: FixedBendIndex) -> Result<(), ()> {
let mut bows: Vec<Bow> = vec![];
let mut cur_bend = bend;
loop {
bows.push(self.layout.bow(cur_bend));
cur_bend = match self.layout.primitive(cur_bend).outer() {
Some(new_bend) => new_bend,
None => break,
}
}
let core = self.layout.primitive(bend).core().unwrap();
let mut maybe_inner = self.layout.primitive(bend).inner();
for bow in &bows {
self.layout.remove_interior(bow);
}
for bow in &bows {
let ends = bow.ends();
let head = self.draw().start(ends.0);
let width = 5.0;
let segbend_head = if let Some(inner) = maybe_inner {
self.draw().segbend_around_bend(head, inner.into(), width)?
} else {
self.draw().segbend_around_dot(head, core.into(), width)?
};
maybe_inner = Some(segbend_head.segbend.bend);
self.draw().finish(head, ends.1, width)?;
//self.relax_band(maybe_inner.unwrap());
}
Ok(())
}*/
/*fn relax_band(&mut self, bend: FixedBendIndex) {
let mut prev_bend = bend;
while let Some(cur_bend) = self.layout.primitive(prev_bend).prev_bend() {
if self.layout.primitive(cur_bend).cross_product() >= 0. {
self.release_bow(cur_bend);
}
prev_bend = cur_bend;
}
let mut prev_bend = bend;
while let Some(cur_bend) = self.layout.primitive(prev_bend).next_bend() {
if self.layout.primitive(cur_bend).cross_product() >= 0. {
self.release_bow(cur_bend);
}
prev_bend = cur_bend;
}
}*/
/*fn release_bow(&mut self, bend: FixedBendIndex) {
let bow = self.layout.bow(bend);
let ends = bow.ends();
self.layout.remove_interior(&bow);
let head = self.draw().start(ends.0);
let _ = self.draw().finish(head, ends.1, 5.0);
}*/
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - 1))]
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> {
if let Head::Segbend(head) = trace.head {
trace.head = self.draw().undo_segbend(head).unwrap();
} else {
return Err(());
}
trace.path.pop();
Ok(())
}
fn draw(&mut self) -> Draw {
Draw::new(&mut self.layout, &self.rules)
}
}