From 933541ad34ab813d20c232852a66f3023da9227d Mon Sep 17 00:00:00 2001 From: Jovansonlee Cesar Date: Sun, 11 Jul 2021 10:57:14 +0800 Subject: Calculate radius, center, center_cells based on the ascii art and EdgeCase specified This also simplify the calculation of quadrant arcs --- svgbob/src/buffer/cell_buffer/cell.rs | 18 +- svgbob/src/map/circle_map.rs | 362 ++++++++++++++++++---------------- svgbob/src/point.rs | 22 +++ svgbob/test_data/circles.bob | 72 +++++-- 4 files changed, 283 insertions(+), 191 deletions(-) diff --git a/svgbob/src/buffer/cell_buffer/cell.rs b/svgbob/src/buffer/cell_buffer/cell.rs index db54d8b..cf49dcb 100644 --- a/svgbob/src/buffer/cell_buffer/cell.rs +++ b/svgbob/src/buffer/cell_buffer/cell.rs @@ -184,7 +184,7 @@ impl Cell { /// check if this cell is bounded by the lower bound and upper bound pub fn is_bounded(&self, bound1: Cell, bound2: Cell) -> bool { - let (lower_bound, upper_bound) = rearrange_bound(bound1, bound2); + let (lower_bound, upper_bound) = Self::rearrange_bound(bound1, bound2); self.x >= lower_bound.x && self.y >= lower_bound.y && self.x <= upper_bound.x @@ -297,15 +297,15 @@ impl Cell { y: self.y + 1, } } -} -/// rearrange the bound of 2 cells -pub fn rearrange_bound(bound1: Cell, bound2: Cell) -> (Cell, Cell) { - let min_x = cmp::min(bound1.x, bound2.x); - let min_y = cmp::min(bound1.y, bound2.y); - let max_x = cmp::max(bound1.x, bound2.x); - let max_y = cmp::max(bound1.y, bound2.y); - (Cell::new(min_x, min_y), Cell::new(max_x, max_y)) + /// rearrange the bound of 2 cells + pub fn rearrange_bound(bound1: Cell, bound2: Cell) -> (Cell, Cell) { + let min_x = cmp::min(bound1.x, bound2.x); + let min_y = cmp::min(bound1.y, bound2.y); + let max_x = cmp::max(bound1.x, bound2.x); + let max_y = cmp::max(bound1.y, bound2.y); + (Cell::new(min_x, min_y), Cell::new(max_x, max_y)) + } } #[cfg(test)] diff --git a/svgbob/src/map/circle_map.rs b/svgbob/src/map/circle_map.rs index 3dcb05d..e2e9d41 100644 --- a/svgbob/src/map/circle_map.rs +++ b/svgbob/src/map/circle_map.rs @@ -36,92 +36,109 @@ lazy_static! { /// 8└─┴─┴─┴─┘ U└─┴─┴─┴─┘Y /// ``` V W X /// art, center_cell, center_point, radius, edge_case, top_offset to center point - pub static ref CIRCLE_MAP: Vec<(&'static str, Cell, Point, f32, EdgeCase, f32)> = + static ref CIRCLE_ART_MAP: Vec<(&'static str, EdgeCase, f32)> = vec![ // CIRCLE_1 - //center 0,0,o, radius = 0.5 - // are circle arc touching the cell edge?: - // x_edge: false - // y_edge: true + //center 1,0,k, radius = 0.5 // 2 cell width , radius formula: (n-1)/2 = (2-1)/2 = 0.5 // where n is the number of cells used // if edge_case starts at edge then n is added by 1. // vert_mid: half (0.5/1.0) + // cx_lies: edge + // cy_lies: mid + // + // edge_case: start_half = 0.5, start_edge = 0.0 + // if radius + edge_case has 0.5 then mid, 0.0 them edge + // + // (r#" () - "#, Cell::new(1,0), Cell::new(1,0).k(), 0.5, EdgeCase::StartHalf, 0.5), + "#, EdgeCase::StartHalf, 0.5), // CIRCLE_2 //center = 1,1,m radius = 1.0 // 3 cell width, (n-1)/2 = (3-1)/2 = 1.0 - // // vert_mid: half (0.5/1.0) + // cx_lies: mid + // cy_lies: mid (r#" (_) - "#, Cell::new(1,0), Cell::new(1,0).m(), 1.0, EdgeCase::StartHalf, 0.5), + "#, EdgeCase::StartHalf, 0.5), // CIRCLE_3 //center = 1,1,o radius = 1.5, // 4 cell width, (n-1)/2 = (4-1)/2 = 1.5 // vert_mid: 3/4 (1.5/2.0) + // cx_lies: edge + // cy_lies: mid (r#" __ (__) - "#, Cell::new(2,1), Cell::new(2,1).k(), 1.5, EdgeCase::StartHalf, 1.5), + "#, EdgeCase::StartHalf, 1.5), // CIRCLE_4 //center: 2,1,m radius: 2.0 // 5 cell width, (n-1)/2 = (5-1)/2 = 2.0 // vert_mid: half (1.5/3.0) + // cx_lies: mid + // cy_lies: mid (r#" ,-. ( ) `-' - "#, Cell::new(2,1), Cell::new(2,1).m(), 2.0, EdgeCase::StartHalf, 1.5), + "#, EdgeCase::StartHalf, 1.5), // CIRCLE_5 //center: 2,1,o radius: 2.5 // 6 cell width, (n-1)/2 = (6-1)/2 = 2.5 // vert_mid: half (1.5/3.0) + // cx_lies: edge + // cy_lies: mid (r#" .--. ( ) `--' - "#, Cell::new(3,1), Cell::new(3,1).k(), 2.5, EdgeCase::StartHalf, 1.5), + "#, EdgeCase::StartHalf, 1.5), // CIRCLE_6 //center: 3,2,m radius: 3.0 // 7 cell width, (n-1)/2 = (7-1)/2 = 3.0 // vert_mid: 2.5/4 + // cx_lies: mid + // cy_lies: mid (r#" _ .' '. ( ) `._.' - "#, Cell::new(3,2), Cell::new(3,2).m(), 3.0, EdgeCase::StartHalf, 2.5), + "#, EdgeCase::StartHalf, 2.5), // CIRCLE_7 //center: 3,2,o radius: 3.5 // 8 cell width, (n-1)/2 = (8-1)/2 = 3.5 // vert_mid: 2.5/4 + // cx_lies: edge + // cy_lies: mid (r#" __ ,' '. ( ) `.__.' - "#, Cell::new(4,2), Cell::new(4,2).k(), 3.5,EdgeCase::StartHalf, 2.5), + "#, EdgeCase::StartHalf, 2.5), // CIRCLE_8 //center: 4,2,m radius:4.0 // 9 cell width, (n-1)/2 = (9-1)/2 = 4.0 // vert_mid: half (2.5/5.0) + // cx_lies: mid + // cy_lies: mid (r#" ___ ,' '. ( ) `. .' `-' - "#, Cell::new(4,2), Cell::new(4,2).m(), 4.0, EdgeCase::StartHalf, 2.5), + "#, EdgeCase::StartHalf, 2.5), // circle 9 and up can be divided into 4 quadrants these quadrants can be arcs and can be used as // rounded edge with larger radius for rouded rect @@ -130,31 +147,37 @@ lazy_static! { // start_edge: true // 9 cell width, (n-0)/2 = (9-0)/2 = 4.5 // vert_mid: 3.0/5.0 + // cx_lies: mid + // cy_lies: edge (r#" ___ ,' `. / \ \ / `.___.' - "#, Cell::new(4,3), Cell::new(4,3).c(), 4.5, EdgeCase::StartEdge, 3.0 ), + "#, EdgeCase::StartEdge, 3.0 ), // CIRCLE_10 //center: 4,2,y radius: 5.0 //start_edge: true // 10 cell width, (n-0)/2 = (10-0)/2 = 5.0 // vert_mid: 3.0/5.0 + // cx_lies: edge + // cy_lies: edge (r#" ____ ,' `. / \ \ / `.____.' - "#, Cell::new(5,3), Cell::new(5,3).a(), 5.0, EdgeCase::StartEdge, 3.0), + "#, EdgeCase::StartEdge, 3.0), // CIRCLE_11 //center:5,3,o radius: 5.5 // 12 cell width, (n-1)/2 = (12-1)/2 = 5.5 // vert_mid: 3.5/6.0 + // cx_lies: edge + // cy_lies: mid (r#" ____ .' `. @@ -162,12 +185,14 @@ lazy_static! { ( ) \ / `.____.' - "#, Cell::new(6,3), Cell::new(6,3).k(), 5.5, EdgeCase::StartHalf , 3.5), + "#, EdgeCase::StartHalf , 3.5), // CIRCLE_12 //center:6,3,m radius: 6.0 // 13 cell width, (n-1)/2 = (13-1)/2 = 6.0 // vert_mid: 3.5/6.0 + // cx_lies: mid + // cy_lies: mid (r#" _____ ,' `. @@ -175,11 +200,13 @@ lazy_static! { ( ) \ / `._____.' - "#, Cell::new(6,3), Cell::new(6,3).m(), 6.0, EdgeCase::StartHalf, 3.5), + "#, EdgeCase::StartHalf, 3.5), // CIRCLE_13 // center: 6,3,y radius: 6.5 // vert_mid: 4.0/7.0 + // cx_lies: edge + // cy_lies: edge (r#" ______ ,' `. @@ -188,11 +215,13 @@ lazy_static! { | | \ / `.______.' - "#, Cell::new(7,4), Cell::new(7,4).a(), 6.5, EdgeCase::StartHalf, 4.0), + "#, EdgeCase::StartHalf, 4.0), // CIRCLE_14 //center: 7,3,w radius: 7.0 //vert_mid: 4.0/7.0 + // cx_lies: mid + // cy_lies: edge (r#" _______ ,' `. @@ -201,12 +230,14 @@ lazy_static! { | | \ / `._______.' - "#, Cell::new(7,4), Cell::new(7,4).c(), 7.0, EdgeCase::StartHalf , 4.0), + "#, EdgeCase::StartHalf , 4.0), // CIRCLE_15 //center: 7,4,o radius: 7.5 //vert_mid: 4.5/8.0 + // cx_lies: edge + // cy_lies: mid (r#" ________ ,' `. @@ -216,11 +247,13 @@ lazy_static! { | | \ / `.________.' - "#, Cell::new(8,4), Cell::new(8,4).k(), 7.5, EdgeCase::StartHalf, 4.5), + "#, EdgeCase::StartHalf, 4.5), // CIRCLE_16 //center: 8,4,m radius: 8.0 //vert_mid: 4.5/9.0 + // cx_lies: mid + // cy_lies: mid (r#" __-----__ ,' `. @@ -231,11 +264,13 @@ lazy_static! { \ / `. .' `-------' - "#, Cell::new(8,4), Cell::new(8,4).m(), 8.0, EdgeCase::StartHalf, 4.5), + "#, EdgeCase::StartHalf, 4.5), // CIRCLE_17 //center: 8,4,o radius: 8.5 // vert_mid: 4.5/9.0 + // cx_lies: edge + // cy_lies: mid (r#" .--------. ,' `. @@ -246,11 +281,13 @@ lazy_static! { \ / `. .' `--------' - "#, Cell::new(9,4), Cell::new(9,4).k(), 8.5, EdgeCase::StartHalf, 4.5), + "#, EdgeCase::StartHalf, 4.5), // CIRCLE_18 //center:9,5,m radius: 9.0 //vert_mid: 5.5/10.0 + // cx_lies: mid + // cy_lies: mid (r#" _.-'''''-._ ,' `. @@ -262,11 +299,13 @@ lazy_static! { \ / `._ _.' '-.....-' - "#, Cell::new(9,5), Cell::new(9,5).m(), 9.0, EdgeCase::StartHalf, 5.5), + "#, EdgeCase::StartHalf, 5.5), // CIRCLE_19 // center: 9,5,o radius: 9.5 // vert_mid: 5.5/10.0 + // cx_lies: edge + // cy_lies: mid (r#" _.-''''''-._ ,' `. @@ -278,12 +317,14 @@ lazy_static! { \ / `._ _.' '-......-' - "#, Cell::new(10,5), Cell::new(10,5).k(), 9.5, EdgeCase::StartHalf, 5.5), + "#, EdgeCase::StartHalf, 5.5), // CIRCLE_20 // center: 10,5,m radius: 10 // vert_mid: 5.5/10.0 + // cx_lies: mid + // cy_lies: mid (r#" _.-'''''''-._ ,' `. @@ -295,11 +336,13 @@ lazy_static! { \ / `._ _.' '-.......-' - "#, Cell::new(10,5), Cell::new(10,5).m(), 10.0, EdgeCase::StartHalf, 5.5), + "#, EdgeCase::StartHalf, 5.5), // CIRCLE_21 // center: 10,5,o radius: 10.5 // vert_mid: 5.5/11.0 + // cx_lies: edge + // cy_lies: mid (r#" _.-''''''''-._ ,' `. @@ -312,12 +355,14 @@ lazy_static! { \ / `._ _.' '-........-' - "#, Cell::new(11,5), Cell::new(11,5).k(), 10.5, EdgeCase::StartHalf, 5.5), + "#, EdgeCase::StartHalf, 5.5), // CIRCLE_22 // center: 10,5,m radius: 11 // radius = (n-1)/2 = (23-1)/2 = 11 // vert_mid: 5.5/11.0 + // cx_lies: mid + // cy_lies: mid (r#" _.-'''''''''-._ ,' `. @@ -330,62 +375,55 @@ lazy_static! { \ / `._ _.' '-.........-' - "#, Cell::new(11,5), Cell::new(11,5).m(), 11.0, EdgeCase::StartHalf, 5.5), + "#, EdgeCase::StartHalf, 5.5), ]; + pub static ref CIRCLE_MAP: BTreeMap<&'static str,(Cell, Point, f32, EdgeCase, f32)> =BTreeMap::from_iter( + CIRCLE_ART_MAP.iter().map(|(art, edge_case, offset_center_y)|{ + let cb = CellBuffer::from(*art); + let (lo, hi) = cb.bounds().expect("circle must have bounds"); + + let width = match *edge_case { + EdgeCase::StartEdge => { + (hi.x - lo.x) as f32 + 1.0 + } + EdgeCase::StartHalf => { + (hi.x - lo.x) as f32 + } + }; + + let calc_radius = width / 2.0; + + let edge_inc_x = match edge_case{ + EdgeCase::StartEdge => 0.0, + EdgeCase::StartHalf => 0.5, + }; + + let calc_center_x = calc_radius + edge_inc_x; + + let calc_center_y = offset_center_y * 2.0; + + let calc_center = Point::new(calc_center_x, calc_center_y); + + let calc_center_cell = calc_center.cell(); + + (*art, (calc_center_cell, calc_center, calc_radius, *edge_case, *offset_center_y)) + }) + ); + /// The fragments for each of the circle /// Calculate the span and get the group fragments pub static ref FRAGMENTS_CIRCLE: Vec<(Vec,Circle)> = Vec::from_iter( - CIRCLE_MAP.iter().map(|(art, _center_cell, center, radius, edge_case, offset_center_y)|{ + CIRCLE_MAP.iter().map(|(art, (_center_cell, center, radius, edge_case, offset_center_y))|{ (circle_art_to_group(art, &Settings::default()), Circle::new(*center, *radius, false)) }) ); /// map of circle spans and their radius pub static ref DIAMETER_CIRCLE: BTreeMap =BTreeMap::from_iter( - CIRCLE_MAP.iter().map(|(art, center_cell, center, radius, edge_case, offset_center_y)|{ + CIRCLE_MAP.iter().map(|(art, (center_cell, center, radius, edge_case, offset_center_y))|{ let cb = CellBuffer::from(*art); - println!("art: {} radius: {}", art,radius); - if let Some((lo, hi)) = cb.bounds(){ - - let width = match *edge_case { - EdgeCase::StartEdge => { - (hi.x - lo.x) as f32 + 1.0 - } - EdgeCase::StartHalf => { - (hi.x - lo.x) as f32 - } - }; - - println!("width: {}", width); - let calc_radius = width / 2.0; - println!("calc_radius: {}", calc_radius); - assert_eq!(calc_radius, *radius); - - let calc_center_x = match *edge_case{ - EdgeCase::StartEdge => { - calc_radius - } - EdgeCase::StartHalf => { - calc_radius + 0.5 - } - }; - - let calc_center_y = offset_center_y * 2.0; - dbg!(offset_center_y); - - let calc_center = Point::new(calc_center_x, calc_center_y); - dbg!(&calc_center); - assert_eq!(calc_center, *center); - - let (calc_center_cell,_) = Cell::snap_point(calc_center); - dbg!(&calc_center_cell); - assert_eq!(calc_center_cell, *center_cell); - - - } - let mut spans = cb.group_adjacents(); assert_eq!(spans.len(), 1); let span = spans.remove(0).localize(); @@ -395,7 +433,7 @@ lazy_static! { /// There is only 1 span per circle, and localized pub static ref CIRCLES_SPAN: BTreeMap = BTreeMap::from_iter( - CIRCLE_MAP.iter().map(|(art, _center_cell, center, radius, edge_case, offset_center_y)|{ + CIRCLE_MAP.iter().map(|(art, (_center_cell, center, radius, edge_case, offset_center_y))|{ let cb = CellBuffer::from(*art); let mut spans = cb.group_adjacents(); assert_eq!(spans.len(), 1); @@ -404,112 +442,103 @@ lazy_static! { }) ); - /// Build a fragment for the characters in the range - /// extract the characters - /// - /// top_left arc: top_left to center cell + + /// Simplified version of fragment arcs derived from CIRCLE_MAP + /// Algorithm: + /// 1. Locate the cells corresponding to the 4 quadrant boundary of the circle /// - /// top_right arc: top_right to center_cell + /// top_left top top_right + /// p2 + /// arc2 | arc1 + /// | + /// left p3----+----- p1 right + /// | + /// arc3 | arc4 + /// p4 + /// bottom_left bottom bottom_right /// - /// bottom_left arc: bottom_left to center_cell + /// p1 = center.x + radius, center.y + /// p2 = center.x, center.y - radius + /// p3 = center.x - radius, center.y + /// p4 = center.x + radius, center.y + radius /// - /// bottom_right arc: bottom_right to center_cell + /// right,top,left,bottom, top_left, top_right,bottom_left,bottom_right are cells dervied from + /// bounds. /// - /// if the number of horizontal cells are odd arc1 an arc2 will both have - /// the top_center character, so as arc3 and arc4 will have both the bottom_center character + /// assert that snapping points to cell corresponds respectively: + /// p1 -> right cell + /// p2 -> top cell + /// p3 -> left cell + /// p4 -> bottom cell /// - /// if the number of vertical cells are odd arc arc1 and arc3 will both have - /// the left_center character, so as arc3 and arc4 will have both the right_center character + /// 2. Locate the span of each quadrants + /// arc4 span is always center_cell, to bottom_right + /// arc2 span is conditional + /// if center cell lies on mid, the span coverage is inclusive of the center cell. + /// otherwise if the center cell lies on the edge, then the cell coverage is exclusive of + /// the center cell /// pub static ref FRAGMENTS_ARC: Vec<(Vec,fragment::Arc)> =Vec::from_iter( - CIRCLE_MAP.iter().skip(3).flat_map(|(art, center_cell, center, radius, edge_case, offset_center_y)|{ + CIRCLE_MAP.iter().skip(3).flat_map(|(art, (center_cell, center, radius, edge_case, offset_center_y))|{ let cb = CellBuffer::from(*art); let mut spans = cb.group_adjacents(); assert_eq!(spans.len(), 1); - //TODO: span localize here affects the center of the arc, - //need to use the exact center used in the circle here - //Need to fix the calculation here involving the span let span = spans.remove(0).localize(); - let (tl_bounds, br_bounds) = span.bounds().expect("There should be bounds"); - - let center_cell_br_bound = center_cell.bottom_right_most(); - // inlude the center cell for x when this is true, when deriving a span for arc1, arc3, arc4 - let eq_include_center_x = center.x <= center_cell_br_bound.x; - // include the center cell for y when this is true, when deriving a span for arc1, arc3, arc4 - let eq_include_center_y = center.y <= center_cell_br_bound.y; - - let strict_include_center_x = center.x < center_cell_br_bound.x; - let strict_include_center_y = center.y < center_cell_br_bound.y; - - // - // ARC 1 - // __ - // | '. - // | \ - // |_____| - // - let arc1_top_right = Cell::new(br_bounds.x, tl_bounds.y); - let arc1_center_cell = Cell::new( - if strict_include_center_x { center_cell.x } else { center_cell.x + 1}, - if eq_include_center_y { center_cell.y } else { center_cell.y + 1}); - - let arc1_top_left = Cell::new(arc1_center_cell.x, tl_bounds.y); - let arc1_center = arc1_top_left.localize_point(*center); - - - let arc1_span = span.extract(arc1_center_cell, arc1_top_right); - let arc1 = fragment::Arc::new(Point::new(arc1_center.x + *radius, arc1_center.y), Point::new(arc1_center.x, arc1_center.y - *radius) , *radius); - - // - // ARC 2 - // __ - // .' | - // / | - // |_____| - // - - let arc2_top_left = Cell::new(tl_bounds.x, tl_bounds.y); - let arc2_span = span.extract(arc2_top_left, *center_cell); - let arc2 = fragment::Arc::new(Point::new(center.x, center.y - radius), Point::new(center.x - radius , center.y), *radius); - - - // - // ARC 3 - // ______. - // | | - // \ | - // `.__| - // - // - let arc3_center_cell = Cell::new( - if eq_include_center_x { center_cell.x } else { center_cell.x + 1}, - if strict_include_center_y { center_cell.y } else { center_cell.y + 1} - ); - let arc3_top_left = Cell::new(tl_bounds.x, arc3_center_cell.y); - let arc3_bottom_right = Cell::new(arc3_center_cell.x, br_bounds.y); - let arc3_center = arc3_top_left.localize_point(*center); - let arc3_span = span.extract(arc3_top_left, arc3_bottom_right); - let arc3 = fragment::Arc::new(Point::new(arc3_center.x - radius, arc3_center.y), Point::new(arc3_center.x, arc3_center.y + radius), *radius); - - - // - // ARC 4 - // - // .______ - // | | - // | / - // |__.' - // - let arc4_center_cell = Cell::new( - if strict_include_center_x { center_cell.x } else { center_cell.x + 1}, - if strict_include_center_y { center_cell.y } else { center_cell.y + 1} - ); - let arc4_top_left = Cell::new(arc4_center_cell.x, arc4_center_cell.y); - let arc4_bottom_right = Cell::new(br_bounds.x, br_bounds.y); - let arc4_center = arc4_top_left.localize_point(*center); - let arc4_span = span.extract(arc4_top_left, arc4_bottom_right); - let arc4 = fragment::Arc::new(Point::new(arc4_center.x, arc4_center.y + radius), Point::new(arc4_center.x + radius, arc4_center.y), *radius); + let (start_bound, end_bound) = span.bounds().expect("There should be bounds"); + + let right = Cell::new(end_bound.x, center_cell.y); + let top = Cell::new(center_cell.x, start_bound.y); + let left = Cell::new(start_bound.x, center_cell.y); + let bottom = Cell::new(center_cell.x, end_bound.y); + + let top_left = Cell::new(left.x, top.y); + let top_right = Cell::new(right.x, top.y); + let bottom_left = Cell::new(left.x, bottom.y); + let bottom_right = Cell::new(right.x, bottom.y); + assert_eq!(top_left, start_bound); + assert_eq!(bottom_right, end_bound); + + + // include cx if the center lies on the horizontal midline + // include cy if the center lies on the veritcal midline + 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 arc1_bounds = Cell::rearrange_bound(Cell::new(center_cell.x, cy_adjusted), top_right); + let arc2_bounds = Cell::rearrange_bound(top_left, Cell::new( cx_adjusted, cy_adjusted)); + let arc3_bounds = Cell::rearrange_bound(bottom_left, Cell::new(cx_adjusted, center_cell.y)); + let arc4_bounds = Cell::rearrange_bound(*center_cell, bottom_right); + + let arc1_span = span.extract(arc1_bounds.0, arc1_bounds.1); + let arc2_span = span.extract(arc2_bounds.0, arc2_bounds.1); + let arc3_span = span.extract(arc3_bounds.0, arc3_bounds.1); + let arc4_span = span.extract(arc4_bounds.0, arc4_bounds.1); + + + 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 arc1_start = arc1_bounds.0.localize_point(p1); + let arc1_end = arc1_bounds.0.localize_point(p2); + + let arc2_start = arc2_bounds.0.localize_point(p2); + let arc2_end = arc2_bounds.0.localize_point(p3); + + let arc3_start = arc3_bounds.0.localize_point(p3); + let arc3_end = arc3_bounds.0.localize_point(p4); + + let arc4_start = arc4_bounds.0.localize_point(p4); + let arc4_end = arc4_bounds.0.localize_point(p1); + + let arc1 = fragment::Arc::new(arc1_start, arc1_end, *radius); + let arc2 = fragment::Arc::new(arc2_start, arc2_end, *radius); + let arc3 = fragment::Arc::new(arc3_start, arc3_end, *radius); + let arc4 = fragment::Arc::new(arc4_start, arc4_end, *radius); + + //TODO: get the settings supplied by the user let settings = &Settings::default(); vec![ @@ -520,6 +549,7 @@ lazy_static! { ] }) ); + } fn circle_art_to_group(art: &str, settings: &Settings) -> Vec { @@ -591,8 +621,10 @@ mod tests { fn access_circles() { let len = DIAMETER_CIRCLE.len(); println!("len: {}", len); + assert_eq!(len, 22); let frag_len = FRAGMENTS_ARC.len(); println!("frag len: {}", frag_len); + assert_eq!(frag_len, 76); } #[test] diff --git a/svgbob/src/point.rs b/svgbob/src/point.rs index 26a67ea..18a8015 100644 --- a/svgbob/src/point.rs +++ b/svgbob/src/point.rs @@ -1,5 +1,6 @@ use crate::buffer::CellGrid; use crate::util; +use crate::Cell; use nalgebra::{Point2, Vector2}; use std::{ cmp::Ordering, @@ -73,6 +74,27 @@ impl Point { let u = units * CellGrid::unit_y(); Self::new(self.x + t, self.y + u) } + + /// test if the point lie on an edge of a cell + /// that is the fractional part is 0.0 + pub fn is_edge_x(&self) -> bool { + self.x.fract() == 0.0 + } + pub fn is_edge_y(&self) -> bool { + (self.y / 2.0).fract() == 0.0 + } + pub fn is_mid_x(&self) -> bool { + self.x.fract() == 0.5 + } + pub fn is_mid_y(&self) -> bool { + (self.y / 2.0).fract() == 0.5 + } + + /// return the cell where this point fall to + pub fn cell(&self) -> Cell { + let (cell, _) = Cell::snap_point(*self); + cell + } } impl From> for Point { diff --git a/svgbob/test_data/circles.bob b/svgbob/test_data/circles.bob index 719c370..339f21b 100644 --- a/svgbob/test_data/circles.bob +++ b/svgbob/test_data/circles.bob @@ -162,8 +162,35 @@ '-.......-' - ,- -. - ( ) + _.-''''''''-._ + ,' `. + / \ + . . + | | + 21 | | + | | + | | + \ / + `._ _.' + '-........-' + + _.-'''''''''-._ + ,' `. + / \ + . . + | | + | | + 22 | | + | | + \ / + `._ _.' + '-.........-' + + | | + V V + + -----> ,- -. + -----> ( ) 4 ( ) `- -' @@ -301,30 +328,41 @@ `._ _.' '-... ...-' + | | | | + V V V V - _.-''' '''-._ - ,' `. - / \ - . . - | | - | | + _.-''' '''-._ + ,' `. + / \ + . . + | | + --> | | <-- 19 - | | - | | - \ / - `._ _.' - '-... ...-' + --> | | <-- + | | + \ / + `._ _.' + '-... ...-' + ^ ^ ^ ^ + | | | | - _.-'''' ''''-._ + + | | | | + V V V V + + --> _.-'''' ''''-._ <-- ,' `. / \ . . | | - | | + --> | | <-- 20 - | | + --> | | <-- | | \ / `._ _.' - '-.... ....-' + --> '-.... ....-' <-- + + ^ ^ ^ ^ + | | | | -- cgit v1.2.3