diff options
107 files changed, 13042 insertions, 43728 deletions
@@ -7,6 +7,7 @@ public/ parts/ prime/ snap/ +**/out/* stage/ *.snap* *.tar* diff --git a/Architecture.md b/Architecture.md new file mode 100644 index 0000000..1ec10b6 --- /dev/null +++ b/Architecture.md @@ -0,0 +1,736 @@ +# Svgbob Architecture and Design phases + +Svgbob creates an svg drawing based on the input ascii art diagrams. +It achieves this by creating a corresponding fragment for each character, and then this little fragments +are then merged to form lines and arcs. The lines and arcs are then endorsed into high level shapes such as rect, circles. + +### Name inspiration: +- svg for svg document and drawing. +- bob for Alice and Bob as common characters in most diagrams + Bob Ross - a painter who like to draws happy little trees. + +### Library used +- [nalgebra](https://www.nalgebra.org/) and [ncollide2d](https://ncollide.org/) for geometric function calculations such as calculating whether lines are intersecting, collinear. Computing the clipping of lines and boxes. +- [pom](https://github.com/J-F-Liu/pom) for parsing the styling directives(Legend) at the bottom of the document +- [sauron](https://github.com/ivanceras/sauron) for building the svg document object tree. + + +### **Iterations, re-architecture rewrites** + +#### Phase 1 +Exploding if statements. This was in elm + [fullcode](https://github.com/ivanceras/elm-examples/blob/master/elm-bot-lines/Grid.elm) + +```elm +getElement x y model = + let + char = get x y model + in + case char of + Just char -> + if isVertical char + && not (isNeighbor left isAlphaNumeric) + && not (isNeighbor right isAlphaNumeric) then + Just Vertical + else if isHorizontal char + && not (isNeighbor left isAlphaNumeric) + && not (isNeighbor right isAlphaNumeric) then + Just Horizontal + else if isIntersection char then + let + isVerticalJunctionLeft = + isNeighbor top isVertical + && isNeighbor(bottomOf x y model) isVertical + && isNeighbor(leftOf x y model) isHorizontal + + isVerticalJunctionRight = + isNeighbor top isVertical + && isNeighbor bottom isVertical + && isNeighbor right isHorizontal + + isHorizontalJunctionTop = + isNeighbor left isHorizontal + && isNeighbor right isHorizontal + && isNeighbor top isVertical + + isHorizontalJunctionBot = + isNeighbor left isHorizontal + && isNeighbor right isHorizontal + && isNeighbor bottom isVertical + + isTopLeftIntersection = + isNeighbor bottom isVertical && isNeighbor right isHorizontal + + isTopRightIntersection = + isNeighbor bottom isVertical && isNeighbor left isHorizontal + + isBottomRightIntersection = + isNeighbor top isVertical && isNeighbor left isHorizontal + + isBottomLeftIntersection = + isNeighbor top isVertical && isNeighbor right isHorizontal + + isCrossIntersection = + isNeighbor top isVertical + && isNeighbor bottom isVertical + && isNeighbor left isHorizontal + && isNeighbor right isHorizontal + + ... 200 more lines... + +``` +Though elm is fast, but if you throw a lot of conditional branching to it, it will slow it down. +At least I don't get to have runtime errors here if it was written in js. +Adding an edgecase is just appending a new if else statement at the bottom of the statements. + +**Pros:** Very simple design. Just if statements and return the appropriate shape the character will take form + Adding edge case behaviour is just appending an `else if` to the nearest conditional(`if`) behavior. + +**Caveats:** The fragments/drawing elements are named. Naming is hard, we can not name all of them. Consistency is broken. + + + + +#### Phase2: +Now in rust. The character behavior is stored in a `Vec<(condition, drawing_elements)>` +This is already close to the current architecture. + + **Improvements:** + - Runs a lot faster than elm. Converting the code from elm to rust, accelerate my learning of the usage of functional programming in rust. + - Consumed elements, if certain group of elements matches a higher level shapes, those elements are consumed/remove from the grid to + avoid generating additional drawing elements when iterated with the rest of the characters in the grid. + + +```rust + //get the paths in the location x,y + //if non path, then see if it can return a text path + fn get_elements(&self, x:isize, y:isize, settings: &Settings) -> Option<Vec<Element>>{ + ... + //common path lines + let vertical = Element::solid_line(center_top, center_bottom); + let horizontal = Element::solid_line(mid_left, mid_right); + let slant_left = Element::solid_line(high_left, low_right); + let slant_right = Element::solid_line(low_left, high_right); + let low_horizontal = Element::solid_line(low_left, low_right); + + + let match_list: Vec<(bool, Vec<Element>)> = + vec![ + /* + .- + | + */ + (self.is_char(this, is_round) + && self.is_char(right, is_horizontal) + && self.is_char(bottom, is_vertical), + vec![cxdy_cxey.clone(), arc_excy_cxdy.clone()] + ), + /* + -. + | + */ + (self.is_char(this, is_round) + && self.is_char(left, is_horizontal) + && self.is_char(bottom, is_vertical), + vec![cxdy_cxey.clone(), arc_cxdy_axcy.clone()] + ), + /* + | + '- + */ + (self.is_char(this, is_round) + && self.is_char(right, is_horizontal) + && self.is_char(top, is_vertical), + vec![cxay_cxby.clone(), arc_cxby_excy.clone()] + ), + /* + | + -' + */ + (self.is_char(this, is_round) + && self.is_char(left, is_horizontal) + && self.is_char(top, is_vertical), + vec![cxay_cxby.clone(), arc_axcy_cxby.clone()] + ), + /* + .- + / + */ + (self.is_char(this, is_round) + && self.is_char(right, is_horizontal) + && self.is_char(bottom_left, is_slant_right), + vec![axey_bxdy.clone(), arc_excy_bxdy.clone()] + ), + /* + -. + \ + */ + (self.is_char(this, is_round) + && self.is_char(left, is_horizontal) + && self.is_char(bottom_right, is_slant_left), + vec![exey_dxdy.clone(), arc_dxdy_axcy.clone()] + ), + /* + -. + / + */ + (self.is_char(this, is_round) + && self.is_char(left, is_horizontal) + && self.is_char(bottom_left, is_slant_right), + vec![axey_bxdy.clone(), arc_bxdy_axcy.clone()] + ), + /* + .- + \ + */ + (self.is_char(this, is_round) + && self.is_char(right, is_horizontal) + && self.is_char(bottom_right, is_slant_left), + vec![exey_dxdy.clone(), arc_excy_dxdy.clone()] + ), + /* + \ + '- + */ + (self.is_char(this, is_round) + && self.is_char(right, is_horizontal) + && self.is_char(top_left, is_slant_left), + vec![axay_bxby.clone(), arc_bxby_excy.clone()] + |