/* library for creating CuVoodoo Land Pattern (cvlp) JSON files and render them Copyright (C) 2015 King Kévin This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // create a set of elements with an line element function cvlp_line(x1, y1, x2, y2, thickness) { var line = {} line.type = "line" line.x1 = x1 line.y1 = y1 line.x2 = x2 line.y2 = y2 line.thickness = thickness return [line] } // create a set of elements with an arc element // arc goes angle degrees clockwise from start function cvlp_arc(x, y, radius, start, angle, thickness) { var arc = {} arc.type = "arc" arc.x = x arc.y = y arc.radius = radius arc.start = start arc.angle = angle arc.thickness = thickness return [arc] } // create a set of elements with an pad element function cvlp_pad(number, x, y, width, height, round) { var pad = {} pad.type = "pad" pad.number = number pad.x = x pad.y = y pad.width = width pad.height = height pad.round = round || true return [pad] } // create a set of elements with an pin element function cvlp_pin(number, x, y, thickness, hole, round) { var pin = {} pin.type = "pin" pin.number = number pin.x = x pin.y = y pin.thickness = thickness pin.hole = hole pin.round = round || true return [pin] } // create a set of elements representing a chain of lines // provide a list of [x,y] coordinates function cvlp_polyline(points, thickness, closed) { var polyline = [] for (var i = 0; i < points.length - 1; i++) { polyline = polyline.concat(cvlp_line(points[i][0], points[i][1], points[i+1][0], points[i+1][1], thickness)) } if (closed || false) { if (points[0][0]!=points[points.length - 1][0] && points[0][1] != points[points.length - 1][1]) { polyline = polyline.concat(cvlp_line(points[points.length - 1][0], points[points.length - 1][1], points[0][0], points[0][1], thickness)) } } return polyline } // create a set of elements representing a rectangle // provide top corner, size, an radius of corner function cvlp_rectangle(x, y, width, height, thickness, radius) { var rectangle = [] rectangle = rectangle.concat(cvlp_line(x + radius, y, x + width - radius, y, thickness)) rectangle = rectangle.concat(cvlp_line(x + width, y + radius, x + width, y + height - radius, thickness)) rectangle = rectangle.concat(cvlp_line(x + width - radius, y + height, x + radius, y + height, thickness)) rectangle = rectangle.concat(cvlp_line(x, y + height - radius, x, y + radius, thickness)) if (radius !== 'undefined' && radius != 0) { rectangle = rectangle.concat(cvlp_arc(x + radius, y + radius, radius, 180, 90, thickness)) rectangle = rectangle.concat(cvlp_arc(x + width - radius, y + radius, radius, 270, 90, thickness)) rectangle = rectangle.concat(cvlp_arc(x + width - radius, y + width - radius, radius, 0, 90, thickness)) rectangle = rectangle.concat(cvlp_arc(x + radius, y + width - radius, radius, 90, 90, thickness)) } return rectangle } // convert value from one unit to another // units allowed: mm, in, mil // returns converted value, on null if unknown unit function convert_unit(value, from, to) { // don't convert if the unit is the same (avoid calculation imprecisions) if (from==to) { return value; } // convert to µm var mum = 0; switch (from) { case 'mm': mum = value * 1000; break; case 'in': mum = value * 1000 * 25.40; break; case 'mil': mum = value * 25.40; break; default: return null; } switch (to) { case 'mm': mum = mum / 1000; break; case 'in': mum = mum / 1000 / 25.40; break; case 'mil': mum = mum / 25.40; break; default: return null; } return mum; } // convert JSON to SVG function json2svg(json) { // create svg var svgNS = "http://www.w3.org/2000/svg" svg = document.createElementNS(svgNS, 'svg') svg.setAttribute('xmlns', svgNS) svg.setAttribute('version', 1.1) svg.setAttribute('xmlns:inkscape', 'http://www.inkscape.org/namespaces/inkscape') // set unit if (json.unit == "mil") { // mil units are not supported in SVG, convert to inch svg.setAttribute('height', (json.height / 1000) + 'in') svg.setAttribute('width', (json.width/1000) + 'in') } else { svg.setAttribute('height', json.height + '' + json.unit) svg.setAttribute('width', json.width + '' + json.unit) } svg.setAttribute('viewBox', '0 0 ' + json.width + ' ' + json.height) // add info var svg_title = document.createElementNS(svgNS, 'title'); svg_title.textContent = json.name; svg.appendChild(svg_title); // add layers layers_desc = [ { name: 'copper', stroke: 'gray', fill: 'gray'}, { name: 'hole', stroke: 'none', fill: 'white'}, { name: 'silkscreen', stroke: 'black', fill: 'none', 'stroke-linecap': 'round'} ] layers = [] for (layer_i in layers_desc) { var layer_desc = layers_desc[layer_i] var layer = document.createElementNS(svgNS, 'g') layer.setAttribute('inkscape:groupmode', 'layer') layer.setAttribute('inkscape:label', layer_desc.name) for (key in layer_desc) { layer.setAttribute(key, layer_desc[key]) } svg.appendChild(layer) layers[layer_desc.name] = layer } for (var element_i in json.elements) { var element = json.elements[element_i] switch (element.type) { case 'line': var line = document.createElementNS(svgNS, 'line') line.setAttribute('x1', element.x1) line.setAttribute('y1', element.y1) line.setAttribute('x2', element.x2) line.setAttribute('y2', element.y2) line.style.setProperty('stroke-width', element.thickness) layers['silkscreen'].appendChild(line) break case 'arc': element.start = (element.start + 360) % 360 element.stop = (element.stop + 360) % 360 var arc = null if (element.start == element.stop) { arc = document.createElementNS(svgNS, 'circle') arc.setAttribute('cx', element.x) arc.setAttribute('cy', element.y) arc.setAttribute('r', element.radius) } else { var x1 = element.x + element.radius * Math.cos(((-1 * element.start) % 360) / 360.0 * Math.PI * 2) var y1 = element.y - element.radius * Math.sin(((-1 * element.start) % 360) / 360.0 * Math.PI * 2) var x2 = element.x + element.radius * Math.cos(((-1 * (element.start + element.angle)) % 360) / 360.0 * Math.PI * 2) var y2 = element.y - element.radius * Math.sin(((-1 * (element.start + element.angle)) % 360) / 360.0 * Math.PI * 2) arc = document.createElementNS(svgNS, 'path') arc.setAttribute('d', 'M ' + x1 + ' ' + y1 + ' A ' + element.radius + ' ' + element.radius + ' 0 ' + ((element.angle) % 360 > 180 ? '1' : '0') + ' 1 ' + x2 + ' ' + y2 + ' ') } arc.style.setProperty('stroke-width', element.thickness) layers['silkscreen'].appendChild(arc) break case 'pad': var copper = document.createElementNS(svgNS, 'rect') copper.style.setProperty('stroke-width', 0) copper.setAttribute('x', element.x - element.width / 2) copper.setAttribute('y', element.y - element.height / 2) copper.setAttribute('width', element.width) copper.setAttribute('height', element.height) if (element.round) { copper.setAttribute('rx', Math.min(element.width, element.height) / 2) copper.setAttribute('ry', Math.min(element.width, element.height) / 2) } else { copper.setAttribute('rx', 0) copper.setAttribute('ry', 0) } layers['copper'].appendChild(copper) break case 'pin': break var copper = document.createElementNS(svgNS, 'rect') copper.style.setProperty('stroke-width', 0) copper.setAttribute('x', element.x - element.thickness / 2) copper.setAttribute('y', element.y - element.thickness / 2) copper.setAttribute('height', element.thickness) copper.setAttribute('width',element.thickness) if (element.round) { copper.setAttribute('rx', element.thickness / 2) copper.setAttribute('ry', element.thickness / 2) } else { copper.setAttribute('rx', 0) copper.setAttribute('ry', 0) } layers['copper'].appendChild(copper) var hole = document.createElementNS(svgNS, 'circle') hole.style.setProperty('stroke-width', 0) hole.setAttribute('cx', element.x) hole.setAttribute('cy', element.y) hole.setAttribute('r', element.hole / 2) layers['hole'].appendChild(hole) break default: console.log('unknown element type: ' + element.type) } } return svg } // convert CuVoodoo Land Pattern JSON to gEDA pcb footprint function json2pcb(json) { // create file and add info var pcb = '' pcb += '# footprint generated from CuVoodoo Land Pattern\n' pcb += '# author: ' + json.author + '\n' pcb += '# version: ' + json.version + '\n' pcb += '# date: ' + json.date + '\n' pcb += 'Element["" "' + json.name + '" "" "" 0 0 0 0 0 100 ""]\n' pcb += '(\n' // add element parts for (var element_i in json.elements) { var element = json.elements[element_i] switch (element.type) { case 'line': pcb += 'ElementLine[' + element.x1 + '' + json.unit + ' ' + element.y1 + '' + json.unit + ' ' + element.x2 + '' + json.unit + ' ' + element.y2 + '' + json.unit + ' ' + element.thickness + '' + json.unit + ']\n' break case 'arc': pcb += 'ElementArc[' + element.x + '' + json.unit + ' ' + element.y + '' + json.unit + ' ' + element.radius + '' + json.unit + ' ' + element.radius + '' + json.unit + ' ' + ((((180 - element.start) % 360) + 360) % 360) + ' ' + (-1 * (element.angle)) + ' ' + element.thickness + '' + json.unit + ']\n' break case 'pad': var x1, y1, x2, y2, thickness if (element.width > element.height) { x1 = element.x - element.width / 2 + element.height / 2 y1 = element.y x2 = element.x + element.width / 2 - element.height / 2 y2 = element.y thickness = element.height } else { x1 = element.x y1 = element.y - element.height / 2 + element.width / 2 x2 = element.x y2 = element.y + element.height / 2 - element.width / 2 thickness = element.width } pcb += 'Pad[' + x1 + '' + json.unit + ' ' + y1 + '' + json.unit + ' ' + x2 + '' + json.unit + ' ' + y2 + '' + json.unit + ' ' + thickness + '' + json.unit + ' ' + 0 + '' + json.unit + ' ' + thickness + '' + json.unit + ' "" "' + element.number + '" "' if (!element.round) { pcb += 'square' } pcb += '"]\n' break case 'pin': pcb += 'Pin[' + element.x + '' + json.unit + ' ' + element.y + '' + json.unit + ' ' + element.thickness + '' + json.unit + ' ' + 0 + '' + json.unit + ' ' + thickness + '' + json.unit + ' ' + element.hole + '' + json.unit + ' "" "' + element.number + '" "' if (!element.round) { pcb += 'square' } pcb += '"]\n' break default: console.log('unknown element type: ' + element.type) } } pcb += ')\n' return pcb } // convert CuVoodoo Land Pattern JSON to KiCad s-expression footprint module/file function json2kicad(json) { // create file and add info var kicad = '' kicad += '# footprint generated from CuVoodoo Land Pattern\n' kicad += '# author: ' + json.author + '\n' kicad += '# version: ' + json.version + '\n' kicad += '# date: ' + json.date + '\n' kicad += '(module "' + json.name + '" (layer F.Cu)\n' // add element parts for (var element_i in json.elements) { var element = json.elements[element_i] switch (element.type) { case 'line': kicad += '(fp_line (start ' + convert_unit(element.x1, json.unit, 'mm') + ' ' + convert_unit(element.y1, json.unit, 'mm') + ') (end ' + convert_unit(element.x2, json.unit, 'mm') + ' ' + convert_unit(element.y2, json.unit , 'mm') + ') (layer F.SilkS) (width ' + convert_unit(element.thickness, json.unit, 'mm') + '))\n' break case 'arc': kicad += '(fp_arc (start ' + convert_unit(element.x, json.unit, 'mm') + ' ' + convert_unit(element.y, json.unit, 'mm') + ') (end ' + convert_unit((element.x + element.radius * Math.cos(((-1 * element.start) % 360) / 360.0 * Math.PI * 2)), json.unit, 'mm') + ' ' + convert_unit((element.y - element.radius * Math.sin(((-1 * element.start) % 360) / 360.0 * Math.PI * 2)), json.unit, 'mm') + ') (angle ' + element.angle + ') (layer F.SilkS) (width ' + convert_unit(element.thickness, json.unit, 'mm') + '))\n' break case 'pad': kicad += '(pad "' + element.number + '" smd ' if (element.round) { kicad += 'oval' } else { kicad += 'rect' } kicad += ' (at ' + convert_unit(element.x, json.unit, 'mm') + ' ' + convert_unit(element.y, json.unit, 'mm') + ')' kicad += ' (size ' + convert_unit(element.width, json.unit, 'mm') + ' ' + convert_unit(element.height, json.unit, 'mm') + ')' kicad += ' (layers F.Cu F.Paste F.Mask)' kicad += ')\n' break case 'pin': var x = (element.x1 + element.x2) / 2 var y = (element.y1 + element.y2) / 2 var length = Math.sqrt(Math.pow(element.x2 - element.x1, 2) + Math.pow(element.y2 - element.y1, 2)) var angle = Math.atan2(element.y2 - element.y1, element.x2 - element.x1) * 180 / Math.PI; kicad += '(pad "' + element.number + '" smd ' if (element.round) { kicad += 'oval' } else { kicad += 'rect' } kicad += ' (at ' + convert_unit(x, json.unit, 'mm') + ' ' + convert_unit(y, json.unit, 'mm') + ' ' + angle + ')' kicad += ' (size ' + convert_unit(length, json.unit, 'mm') + ' ' + convert_unit(element.thickness, json.unit, 'mm') + ')' kicad += ' (drill ' + convert_unit(element.hole, json.unit, 'mm') kicad += ' (layers F.Cu F.Paste F.Mask)' kicad += ')\n' break default: console.log('unknown element type: ' + element.type) } } kicad += ')\n' return kicad } // convert JSON to eagle library function json2eagle(json) { // create eagle xml library var docType = document.implementation.createDocumentType('eagle', 'SYSTEM', 'eagle.dtd') var xml = document.implementation.createDocument('', 'eagle', docType) xml.documentElement.setAttribute('version','6.0') var comment = xml.createComment('footprint generated from CuVoodoo Land Pattern, author: ' + json.author + ', version: ' + json.version + ', date: ' + json.date) xml.documentElement.appendChild(comment) var drawing = xml.createElement('drawing') xml.documentElement.appendChild(drawing) // add layers var layers = xml.createElement('layers') drawing.appendChild(layers) layers_desc = [ { number: 1, name: 'Top', color: 4, fill: 1, visible: 'yes', active: 'yes'}, { number: 17, name: 'Pads', color: 2, fill: 1, visible: 'yes', active: 'yes'}, { number: 21, name: 'tPLace', color: 7, fill: 1, visible: 'yes', active: 'yes'}, ] for (layer_i in layers_desc) { var layer_desc = layers_desc[layer_i] var layer = xml.createElement('layer') for (key in layer_desc) { layer.setAttribute(key,layer_desc[key]) } layers.appendChild(layer) } // create library var library = xml.createElement('library') drawing.appendChild(library) // add description var description = xml.createElement('description') description.textContent = json.name library.appendChild(description) // add package var packages = xml.createElement('packages') library.appendChild(packages) var packag = xml.createElement('package') packag.setAttribute('name','OSHW') packages.appendChild(packag) var desc = xml.createElement('description') desc.textContent = json.name packag.appendChild(desc) // add element parts // note: in eagle the origin is the bottom left corner (negate y to be compatible with the json coordinate system) for (var element_i in json.elements) { var element = json.elements[element_i] switch (element.type) { case 'line': var line = xml.createElement('wire') line.setAttribute('x1', convert_unit(element.x1, json.unit, 'mm')) line.setAttribute('y1', convert_unit(-1 * element.y1, json.unit, 'mm')) line.setAttribute('x2', convert_unit(element.x2, json.unit, 'mm')) line.setAttribute('y2', convert_unit(-1 * element.y2, json.unit, 'mm')) line.setAttribute('width', convert_unit(element.thickness, json.unit, 'mm')) line.setAttribute('layer', '21') packag.appendChild(line) break case 'arc': var wire = xml.createElement('wire') wire.setAttribute('x1', convert_unit(element.x + element.radius * Math.cos(((-1 * element.start) % 360) / 360.0 * Math.PI * 2), json.unit, 'mm')) wire.setAttribute('y1', convert_unit(-1 * element.y + element.radius * Math.sin(((-1 * element.start) % 360) / 360.0 * Math.PI * 2), json.unit, 'mm')) wire.setAttribute('x2', convert_unit(element.x + element.radius * Math.cos(((-1 * (element.start + element.angle)) % 360) / 360.0 * Math.PI * 2), json.unit, 'mm')) wire.setAttribute('y2', convert_unit(-1 * element.y + element.radius * Math.sin(((-1 * (element.start + element.angle)) % 360) / 360.0 * Math.PI * 2), json.unit, 'mm')) wire.setAttribute('curve',-1 * element.angle) wire.setAttribute('width', convert_unit(element.thickness, json.unit,'mm')) wire.setAttribute('layer', '21') wire.setAttribute('cap', 'round') packag.appendChild(wire) break case 'pad': var pad = xml.createElement('smd') pad.setAttribute('name', element.number) pad.setAttribute('x', convert_unit(element.x, json.unit, 'mm')) pad.setAttribute('y', convert_unit(-1 * element.y, json.unit, 'mm')) pad.setAttribute('dx', convert_unit(element.width, json.unit, 'mm')) pad.setAttribute('dy', convert_unit(element.height, json.unit, 'mm')) pad.setAttribute('layer', '1') if (element.round) { pad.setAttribute('roundness', 100) } else { pad.setAttribute('roundness', 0) } packag.appendChild(pad) break case 'pin': var pin = xml.createElement('pad') pin.setAttribute('name', element.number) pin.setAttribute('x', convert_unit(element.x, json.unit, 'mm')) pin.setAttribute('y', convert_unit(-1 * element.y, json.unit, 'mm')) pin.setAttribute('drill', convert_unit(element.hole, json.unit, 'mm')) pin.setAttribute('diameter', convert_unit(element.thickness, json.unit, 'mm')) pin.setAttribute('layer', '17') if (element.round) { pin.setAttribute('shape', 'round') } else { pin.setAttribute('shape', 'square') } packag.appendChild(pin) break default: console.log('unknown element type: ' + element.type) } } return xml } // convert CuVoodoo Land Pattern JSON to coralEDA subscircuit function json2subc(json) { // create file and add info var subc = '' subc += '# footprint generated from CuVoodoo Land Pattern\n' subc += '# author: ' + json.author + '\n' subc += '# version: ' + json.version + '\n' subc += '# date: ' + json.date + '\n' id = 1 // global subc id subc += 'li:pcb-rnd-subcircuit-v6 {\n' subc += ' ha:subc.' + (id++) + ' {\n' subc += ' uid = any_24_ASCII_characters_\n' subc += ' ha:attributes {\n' subc += ' footprint = ' + json.name + '\n' subc += ' }\n' subc += ' ha:data {\n' // try to group the pads/pins function element_generic(element) { generic = JSON.parse(JSON.stringify(element)) delete generic.x delete generic.y delete generic.number return generic } // get pins/pads padstacks = [] for (var element_i in json.elements) { var element = json.elements[element_i] if (element.type == 'pin' || element.type == 'pad') { padstacks.push(element_generic(element)) } } padstacks = padstacks.map((value) => JSON.stringify(value)) padstacks = padstacks.filter((value, index, self) => self.indexOf(value) == index) padstacks = padstacks.map((value) => JSON.parse(value)) // add padstacks prototypes id = 2 subc += ' li:padstack_prototypes {\n' for (var padstack_i in padstacks) { var padstack = padstacks[padstack_i] switch (padstack.type) { case 'pad': subc += ' ha:ps_proto_v6.' + (id++) + ' {\n' subc += ' htop = 0\n' subc += ' hbottom = 0\n' subc += ' hdia = 0\n' subc += ' hplated = 0\n' subc += ' li:shape {\n' var line = '' line += ' ha:ps_line {\n' var x1, y1, x2, y2, thickness if (padstack.width > padstack.height) { x1 = - padstack.width / 2 + padstack.height / 2 y1 = 0 x2 = padstack.width / 2 - padstack.height / 2 y2 = 0 thickness = padstack.height } else { x1 = 0 y1 = - padstack.height / 2 + padstack.width / 2 x2 = 0 y2 = padstack.height / 2 - padstack.width / 2 thickness = padstack.width } line += ' x1 = ' + x1 + json.unit + '\n' line += ' y1 = ' + y1 + json.unit + '\n' line += ' x2 = ' + x2 + json.unit + '\n' line += ' y2 = ' + y2 + json.unit + '\n' line += ' thickness =' + thickness + json.unit + '\n' line += ' square = ' + (padstack.round ? '0' : '1') + '\n' line += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += line subc += ' ha:layer_mask {\n' subc += ' top = 1\n' subc += ' copper = 1\n' subc += ' }\n' subc += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += line subc += ' ha:layer_mask {\n' subc += ' top = 1\n' subc += ' mask = 1\n' subc += ' }\n' subc += ' ha:combining {\n' subc += ' sub = 1\n' subc += ' auto = 1\n' subc += ' }\n' subc += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += line subc += ' ha:layer_mask {\n' subc += ' top = 1\n' subc += ' paste = 1\n' subc += ' }\n' subc += ' ha:combining {\n' subc += ' auto = 1\n' subc += ' }\n' subc += ' }\n' subc += ' }\n' subc += ' }\n' break case 'pin': subc += ' ha:ps_proto_v6.' + (id++) + ' {\n' subc += ' htop = 0\n' subc += ' hbottom = 0\n' subc += ' hdia = ' + element.hole + json.unit + '\n' subc += ' hplated = ' + (element.thickness > element.hole ? '1' : '0') + '\n' subc += ' li:shape {\n' var circle = '' circle += ' ha:ps_circ {\n' circle += ' x = 0\n' circle += ' y = 0\n' circle += ' dia = ' + element.thickness + json.unit + '\n' circle += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += circle subc += ' ha:layer_mask {\n' subc += ' top = 1\n' subc += ' copper = 1\n' subc += ' }\n' subc += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += circle subc += ' ha:layer_mask {\n' subc += ' top = 1\n' subc += ' mask = 1\n' subc += ' }\n' subc += ' ha:combining {\n' subc += ' sub = 1\n' subc += ' auto = 1\n' subc += ' }\n' subc += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += circle subc += ' ha:layer_mask {\n' subc += ' intern = 1\n' subc += ' copper = 1\n' subc += ' }\n' subc += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += circle subc += ' ha:layer_mask {\n' subc += ' bottom = 1\n' subc += ' copper = 1\n' subc += ' }\n' subc += ' }\n' subc += ' ha:ps_shape_v4 {\n' subc += ' clearance = 0\n' subc += circle subc += ' ha:layer_mask {\n' subc += ' bottom = 1\n' subc += ' mask = 1\n' subc += ' }\n' subc += ' ha:combining {\n' subc += ' sub = 1\n' subc += ' auto = 1\n' subc += ' }\n' subc += ' }\n' subc += ' }\n' subc += ' }\n' break } } subc += ' }\n' // end padstack_prototypes // add pads/pins subc += ' li:objects {\n' for (var element_i in json.elements) { var element = json.elements[element_i] if (element.type != 'pin' && element.type != 'pad') { continue } padstack = padstacks.map((value) => JSON.stringify(value)).indexOf(JSON.stringify(element_generic(element))) if (padstack < 0) { continue } subc += ' ha:padstack_ref.' + (id++) + '{\n' subc += ' proto = ' + (2 + padstack) + '\n' subc += ' rot = 0\n' subc += ' x = ' + element.x + json.unit + '\n' subc += ' y = ' + element.y + json.unit + '\n' subc += ' ha:attributes {\n' subc += ' term = ' + element.number + '\n' subc += ' name = ' + element.number + '\n' subc += ' }\n' subc += ' }\n' } subc += ' }\n' // end objects // add silkscreen subc += ' li:layers {\n' subc += ' ha:top-silkscreen {\n' subc += ' lid = 1\n' subc += ' ha:type {\n' subc += ' top = 1\n' subc += ' silk = 1\n' subc += ' }\n' subc += ' li:objects {\n' for (var element_i in json.elements) { var element = json.elements[element_i] switch (element.type) { case 'line': subc += ' ha:line.' + (id++) + '{\n' subc += ' clearance = 0\n' subc += ' x1 = ' + element.x1 + json.unit + '\n' subc += ' y1 = ' + element.y1 + json.unit + '\n' subc += ' x2 = ' + element.x2 + json.unit + '\n' subc += ' y2 = ' + element.y2 + json.unit + '\n' subc += ' thickness = ' + element.thickness + json.unit + '\n' subc += ' }\n' break case 'arc': subc += ' ha:arc.' + (id++) + '{\n' subc += ' clearance = 0\n' subc += ' x = ' + element.x + json.unit + '\n' subc += ' y = ' + element.y + json.unit + '\n' subc += ' width = ' + element.radius + json.unit + '\n' subc += ' height = ' + element.radius + json.unit + '\n' subc += ' thickness = ' + element.thickness + json.unit + '\n' subc += ' astart = ' + ((element.start * -1 + 180) % 360) + '\n' subc += ' adelta = ' + (element.angle * -1) + '\n' subc += ' }\n' break } if (element.type != 'pin' && element.type != 'pad') { continue } padstack = padstacks.map((value) => JSON.stringify(value)).indexOf(JSON.stringify(element_generic(element))) if (padstack < 0) { continue } subc += ' ha:padstack_ref.' + (id++) + '{\n' subc += ' proto = ' + (2 + padstack) + '\n' subc += ' rot = 0\n' subc += ' x = ' + element.x + json.unit + '\n' subc += ' y = ' + element.y + json.unit + '\n' subc += ' ha:attributes {\n' subc += ' term = ' + element.number + '\n' subc += ' name = ' + element.number + '\n' subc += ' }\n' subc += ' }\n' } subc += ' }\n' // end objects subc += ' }\n' // end silkscreen subc += ' }\n' // end layers subc += ' }\n' // end data subc += ' }\n' // end subc subc += '}\n' // end pcb-rnd-subcircuit-v6 return subc }