diff options
author | Jovansonlee Cesar <ivanceras@gmail.com> | 2021-08-27 16:14:46 +0800 |
---|---|---|
committer | Jovansonlee Cesar <ivanceras@gmail.com> | 2021-08-27 16:14:46 +0800 |
commit | dfb72d701bb5bd0e59e8bee4daa86d6861d3ac46 (patch) | |
tree | ef58b8a330f60ca1f4cbc862ed5cc206413f6d82 | |
parent | b22400a3b80c1aa9a10607393bca27af077eb8ab (diff) |
Modify the algorithm for endorse such that circles and arcs are matched by their ascii art rather than their computed fragments, this way, it can intersect with other fragments
-rw-r--r-- | svgbob/src/buffer/cell_buffer/span.rs | 62 | ||||
-rw-r--r-- | svgbob/src/map/circle_map.rs | 129 | ||||
-rw-r--r-- | svgbob/test_data/circles.bob | 18 |
3 files changed, 147 insertions, 62 deletions
diff --git a/svgbob/src/buffer/cell_buffer/span.rs b/svgbob/src/buffer/cell_buffer/span.rs index def4e31..199bf1a 100644 --- a/svgbob/src/buffer/cell_buffer/span.rs +++ b/svgbob/src/buffer/cell_buffer/span.rs @@ -32,6 +32,12 @@ impl DerefMut for Span { } } +impl From<Vec<(Cell, char)>> for Span { + fn from(cell_chars: Vec<(Cell, char)>) -> Self { + Span(cell_chars) + } +} + impl Span { pub(super) fn new(cell: Cell, ch: char) -> Self { Span(vec![(cell, ch)]) @@ -169,35 +175,6 @@ impl Span { (fragments, un_endorsed_rect) } - /// [X](Done) TODO: this is trying to match all the members of this contact - /// to each specific circle, this can be improve by checking - /// subsets of the contacts to match the circles. - /// - /// This function is calling on endorse algorithmn on fragments that - /// are neighbors, but not necessarily touching to be promoted to a shape. - /// These includes: circle, arc, and line with arrow heads. - fn endorse_circles_and_arcs( - groups: Vec<Contacts>, - ) -> (Vec<Fragment>, Vec<Contacts>) { - let mut fragments = vec![]; - let mut un_endorsed_circles: Vec<Contacts> = vec![]; - if let Some((circle, unmatched)) = circle_map::endorse_circle(&groups) { - fragments.push(circle.clone().into()); - for um in unmatched { - un_endorsed_circles.push(groups[um].clone()); - } - } else if let Some((arc, unmatched)) = circle_map::endorse_arc(&groups) - { - fragments.push(arc.clone().into()); - for um in unmatched { - un_endorsed_circles.push(groups[um].clone()); - } - } else { - un_endorsed_circles.extend(groups) - } - (fragments, un_endorsed_circles) - } - /// convert this span into fragments applying endorsement /// of group into fragments /// @@ -212,15 +189,28 @@ impl Span { self, settings: &Settings, ) -> (Vec<Fragment>, Vec<Contacts>) { - let (top_left, _) = self.bounds().expect("mut have bounds"); - let groups: Vec<Contacts> = self.get_contacts(settings); + let mut fragments = vec![]; + let (top_left, _) = self.bounds().expect("must have bounds"); + let un_endorsed_span = if let Some((circle, un_endorsed_span)) = + circle_map::endorse_circle_span(&self) + { + fragments.push(circle.clone().into()); + un_endorsed_span + } else if let Some((arc, un_endorsed_span)) = + circle_map::endorse_arc_span(&self) + { + fragments.push(arc.clone().into()); + un_endorsed_span + } else { + self + }; + + let groups: Vec<Contacts> = un_endorsed_span.get_contacts(settings); // 1st phase, successful_endorses fragments, unendorsed one) - let (mut fragments, un_endorsed) = Self::endorse_rects(groups); - // 2nd phase, try to endorse to circles and arcs from the rejects of the 1st phase - let (circle_fragments, un_endorsed) = - Self::endorse_circles_and_arcs(un_endorsed); + let (rect_fragments, un_endorsed) = Self::endorse_rects(groups); + + fragments.extend(rect_fragments); - fragments.extend(circle_fragments); ( fragments .iter() diff --git a/svgbob/src/map/circle_map.rs b/svgbob/src/map/circle_map.rs index 279ae74..5f48446 100644 --- a/svgbob/src/map/circle_map.rs +++ b/svgbob/src/map/circle_map.rs @@ -1,6 +1,7 @@ use crate::{ buffer::{CellBuffer, Contacts, Span}, fragment, + fragment::Arc, fragment::Circle, Cell, Point, Settings, }; @@ -411,6 +412,7 @@ lazy_static! { }) ); + /// The fragments for each of the circle /// Calculate the span and get the group fragments static ref FRAGMENTS_CIRCLE: Vec<(Vec<Contacts>,Circle)> = Vec::from_iter( @@ -441,6 +443,62 @@ lazy_static! { }) ); + pub static ref ARC_SPAN: BTreeMap<Arc, Span> = BTreeMap::from_iter( + CIRCLE_MAP.iter().skip(3).flat_map(|(art, center, radius, edge_case, offset_center_y)|{ + let span = circle_art_to_span(art); + let (top_left, bottom_right) = span.bounds().expect("must have bounds"); + let top_right = Cell::new(bottom_right.x, top_left.y); + let bottom_left = Cell::new(top_left.x, bottom_right.y); + + let p1 = Point::new(center.x + radius, center.y); + let p2 = Point::new(center.x, center.y - radius); + let p3 = Point::new(center.x - radius, center.y); + let p4 = Point::new(center.x, center.y + radius); + + + let center_cell = center.cell(); + + // TODO: use the edge_case from the circle_art map + let cx_adjusted = if !center.is_edge_x(){ center_cell.x }else{ center_cell.x - 1 }; + let cy_adjusted = if !center.is_edge_y(){ center_cell.y }else{ center_cell.y - 1 }; + + let span1_center = Cell::new(center_cell.x, cy_adjusted); + let span2_center = Cell::new(cx_adjusted, cy_adjusted); + let span3_center = Cell::new(cx_adjusted, center_cell.y); + let span4_center = center_cell; + + let bounds1 = Cell::rearrange_bound(span1_center, top_right); + let bounds2 = Cell::rearrange_bound(top_left, span2_center); + let bounds3 = Cell::rearrange_bound(bottom_left, span3_center); + let bounds4 = Cell::rearrange_bound(span4_center, bottom_right); + + let span1 = span.extract(bounds1.0, bounds1.1).localize(); + let span2 = span.extract(bounds2.0, bounds2.1).localize(); + let span3 = span.extract(bounds3.0, bounds3.1).localize(); + let span4 = span.extract(bounds4.0, bounds4.1).localize(); + + let arc1_start = bounds1.0.localize_point(p1); + let arc1_end = bounds1.0.localize_point(p2); + + let arc2_start = bounds2.0.localize_point(p2); + let arc2_end = bounds2.0.localize_point(p3); + + let arc3_start = bounds3.0.localize_point(p3); + let arc3_end = bounds3.0.localize_point(p4); + + let arc4_start = bounds4.0.localize_point(p4); + let arc4_end = bounds4.0.localize_point(p1); + + let arc1 = Arc::new(arc1_start, arc1_end, *radius); + let arc2 = Arc::new(arc2_start, arc2_end, *radius); + let arc3 = Arc::new(arc3_start, arc3_end, *radius); + let arc4 = Arc::new(arc4_start, arc4_end, *radius); + + vec![(arc1, span1), (arc2, span2), (arc3, span3), (arc4, span4)] + + }) + ); + /// Simplified version of fragment arcs derived from CIRCLE_MAP /// Algorithm: @@ -560,27 +618,64 @@ fn circle_art_to_group(art: &str, settings: &Settings) -> Vec<Contacts> { span1.get_contacts(settings) } -/// [X](Done) TODO: search only the subset of contacts that matches the circle. -/// if it is a subset then the circle is matched and the non-matching ones are returned -pub fn endorse_circle(search: &Vec<Contacts>) -> Option<(&Circle, Vec<usize>)> { - FRAGMENTS_CIRCLE - .iter() - .rev() - .find_map(|(contacts, circle)| { - let (matched, unmatched) = is_subset_of(contacts, search); - if matched { - Some((circle, unmatched)) - } else { - None - } - }) +fn circle_art_to_span(art: &str) -> Span { + let cell_buffer = CellBuffer::from(art); + let mut spans = cell_buffer.group_adjacents(); + assert_eq!(spans.len(), 1); + spans.remove(0).localize() +} + +pub fn endorse_circle_span(search: &Span) -> Option<(&Circle, Span)> { + CIRCLES_SPAN.iter().rev().find_map(|(circle, span)| { + let search_localized = search.clone().localize(); + let (matched, unmatched) = is_subset_of(span, &search_localized); + if matched { + let unmatched_cell_chars = search + .iter() + .enumerate() + .filter_map(|(i, cell_char)| { + if unmatched.contains(&i) { + Some(cell_char.clone()) + } else { + None + } + }) + .collect::<Vec<_>>(); + Some((circle, Span::from(unmatched_cell_chars))) + } else { + None + } + }) +} + +pub fn endorse_arc_span(search: &Span) -> Option<(&Arc, Span)> { + ARC_SPAN.iter().rev().find_map(|(arc, span)| { + let search_localized = search.clone().localize(); + let (matched, unmatched) = is_subset_of(span, &search_localized); + if matched { + let unmatched_cell_chars = search + .iter() + .enumerate() + .filter_map(|(i, cell_char)| { + if unmatched.contains(&i) { + Some(cell_char.clone()) + } else { + None + } + }) + .collect::<Vec<_>>(); + Some((arc, Span::from(unmatched_cell_chars))) + } else { + None + } + }) } /// returns true if all the contacts in subset is in big_set /// This also returns the indices of big_set that are not found in the subset -fn is_subset_of( - subset: &Vec<Contacts>, - big_set: &Vec<Contacts>, +fn is_subset_of<T: PartialEq>( + subset: &[T], + big_set: &[T], ) -> (bool, Vec<usize>) { let mut unmatched = vec![]; let mut matched = 0; diff --git a/svgbob/test_data/circles.bob b/svgbob/test_data/circles.bob index 68914ef..a5facc2 100644 --- a/svgbob/test_data/circles.bob +++ b/svgbob/test_data/circles.bob @@ -155,7 +155,7 @@ / | \ . | . | | | - 20 | --------+-------- | + 20 |---------+---------| | | | \ | / `._ | _.' @@ -370,16 +370,16 @@ _.-'''' ''''-._ - ,' `. + ,' | | `. / | | \ . | | . | | | | - | --------+ +-------- | + |---------+ +---------| - | --------+ +-------- | + |---------+ +---------| | | | | \ | | / - `._ _.' + `._ | | _.' '-.... ....-' @@ -398,15 +398,15 @@ _.-'''' ''''-._ - ,' `. - / | | \ + ,' | | `. + / '. | | .' \ . '. | | .' . | '. | | .' | | '+ +' | - | --------+ + | + |---------+ + | | / |\ | \ / | \ / - `._ _.' + `._ / | \ _.' '-.... ....-' |