diff options
author | Jovansonlee Cesar <ivanceras@gmail.com> | 2020-02-14 18:05:20 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-14 18:05:20 +0800 |
commit | ef274b7941d3705f93efb97e4f5da92012d9ccd2 (patch) | |
tree | 4e08e7115c235e0d4e4a9272d3dbbeb1e5b50613 | |
parent | 049dcb0ddf4826eb69a6884e7d92efdce0e60c4f (diff) | |
parent | f8d41a7d19447e46b6c5cf6f6e93c4a09203c48f (diff) |
Merge pull request #48 from ivanceras/rewrite3-vectorize
This is the 3rd major rewrite of the core architecture of svgbob.
This provides major improvements in terms of performance, extensibility and modular design.
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), + v |