// Router // Version: 0.1 // Snippets of code used here were taken from https://github.com/infused-kim/kb_ergogen_fp (adjust_oint) // Credits goes to Github infused-kim, Thanks! module.exports = { params: { net: { type: "net", value: "" }, width: { type: "number", value: 0.25 }, route: { type: "string", value: "" }, routes: { type: "array", value: [] }, via_size: { type: "number", value: 0.8 }, via_drill: { type: "number", value: 0.4 }, locked: false, }, body: (p) => { const get_at_coordinates = () => { const pattern = /\(at (-?[\d\.]*) (-?[\d\.]*) (-?[\d\.]*)\)/ const matches = p.at.match(pattern) if (matches && matches.length == 4) { return [ parseFloat(matches[1]), parseFloat(matches[2]), parseFloat(matches[3]), ] } else { return null } } const adjust_point = (x, y) => { const at_l = get_at_coordinates() if (at_l == null) { throw new Error(`Could not get x and y coordinates from p.at: ${p.at}`) } const at_x = at_l[0] const at_y = at_l[1] const at_angle = at_l[2] const radians = (Math.PI / 180) * at_angle, cos = Math.cos(radians), sin = Math.sin(radians), nx = cos * x + sin * y + at_x, ny = cos * y - sin * x + at_y const point_str = `${nx.toFixed(5)/1} ${ny.toFixed(5)/1}` // the division by 1 is to remove trailing zeros return point_str } // (segment (start 108.8 108) (end 109.7 108) (width 0.2) (layer "F.Cu") (net 0)) const get_segment = (start, end, layer, net) => { if (!layer) { throw new Error( "Can't place segment before layer is set, use 'f' or 'b', to set starting layer" ) } return `(segment ${locked}(start ${adjust_point( start[0], start[1] )}) (end ${adjust_point(end[0], end[1])}) (width ${ p.width }) (layer ${layer}) (net ${net}))` } // (via (at 108.8 108) (size 0.8) (drill 0.4) (layers "F.Cu" "B.Cu") (net 0)) const get_via = (pos, net) => { if (!pos) { throw new Error( "Can't place via when position is not set, use (x,y) to set position" ) } return `(via ${locked}(at ${adjust_point(pos[0], pos[1])}) (size ${ p.via_size }) (drill ${p.via_drill}) (layers "F.Cu" "B.Cu") (net ${net}))` } const parse_tuple = (t) => { let str_tuple = JSON.parse(t.replace(/\(/g, "[").replace(/\)/g, "]")) let num_tuple = str_tuple.map((v) => Number(v)) if (isNaN(num_tuple[0] || isNaN(num_tuple[1]))) { throw new Error(`Invalid position encountered: ${str_tuple}`) } return num_tuple } const get_traces = (route, net) => { let traces = "" let layer = undefined let start = undefined // [x, y] for (let i = 0; i < route.length; i++) { ch = route[i].toLowerCase() switch (ch) { case "f": layer = "F.Cu" break case "b": layer = "B.Cu" break case "v": traces = traces + get_via(start, net) + "\n" switch (layer) { case "F.Cu": layer = "B.Cu" break case "B.Cu": layer = "F.Cu" break } break case "(": let tuple_str = "(" let parenthesis_idx = i for (i = i + 1; i < route.length; i++) { let ch = route[i] tuple_str += ch if (route[i] == ")") { break } if (i > route.length) { throw new Error( `Unclosed position parenthesis in ${route} at character position ${parenthesis_idx}` ) } } let pos = parse_tuple(tuple_str) if (start) { traces = traces + get_segment(start, pos, layer, net) + "\n" } start = pos break case "<": let net_name = "" let lt_idx = i for (i = i + 1; i < route.length; i++) { let ch = route[i] if (route[i] == ">") { break } net_name += ch if (i > route.length) { throw new Error( `Unclosed net parenthesis in ${route} at character position ${lt_idx}` ) } } net = p.global_net(net_name) case "x": case "|": start = undefined break default: throw new Error(`Unsupported character '${ch}' at position ${i}.`) } } return traces } const get_routes_traces = (routes, net) => { let routes_traces = routes.reduce((acc_traces, route) => { return acc_traces + get_traces(route, net) }, "") return routes_traces } let combined_traces = "" let locked = p.locked ? 'locked ' : '' if (p.route) { combined_traces += get_traces(p.route, p.net.index) } if (p.routes) { combined_traces += get_routes_traces(p.routes, p.net.index) } return combined_traces }, }