xbar 1.0.1

An iterator-based implementation of the locality-preserving one-sided binary tree - crossbar switch wiring design algorithm.
Documentation
extern crate clap;
extern crate svg;
extern crate xbar;

use clap::{App, Arg};
use svg::node::element::path::Data;
use svg::node::{element::Path, element::Text as TextBox, Text};
use svg::Document;
use xbar::{Connection, Crossbar};

static BLOCK_W: usize = 20;
static BLOCK_H: usize = 20;
static MARGIN_X: usize = 40;
static MARGIN_Y: usize = 40;
static LEFT_TEXT_PAD: usize = 30;

pub fn main() {
    let matches = App::new("xbar")
        .version("1.0")
        .author("kubuzetto <dvr.sahin@gmail.com>")
        .about("Renders a crossbar switch with N terminals")
        .arg(
            Arg::with_name("num_terms")
                .help("Number of terminals")
                .value_name("count")
                .long("num_terms")
                .takes_value(true)
                .required(true)
                .short("n"),
        )
        .arg(
            Arg::with_name("output")
                .help("Output SVG file path")
                .value_name("filePath")
                .takes_value(true)
                .long("output")
                .required(true)
                .short("o"),
        )
        .get_matches();
    let num = matches
        .value_of("num_terms")
        .unwrap()
        .parse::<usize>()
        .unwrap();
    let path = matches.value_of("output").unwrap();
    render(path, num);
    println!(
        "Crossbar switch with {} terminals was printed to the SVG file {}.",
        num, path
    );
}

fn render(file: &str, n: usize) {
    let w = Crossbar::columns(n) * BLOCK_W + BLOCK_W + 2 * MARGIN_X + LEFT_TEXT_PAD;
    let h = (Crossbar::rows(n) + Crossbar::blocks(n) - 1) * BLOCK_H + 2 * MARGIN_Y;
    let mut doc = Document::new().set("viewBox", (0, 0, w, h)).add(
        Path::new()
            .set("fill", "#ffffff")
            .set("stroke", "#444444")
            .set("stroke-width", 2)
            .set(
                "d",
                Data::new()
                    .move_to((0, 0))
                    .line_to((w, 0))
                    .line_to((w, h))
                    .line_to((0, h))
                    .close(),
            ),
    );
    for val in Crossbar::new(n) {
        doc = render_one(doc, val, n);
    }
    svg::save(file, &doc).unwrap();
}

fn render_one(doc: Document, val: Connection, n: usize) -> Document {
    let l0 = MARGIN_X + LEFT_TEXT_PAD;
    let l1 = l0 + (1 + val.col_idx) * BLOCK_W;
    let t0 = MARGIN_Y + BLOCK_H * (val.start.block_idx * (n + 1) + val.start.row_idx);
    let t1 = MARGIN_Y + BLOCK_H * (val.end.block_idx * (n + 1) + val.end.row_idx);
    doc.add(
        Path::new()
            .set("fill", "none")
            .set("stroke", "black")
            .set("stroke-width", 2)
            .set(
                "d",
                Data::new()
                    .move_to((l0, t0))
                    .line_to((l1, t0))
                    .line_to((l1, t1))
                    .line_to((l0, t1)),
            ),
    )
    .add(
        TextBox::new()
            .set("y", t0 + BLOCK_H / 4)
            .set("x", MARGIN_X)
            .set(
                "style",
                format!(
                    "font-size:{}px; \
                     font-family:sans-serif; \
                     fill:#000000; \
                     fill-opacity:1; \
                     stroke:none;",
                    BLOCK_H
                ),
            )
            .add(Text::new(format!("{}", val.start.row_idx))),
    )
    .add(
        TextBox::new()
            .set("y", t1 + BLOCK_H / 4)
            .set("x", MARGIN_X)
            .set(
                "style",
                format!(
                    "font-size:{}px; \
                     font-family:sans-serif; \
                     fill:#000000; \
                     fill-opacity:1; \
                     stroke:none;",
                    BLOCK_H
                ),
            )
            .add(Text::new(format!("{}", val.end.row_idx))),
    )
}