///|
/// A graph of motif nodes used to coordinate repeated and connected decorations.
pub(all) struct MotifGraph {
nodes : Array[Motif]
edges : Array[(Int, Int)]
} derive(Debug)
///|
pub fn MotifGraph::new() -> MotifGraph {
{ nodes: [], edges: [] }
}
///|
pub fn MotifGraph::add_node(self : MotifGraph, motif : Motif) -> Int {
self.nodes.push(motif)
self.nodes.length() - 1
}
///|
pub fn MotifGraph::connect(self : MotifGraph, left : Int, right : Int) -> Bool {
if left < 0 ||
right < 0 ||
left >= self.nodes.length() ||
right >= self.nodes.length() {
false
} else {
self.edges.push((left, right))
true
}
}
///|
pub fn MotifGraph::neighbors(self : MotifGraph, node : Int) -> Array[Int] {
let result = []
for edge in self.edges {
if edge.0 == node {
result.push(edge.1)
} else if edge.1 == node {
result.push(edge.0)
}
}
result
}
///|
pub fn MotifGraph::connected_components(self : MotifGraph) -> Array[Array[Int]] {
let visited = []
for _ in 0.. 0 {
let node = queue.remove(0)
component.push(node)
for neighbor in self.neighbors(node) {
if !visited[neighbor] {
visited[neighbor] = true
queue.push(neighbor)
}
}
}
components.push(component)
}
}
components
}
///|
pub fn MotifGraph::bounds(self : MotifGraph) -> Rect {
let points = []
for node in self.nodes {
points.push(node.anchor)
}
bounds_of_points(points)
}
///|
pub fn MotifGraph::translate(self : MotifGraph, offset : Vec2) -> MotifGraph {
let nodes = []
for node in self.nodes {
nodes.push(
node.placed(
node.anchor.x + offset.x,
node.anchor.y + offset.y,
node.scale,
node.rotation,
),
)
}
{ nodes, edges: self.edges }
}
///|
pub fn MotifGraph::to_document(
self : MotifGraph,
width : Double,
height : Double,
background : Color,
) -> SvgDocument {
let document = SvgDocument::new(width, height)
document.add(
SvgElement::SvgPath(
Path::rect(width, height),
SvgStyle::new(fill=background.to_hex(), stroke="none"),
),
)
for edge in self.edges {
let left = self.nodes[edge.0].anchor
let right = self.nodes[edge.1].anchor
document.add_line(
left,
right,
SvgStyle::new(fill="none", stroke="#999999", stroke_width=0.5),
)
}
for node in self.nodes {
document.add(SvgElement::SvgPath(node.transformed_path(), node.style))
}
document
}