## ----setup, include=FALSE----------------------------------------------------- library(knitr) opts_chunk$set( cache = TRUE, echo = TRUE, eval = TRUE, fig.align = "left", fig.height = 6, fig.width = 6, message = FALSE, out.extra = "", results = "hold", warning = FALSE ) ## Render a Graphviz/DOT diagram directly from its source to a vector PDF. The class ## diagrams, the algorithm flow chart, and the Engine call graphs in this vignette are ## therefore generated from code (and stay in sync with it) instead of being maintained ## as static images (#75). Uses DiagrammeRsvg + rsvg, so no headless browser is required. renderDot <- function(dot) { svg <- DiagrammeRsvg::export_svg(DiagrammeR::grViz(dot)) out <- fig_path(".pdf") dir.create(dirname(out), recursive = TRUE, showWarnings = FALSE) rsvg::rsvg_pdf(charToRaw(svg), out) include_graphics(out) } ## ----flowchart, echo = FALSE, out.width = "62%", fig.cap = "Overview of the MPG algorithm."---- renderDot(' digraph mpg_algorithm { graph [fontsize = 10, rankdir = TB] node [fontname = Courier, fontsize = 10] init [shape = oval, label = "initialize()"] patches [shape = box, label = "findPatches(): seed the Voronoi map and\\liLinkMap cell ids, then build the initial\\lactive cells (patch cells spread at the\\luniform minimum cost)\\l"] loop [shape = diamond, height = 1.1, label = "active\\ncells\\nremain?"] check [shape = box, label = "activeCellSpreadChecker(): a cell whose\\lwaiting time has reached its resistance is\\lmarked settled and queued to spread (the\\lqueue is sorted by effective distance)\\l"] spread [shape = box, label = "createActiveCell(): spread into the 4 adjacent\\lunclaimed cells, assign the Voronoi id, and\\lconnectCell() back to the parent\\l"] link [shape = box, label = "createLinks() / findPath(): at a boundary\\lbetween two settled patches, record the\\lleast-cost link (keep the cheapest; drop\\lredundant indirect and malformed links)\\l"] out [shape = oval, label = "write the Voronoi map\\land links to output"] init -> patches -> loop loop -> check [label = " yes"] check -> spread -> link -> loop loop -> out [label = " no"] } ') ## ----cells_diagram, echo = FALSE, out.width = "62%", fig.cap = "Schematic representation of Cell type data structures. An open triangle denotes inheritance."---- renderDot(' digraph cells { graph [rankdir = BT, fontsize = 10] node [shape = record, fontname = Courier, fontsize = 10] Cell [label = "{Cell|+ row : int\\l+ column : int\\l+ id : float\\l}"] ActiveCell [label = "{ActiveCell|+ time : float\\l+ distance : float\\l+ resistance : float\\l+ parentResistance : float\\l+ originCell : Cell\\l}"] LinkCell [label = "{LinkCell|+ fromCell : Cell\\l+ originCell : Cell\\l+ distance : float\\l+ cost : float\\l}"] edge [arrowhead = onormal] ActiveCell -> Cell LinkCell -> Cell } ') ## ----data_struct_diagram, echo = FALSE, out.width = "98%", fig.cap = "Schematic representation of additional data structures. An open diamond denotes composition (a 'has-a' relationship); dashed boxes are the Cell types shown above."---- renderDot(' digraph data_struct { graph [rankdir = TB, fontsize = 10] node [shape = record, fontname = Courier, fontsize = 10] InputData [label = "{InputData|+ cost_vec : vector\\\\l+ nrow : int\\l+ ncol : int\\l+ patch_vec : vector\\\\l}"] OutputData [label = "{OutputData|+ voronoi_map : vector\\\\l+ patch_map : vector\\\\l+ link_data : vector\\\\l+ patch_list : vector\\\\l}"] Link [label = "{Link|+ start : Cell\\l+ end : Cell\\l+ connection : vector\\\\l+ cost : float\\l}"] Patch [label = "{Patch|+ body : vector\\\\l+ id : float\\l}"] ActiveCellHolder [label = "{ActiveCellHolder|+ value : float\\l+ list : vector\\\\l|+ add(ActiveCell)\\l+ size() : int\\l}"] ActiveCellQueue [label = "{ActiveCellQueue|+ holder_list : vector\\\\l|+ insertH(ActiveCellHolder)\\l+ size() : int\\l}"] node [shape = box, style = dashed] Cell; ActiveCell edge [arrowhead = odiamond, fontname = Courier, fontsize = 9] ActiveCellQueue -> ActiveCellHolder [label = " holder_list"] ActiveCellHolder -> ActiveCell [label = " list"] OutputData -> Link [label = " link_data"] OutputData -> Patch [label = " patch_list"] Link -> Cell [label = " start, end,\\l connection"] Patch -> Cell [label = " body"] } ') ## ----typedef_diagram, echo = FALSE, out.width = "82%", fig.cap = "Schematic representation of type definitions."---- renderDot(' digraph typedefs { graph [rankdir = LR, fontsize = 10, nodesep = 0.4, ranksep = 0.7] node [shape = box, fontname = Courier, fontsize = 10] flCol [label = "flCol\\n= vector"] flMap [label = "flMap\\n= vector"] lcCol [label = "lcCol\\n= vector"] LinkMap [label = "LinkMap\\n= vector"] boolCol [label = "boolCol\\n= vector"] boolMap [label = "boolMap\\n= vector"] edge [arrowhead = vee, fontname = Courier, fontsize = 9] flCol -> flMap [label = " vector of"] lcCol -> LinkMap [label = " vector of"] boolCol -> boolMap [label = " vector of"] } ') ## ----engine_class_diagram, echo = FALSE, out.width = "72%", fig.cap = "Schematic representation of the Engine class. A leading + marks a public member and - a private member; related methods are grouped on a line. Full signatures are given in the tables below."---- renderDot(' digraph engine { graph [fontsize = 10] node [shape = record, fontname = Courier, fontsize = 10] Engine [label = "{Engine|- in_data : InputData*\\l- out_data : OutputData*\\l- maxCost : float\\l- costRes : float\\l- active_cell_holder : ActiveCellQueue\\l- temporary_active_cell_holder : ActiveCellQueue\\l- spread_list : vector\\\\l- iLinkMap : LinkMap\\l- voronoi_map : flMap\\l- cost_map : flMap\\l- settled_map : boolMap\\l- initialized : bool\\l- error_message : char*\\l- error_message_size : int\\l|+ Engine() / ~Engine()\\l+ initialize() : bool\\l+ start() : void\\l+ emax() / emin() / calcDistance() [static]\\l- findPatches() / getIndexFromList() / combinePatches()\\l- activeCellSpreadChecker() / createActiveCell()\\l- createLinks() / findPath() / parseMap() / lookForIndirectPath()\\l- connectCell() / cellIsZero() / cellsEqual() / outOfBounds()\\l- updateOutputMap() / writeErrorMessage()\\l}"] } ') ## ----call_graph_engine_initialize, echo = FALSE, out.width = "50%", fig.cap = "Call diagram for Engine::initialize()"---- renderDot(' digraph initialize { graph [overlap = true, fontsize = 10] # nodes node [fillcolor = navy, fontcolor = white, fontname = Courier, shape = oval, style = filled] initialize node [fillcolor = grey50, fontcolor = white, fontname = Courier, shape = box, style = filled] cellIsZero; combinePatches; findPatches; getIndexFromList; outOfBounds; updateOutputMap; writeErrorMessage; # edges initialize->cellIsZero initialize->findPatches initialize->updateOutputMap initialize->writeErrorMessage cellIsZero->outOfBounds findPatches->combinePatches findPatches->getIndexFromList findPatches->outOfBounds } ') ## ----call_graph_engine_start, echo = FALSE, out.width = "60%", fig.cap = "Call diagram for Engine::start()"---- renderDot(' digraph start { graph [overlap = true, fontsize = 10] # nodes node [fillcolor = navy, fontcolor = white, fontname = Courier, shape = oval, style = filled] start node [fillcolor = grey50, fontcolor = white, fontname = Courier, shape = box, style = filled] activeCellSpreadChecker; calcDistance; cellsEqual; connectCell; createActiveCell; createLinks; findPath; lookForIndirectPath; outOfBounds; parseMap; updateOutputMap; writeErrorMessage; # edges start->activeCellSpreadChecker start->createActiveCell start->createLinks start->updateOutputMap start->writeErrorMessage createActiveCell->calcDistance createActiveCell->connectCell createActiveCell->outOfBounds createLinks->findPath createLinks->outOfBounds findPath->parseMap findPath->lookForIndirectPath parseMap->cellsEqual } ')