first commit: generating log, svg, pcb, kicad is done. changing unit is WiP
This commit is contained in:
commit
224e4d61a6
60
cvlp_format.txt
Normal file
60
cvlp_format.txt
Normal file
@ -0,0 +1,60 @@
|
||||
// CuVoodoo Land Pattern files (.cvlp) define the land pattern (aka. footprint) of electronic components (used in printed circuit boards)
|
||||
// it is intended to be used in web applications, thus it uses the JSON file format
|
||||
// it can then be rendered to various other formats, such as SVG, Gerber-X, gEDA pcb, KiCAD, or eagleCAD
|
||||
{
|
||||
// name of the land pattern (for the electronic component)
|
||||
"name": "CuVoodoo Land Pattern template",
|
||||
// name of the author
|
||||
"author": "King Kevin",
|
||||
// version of the file
|
||||
"version": 0,
|
||||
// date of creation (RFC 3339 seconds format)
|
||||
"date": "2015-04-11 13:58:46+02:00",
|
||||
// unit of dimensions
|
||||
"unit": "mm",
|
||||
// the parts of the land pattern
|
||||
"elements" : [
|
||||
{
|
||||
"type": "line", // a line (on silk screen layer)
|
||||
"x1": 0, // start horizontal position of line
|
||||
"y1": 0, // start vertical position of line
|
||||
"x2": 100, // end horizontal position of line
|
||||
"y2": 100, // end vertical position of the line
|
||||
"thickness": 10, // thickness of line
|
||||
"round": true, // round or square edges to start/stop of line (adds thickness/2 to line)
|
||||
},
|
||||
{
|
||||
"type": "arc", // a circle arc (on silk screen layer)
|
||||
"x": 50, // center horizontal position of circle
|
||||
"y": 50, // center vertical position of circle
|
||||
"radius": 20, // radius of circle
|
||||
"start": 0, // start point of arc (0=east, 90=south, 180=west, 270=north)
|
||||
"angle": 0, // angle of clockwise arc (can be negative)
|
||||
"thickness": 10, // thickness of trace
|
||||
"round": true, // round or square edges to start/stop of line (adds thickness/2 to arc)
|
||||
},
|
||||
{
|
||||
"type": "pad" // a pad (on copper layer)
|
||||
"number": 0, // pad name/number
|
||||
"x1": 0, // start position of pad
|
||||
"y1": 0, // start position of pad
|
||||
"x2": 100, // end position of pad
|
||||
"y2": 100, // end position of pad
|
||||
"thickness": 10, // thickness of copper pad
|
||||
"clearance": 5, // clearance of pad (added to each side of copper)
|
||||
"soldermask": 11, // thickness of solder mask opening (generally >= copper thickness)
|
||||
"round": true, // round or square edges to start/stop of pad (adds thickness/2 to pad)
|
||||
},
|
||||
{
|
||||
"type": "pin" // a pin with a drill hole (on copper layer)
|
||||
"number": 0; // pin name/number
|
||||
"x": 50, // center horizontal position of pin
|
||||
"y": 50, // center vertical position of pin
|
||||
"thickness": 30, // diameter/width of copper pin (>= drill diameter/width)
|
||||
"drill": 20, // diameter/width of drill
|
||||
"clearance": 5, // clearance of pad (added to each side of copper)
|
||||
"soldermask": 35, // thickness of solder mask opening (generally >= copper thickness)
|
||||
"round": true, // shape of pin: round or square
|
||||
}
|
||||
]
|
||||
}
|
400
cvlp_lib.js
Normal file
400
cvlp_lib.js
Normal file
@ -0,0 +1,400 @@
|
||||
// library for creating CuVoodoo Land Pattern (cvlp) JSON files and render them
|
||||
|
||||
// create a set of elements with an line element
|
||||
function cvlp_line(x1, y1, x2, y2, thickness, round=true) {
|
||||
var line = {}
|
||||
line.type = "line"
|
||||
line.x1 = x1
|
||||
line.y1 = y1
|
||||
line.x2 = x2
|
||||
line.y2 = y2
|
||||
line.thickness = thickness
|
||||
line.round = round
|
||||
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, round=true) {
|
||||
var arc = {}
|
||||
arc.type = "arc"
|
||||
arc.x = x
|
||||
arc.y = y
|
||||
arc.radius = radius
|
||||
arc.start = start
|
||||
arc.angle = angle
|
||||
arc.thickness = thickness
|
||||
arc.round = round
|
||||
return [arc]
|
||||
}
|
||||
|
||||
// create a set of elements with an pad element
|
||||
function cvlp_pad(number, x1, y1, x2, y2, thickness, clearance, soldermask, round=true) {
|
||||
var pad = {}
|
||||
pad.type = "pad"
|
||||
pad.number = number
|
||||
pad.x1 = x1
|
||||
pad.y1 = y1
|
||||
pad.x2 = x2
|
||||
pad.y2 = y2
|
||||
pad.thickness = thickness
|
||||
pad.clearance = clearance
|
||||
pad.soldermask = soldermask
|
||||
pad.round = round
|
||||
return [pad]
|
||||
}
|
||||
|
||||
// create a set of elements with an pin element
|
||||
function cvlp_pin(number, x, y, thickness, drill, clearance, soldermask, round=true) {
|
||||
var pin = {}
|
||||
pin.type = "pin"
|
||||
pin.number = number
|
||||
pin.x = x
|
||||
pin.y = y
|
||||
pin.thickness = thickness
|
||||
pin.drill = drill
|
||||
pin.clearance = clearance
|
||||
pin.soldermask = soldermask
|
||||
pin.round = round
|
||||
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=false) {
|
||||
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) {
|
||||
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=0, round=true) {
|
||||
var rectangle = []
|
||||
rectangle = rectangle.concat(cvlp_line(x+radius, y, x+width-radius, y, thickness, round))
|
||||
rectangle = rectangle.concat(cvlp_line(x+width, y+radius, x+width, y+height-radius, thickness, round))
|
||||
rectangle = rectangle.concat(cvlp_line(x+width-radius, y+height, x+radius, y+height, thickness, round))
|
||||
rectangle = rectangle.concat(cvlp_line(x, y+height-radius, x, y+radius, thickness, round))
|
||||
if (radius!=0) {
|
||||
rectangle = rectangle.concat(cvlp_arc(x+radius, y+radius, radius, 180, 90, thickness, round))
|
||||
rectangle = rectangle.concat(cvlp_arc(x+width-radius, y+radius, radius, 270, 90, thickness, round))
|
||||
rectangle = rectangle.concat(cvlp_arc(x+width-radius, y+width-radius, radius, 0, 90, thickness, round))
|
||||
rectangle = rectangle.concat(cvlp_arc(x+radius, y+width-radius, radius, 90, 90, thickness, round))
|
||||
}
|
||||
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 fixed(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')
|
||||
// add info
|
||||
svg.setAttribute('height',json.height)
|
||||
svg.setAttribute('width',json.width)
|
||||
var svg_title = document.createElementNS(svgNS,'title');
|
||||
svg_title.textContent = json.name;
|
||||
svg.appendChild(svg_title);
|
||||
// add copper and silkscreen layers
|
||||
layers_desc = [ { name: 'copper', stroke: 'black', fill: 'black', display: 'inline'},
|
||||
{ name: 'drill', stroke: 'none', fill: 'white', display: 'inline'},
|
||||
{ name: 'clearance', stroke: 'red', fill: 'none', display: 'none'},
|
||||
{ name: 'soldermask', stroke: 'green', fill: 'none', display: 'none'},
|
||||
{ name: 'silkscreen', stroke: 'gray', fill: 'none', display: 'inline'}
|
||||
]
|
||||
layers = []
|
||||
for (var layer_i in layers_desc) {
|
||||
var layer_desc = layers_desc[layer_i]
|
||||
var layer = document.createElementNS(svgNS,'g')
|
||||
layer.setAttribute('name',layer_desc.name)
|
||||
layer.setAttribute('inkscape:groupmode','layer')
|
||||
layer.setAttribute('inkscape:label',layer_desc.name)
|
||||
layer.setAttribute('display',layer_desc.display)
|
||||
layer.style.setProperty('stroke',layer_desc.stroke)
|
||||
layer.style.setProperty('fill',layer_desc.fill)
|
||||
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.style.setProperty('stroke-width',element.thickness)
|
||||
if (element.round) {
|
||||
line.style.setProperty('stroke-linecap','round')
|
||||
} else {
|
||||
line.style.setProperty('stroke-linecap','square')
|
||||
}
|
||||
line.setAttribute('x1',element.x1)
|
||||
line.setAttribute('y1',element.y1)
|
||||
line.setAttribute('x2',element.x2)
|
||||
line.setAttribute('y2',element.y2)
|
||||
layers['silkscreen'].appendChild(line)
|
||||
break
|
||||
case 'arc':
|
||||
element.start = element.start % 360
|
||||
element.stop = element.stop % 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 {
|
||||
arc = document.createElementNS(svgNS,'path')
|
||||
arc.setAttribute('d',"M "+(element.x+element.radius*Math.cos(((-1*element.start)%360)/360.0*Math.PI*2))+" "+(element.y-element.radius*Math.sin(((-1*element.start)%360)/360.0*Math.PI*2))+" A "+element.radius+" "+element.radius+" 0 "+((element.angle)%360>180 ? "1" : "0")+" 1 "+(element.x+element.radius*Math.cos(((-1*(element.start+element.angle))%360)/360.0*Math.PI*2))+" "+(element.y-element.radius*Math.sin(((-1*(element.start+element.angle))%360)/360.0*Math.PI*2))+" ")
|
||||
}
|
||||
arc.style.setProperty('stroke-width',element.thickness)
|
||||
if (element.round) {
|
||||
arc.style.setProperty('stroke-linecap','round')
|
||||
} else {
|
||||
arc.style.setProperty('stroke-linecap','square')
|
||||
}
|
||||
layers['silkscreen'].appendChild(arc)
|
||||
break
|
||||
case 'pad':
|
||||
var copper = document.createElementNS(svgNS,'line')
|
||||
copper.style.setProperty('stroke-width',element.thickness)
|
||||
if (element.round) {
|
||||
copper.style.setProperty('stroke-linecap','round')
|
||||
} else {
|
||||
copper.style.setProperty('stroke-linecap','square')
|
||||
}
|
||||
copper.setAttribute('x1',element.x1)
|
||||
copper.setAttribute('y1',element.y1)
|
||||
copper.setAttribute('x2',element.x2)
|
||||
copper.setAttribute('y2',element.y2)
|
||||
layers['copper'].appendChild(copper)
|
||||
var clearance = document.createElementNS(svgNS,'line')
|
||||
clearance.style.setProperty('stroke-width',element.thickness+2*element.clearance)
|
||||
if (element.round) {
|
||||
clearance.style.setProperty('stroke-linecap','round')
|
||||
} else {
|
||||
clearance.style.setProperty('stroke-linecap','square')
|
||||
}
|
||||
clearance.setAttribute('x1',element.x1)
|
||||
clearance.setAttribute('y1',element.y1)
|
||||
clearance.setAttribute('x2',element.x2)
|
||||
clearance.setAttribute('y2',element.y2)
|
||||
layers['clearance'].appendChild(clearance)
|
||||
var soldermask = document.createElementNS(svgNS,'line')
|
||||
soldermask.style.setProperty('stroke-width',element.soldermask)
|
||||
if (element.round) {
|
||||
soldermask.style.setProperty('stroke-linecap','round')
|
||||
} else {
|
||||
soldermask.style.setProperty('stroke-linecap','square')
|
||||
}
|
||||
soldermask.setAttribute('x1',element.x1)
|
||||
soldermask.setAttribute('y1',element.y1)
|
||||
soldermask.setAttribute('x2',element.x2)
|
||||
soldermask.setAttribute('y2',element.y2)
|
||||
layers['soldermask'].appendChild(soldermask)
|
||||
break
|
||||
case 'pin':
|
||||
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 drill = document.createElementNS(svgNS,'rect')
|
||||
drill.style.setProperty('stroke-width',0)
|
||||
drill.setAttribute('x',element.x-element.drill/2)
|
||||
drill.setAttribute('y',element.y-element.drill/2)
|
||||
drill.setAttribute('height',element.drill)
|
||||
drill.setAttribute('width',element.drill)
|
||||
if (element.round) {
|
||||
drill.setAttribute('rx',element.drill/2)
|
||||
drill.setAttribute('ry',element.drill/2)
|
||||
} else {
|
||||
drill.setAttribute('rx',0)
|
||||
drill.setAttribute('ry',0)
|
||||
}
|
||||
layers['drill'].appendChild(drill)
|
||||
var clearance = document.createElementNS(svgNS,'rect')
|
||||
clearance.style.setProperty('stroke-width',0)
|
||||
clearance.setAttribute('x',element.x-element.thickness/2-element.clearance)
|
||||
clearance.setAttribute('y',element.y-element.thickness/2-element.clearance)
|
||||
clearance.setAttribute('height',element.thickness+element.clearance*2)
|
||||
clearance.setAttribute('width',element.thickness+element.clearance*2)
|
||||
if (element.round) {
|
||||
clearance.setAttribute('rx',element.thickness/2+element.clearance)
|
||||
clearance.setAttribute('ry',element.thickness/2+element.clearance)
|
||||
} else {
|
||||
clearance.setAttribute('rx',0)
|
||||
clearance.setAttribute('ry',0)
|
||||
}
|
||||
layers['clearance'].appendChild(clearance)
|
||||
var soldermask = document.createElementNS(svgNS,'rect')
|
||||
soldermask.style.setProperty('stroke-width',0)
|
||||
soldermask.setAttribute('x',element.x-element.soldermask/2)
|
||||
soldermask.setAttribute('y',element.y-element.soldermask/2)
|
||||
soldermask.setAttribute('height',element.soldermask)
|
||||
soldermask.setAttribute('width',element.soldermask)
|
||||
if (element.round) {
|
||||
soldermask.setAttribute('rx',element.soldermask/2)
|
||||
soldermask.setAttribute('ry',element.soldermask/2)
|
||||
} else {
|
||||
soldermask.setAttribute('rx',0)
|
||||
soldermask.setAttribute('ry',0)
|
||||
}
|
||||
layers['soldermask'].appendChild(soldermask)
|
||||
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':
|
||||
pcb += 'Pad['+element.x1+''+json.unit+' '+element.y1+''+json.unit+' '+element.x2+''+json.unit+' '+element.y2+''+json.unit+' '+element.thickness+''+json.unit+' '+element.clearance*2+''+json.unit+' '+element.soldermask+''+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+' '+element.clearance*2+''+json.unit+' '+element.soldermask+''+json.unit+' '+element.drill+''+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) {
|
||||
if (json.unit!='mm') {
|
||||
console.log('KiCad export only supports units in mm')
|
||||
return ''
|
||||
}
|
||||
// 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 '+element.x1+' '+element.y1+') (end '+element.x2+' '+element.y2+') (layer F.SilkS) (width '+element.thickness+'))\n'
|
||||
break
|
||||
case 'arc':
|
||||
kicad += '(fp_arc (start '+element.x+' '+element.y+') (end '+(element.x+element.radius*Math.cos(((-1*element.start)%360)/360.0*Math.PI*2))+' '+(element.y-element.radius*Math.sin(((-1*element.start)%360)/360.0*Math.PI*2))+') (angle '+element.angle+') (layer F.SilkS) (width '+element.thickness+'))\n'
|
||||
break
|
||||
case 'pad':
|
||||
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 '+x+' '+y+' '+angle+')'
|
||||
kicad += ' (size '+length+' '+element.thickness+')'
|
||||
kicad += ' (layers F.Cu F.Paste F.Mask)'
|
||||
kicad += ' (clearance '+element.clearance+')'
|
||||
kicad += ' (solder_mask_margin '+(element.thickness/2*-1+element.soldermask)+')'
|
||||
kicad += ')\n'
|
||||
break
|
||||
case 'pin':
|
||||
break
|
||||
default:
|
||||
console.log("unknown element type: "+element.type)
|
||||
}
|
||||
}
|
||||
kicad += ')\n'
|
||||
return kicad
|
||||
}
|
2
lib/FileSaver.min.js
vendored
Normal file
2
lib/FileSaver.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
|
||||
var saveAs=saveAs||function(e){"use strict";if("undefined"==typeof navigator||!/MSIE [1-9]\./.test(navigator.userAgent)){var t=e.document,n=function(){return e.URL||e.webkitURL||e},o=t.createElementNS("http://www.w3.org/1999/xhtml","a"),r="download"in o,i=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},a=e.webkitRequestFileSystem,c=e.requestFileSystem||a||e.mozRequestFileSystem,u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},f="application/octet-stream",s=0,d=500,l=function(t){var o=function(){"string"==typeof t?n().revokeObjectURL(t):t.remove()};e.chrome?o():setTimeout(o,d)},v=function(e,t,n){t=[].concat(t);for(var o=t.length;o--;){var r=e["on"+t[o]];if("function"==typeof r)try{r.call(e,n||e)}catch(i){u(i)}}},p=function(e){return/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)?new Blob(["",e],{type:e.type}):e},w=function(t,u,d){d||(t=p(t));var w,y,m,S=this,h=t.type,O=!1,R=function(){v(S,"writestart progress write writeend".split(" "))},b=function(){if((O||!w)&&(w=n().createObjectURL(t)),y)y.location.href=w;else{var o=e.open(w,"_blank");void 0==o&&"undefined"!=typeof safari&&(e.location.href=w)}S.readyState=S.DONE,R(),l(w)},g=function(e){return function(){return S.readyState!==S.DONE?e.apply(this,arguments):void 0}},E={create:!0,exclusive:!1};return S.readyState=S.INIT,u||(u="download"),r?(w=n().createObjectURL(t),o.href=w,o.download=u,void setTimeout(function(){i(o),R(),l(w),S.readyState=S.DONE})):(e.chrome&&h&&h!==f&&(m=t.slice||t.webkitSlice,t=m.call(t,0,t.size,f),O=!0),a&&"download"!==u&&(u+=".download"),(h===f||a)&&(y=e),c?(s+=t.size,void c(e.TEMPORARY,s,g(function(e){e.root.getDirectory("saved",E,g(function(e){var n=function(){e.getFile(u,E,g(function(e){e.createWriter(g(function(n){n.onwriteend=function(t){y.location.href=e.toURL(),S.readyState=S.DONE,v(S,"writeend",t),l(e)},n.onerror=function(){var e=n.error;e.code!==e.ABORT_ERR&&b()},"writestart progress write abort".split(" ").forEach(function(e){n["on"+e]=S["on"+e]}),n.write(t),S.abort=function(){n.abort(),S.readyState=S.DONE},S.readyState=S.WRITING}),b)}),b)};e.getFile(u,{create:!1},g(function(e){e.remove(),n()}),g(function(e){e.code===e.NOT_FOUND_ERR?n():b()}))}),b)}),b)):void b())},y=w.prototype,m=function(e,t,n){return new w(e,t,n)};return"undefined"!=typeof navigator&&navigator.msSaveOrOpenBlob?function(e,t,n){return n||(e=p(e)),navigator.msSaveOrOpenBlob(e,t||"download")}:(y.abort=function(){var e=this;e.readyState=e.DONE,v(e,"abort")},y.readyState=y.INIT=0,y.WRITING=1,y.DONE=2,y.error=y.onwritestart=y.onprogress=y.onwrite=y.onabort=y.onerror=y.onwriteend=null,m)}}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this.content);"undefined"!=typeof module&&module.exports?module.exports.saveAs=saveAs:"undefined"!=typeof define&&null!==define&&null!=define.amd&&define([],function(){return saveAs});
|
14
lib/jszip.min.js
vendored
Normal file
14
lib/jszip.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
200
oshw_logo.html
Normal file
200
oshw_logo.html
Normal file
@ -0,0 +1,200 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>open source hardware logo customisation</title>
|
||||
<script type="text/javascript" src="cvlp_lib.js"></script>
|
||||
<script type="text/javascript" src="lib/FileSaver.min.js"></script>
|
||||
<script type="text/javascript" src="lib/jszip.min.js"></script>
|
||||
</head>
|
||||
<body onload="draw()">
|
||||
<script type="text/javascript">
|
||||
// the OSHW logo
|
||||
var logo = {
|
||||
"name": "open source hardware logo",
|
||||
"author": "King Kevin",
|
||||
"version": 0,
|
||||
"date": "2015-04-11 13:58:46+02:00",
|
||||
"unit": "mm",
|
||||
"elements": []
|
||||
}
|
||||
// draw logo
|
||||
function draw() {
|
||||
// get values
|
||||
var pad_size = parseInt(pad_size_range.value,10)
|
||||
var pad_thickness = parseInt(pad_thickness_range.value,10)
|
||||
var pad_spacing = parseInt(pad_spacing_range.value,10)
|
||||
var pad_chip_spacing = parseInt(pad_chip_spacing_range.value,10)
|
||||
var chip_thickness = parseInt(chip_thickness_range.value,10)
|
||||
var text_thickness = parseInt(text_thickness_range.value,10)
|
||||
|
||||
// display values
|
||||
pad_size_text.innerHTML = pad_size
|
||||
pad_thickness_text.innerHTML = pad_thickness
|
||||
pad_spacing_text.innerHTML = pad_spacing
|
||||
pad_chip_spacing_text.innerHTML = pad_chip_spacing
|
||||
chip_thickness_text.innerHTML = chip_thickness
|
||||
text_thickness_text.innerHTML = text_thickness
|
||||
|
||||
// set values in logo
|
||||
var size = pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2+pad_size+pad_thickness
|
||||
logo.width = size
|
||||
logo.height = size
|
||||
|
||||
// clear elements
|
||||
logo.elements = []
|
||||
|
||||
// draw pads
|
||||
for (var i=0; i<6; i++) {
|
||||
if (document.getElementById("pad_layer_copper").checked) {
|
||||
var west = cvlp_pad(i+1, 0+pad_thickness, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness, pad_thickness*0.1, 0)
|
||||
logo.elements = logo.elements.concat(west)
|
||||
var north = cvlp_pad(24-i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size, pad_thickness, pad_thickness*0.1, 0)
|
||||
logo.elements = logo.elements.concat(north)
|
||||
var east = cvlp_pad(18-i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2+pad_size, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness, pad_thickness*0.1, 0)
|
||||
logo.elements = logo.elements.concat(east)
|
||||
var south = cvlp_pad(i+7, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2+pad_size, pad_thickness, pad_thickness*0.1, 0)
|
||||
logo.elements = logo.elements.concat(south)
|
||||
} else {
|
||||
var west = cvlp_line(0+pad_thickness, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness)
|
||||
logo.elements = logo.elements.concat(west)
|
||||
var north = cvlp_line(pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size, pad_thickness)
|
||||
logo.elements = logo.elements.concat(north)
|
||||
var east = cvlp_line(pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2+pad_size, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness)
|
||||
logo.elements = logo.elements.concat(east)
|
||||
var south = cvlp_line(pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*i, pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5+pad_chip_spacing*2+pad_size, pad_thickness)
|
||||
logo.elements = logo.elements.concat(south)
|
||||
}
|
||||
}
|
||||
// draw chip outline
|
||||
var chip = cvlp_rectangle(pad_thickness+pad_size+pad_chip_spacing, pad_thickness+pad_size+pad_chip_spacing, pad_chip_spacing*2+pad_spacing*5, pad_chip_spacing*2+pad_spacing*5, chip_thickness, pad_chip_spacing)
|
||||
logo.elements = logo.elements.concat(chip)
|
||||
// draw O letter
|
||||
var x = pad_thickness+pad_size+pad_chip_spacing*2
|
||||
var y = pad_thickness+pad_size+pad_chip_spacing*2
|
||||
var text = cvlp_polyline([[x,y],
|
||||
[x+=pad_spacing*2,y],
|
||||
[x,y+=pad_spacing*2],
|
||||
[x+=pad_spacing*-2,y],
|
||||
[x,y+=pad_spacing*-2]],text_thickness)
|
||||
logo.elements = logo.elements.concat(text)
|
||||
// draw S letter
|
||||
var x = pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*5
|
||||
var y = pad_thickness+pad_size+pad_chip_spacing*2
|
||||
var text = cvlp_polyline([[x,y],
|
||||
[x+=pad_spacing*-2,y],
|
||||
[x,y+=pad_spacing],
|
||||
[x+=pad_spacing*2,y],
|
||||
[x,y+=pad_spacing],
|
||||
[x+=pad_spacing*-2,y]],text_thickness)
|
||||
logo.elements = logo.elements.concat(text)
|
||||
// draw H letter
|
||||
var x = pad_thickness+pad_size+pad_chip_spacing*2
|
||||
var y = pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*3
|
||||
var text = cvlp_line(x, y, x, y+pad_spacing*2, text_thickness)
|
||||
logo.elements = logo.elements.concat(text)
|
||||
var text = cvlp_line(x, y+pad_spacing, x+pad_spacing*2, y+pad_spacing, text_thickness)
|
||||
logo.elements = logo.elements.concat(text)
|
||||
var text = cvlp_line(x+pad_spacing*2, y, x+pad_spacing*2, y+pad_spacing*2, text_thickness)
|
||||
logo.elements = logo.elements.concat(text)
|
||||
// draw W letter
|
||||
var x = pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*3
|
||||
var y = pad_thickness+pad_size+pad_chip_spacing*2+pad_spacing*3
|
||||
var text = cvlp_polyline([[x,y],
|
||||
[x,y+=pad_spacing*2],
|
||||
[x+=pad_spacing,y+=pad_spacing*-1],
|
||||
[x+=pad_spacing,y+=pad_spacing],
|
||||
[x,y+=pad_spacing*-2]],text_thickness)
|
||||
logo.elements = logo.elements.concat(text)
|
||||
|
||||
var svg = json2svg(logo)
|
||||
var div = document.getElementById('svg')
|
||||
div.textContent = ""
|
||||
div.appendChild(svg)
|
||||
}
|
||||
|
||||
function download() {
|
||||
var select = document.getElementById("filetype")
|
||||
var filetype = select.options[select.selectedIndex].value
|
||||
switch (filetype) {
|
||||
case 'json':
|
||||
var blob = new Blob([JSON.stringify(logo, null, '\t')], {type: "application/json"})
|
||||
saveAs(blob, "oshw_logo.json")
|
||||
break
|
||||
case 'svg':
|
||||
var blob = new Blob([new XMLSerializer().serializeToString(json2svg(logo))], {type: "image/svg+xml"})
|
||||
saveAs(blob, "oshw_logo.svg")
|
||||
break
|
||||
case 'pcb':
|
||||
var blob = new Blob([json2pcb(logo)], {type: "application/x-pcb-footprint"})
|
||||
saveAs(blob, "oshw_logo.fp")
|
||||
break
|
||||
case 'kicad':
|
||||
var blob = new Blob([json2kicad(logo)], {type: "application/x-kicad-pcb"})
|
||||
saveAs(blob, "oshw_logo.kicad_mod")
|
||||
break
|
||||
case 'zip':
|
||||
var zip = new JSZip()
|
||||
zip.file("oshw_logo.json", JSON.stringify(logo, null, '\t'))
|
||||
zip.file("oshw_logo.svg", new XMLSerializer().serializeToString(json2svg(logo)))
|
||||
zip.file("oshw_logo.fp", json2pcb(logo))
|
||||
var file = zip.generate({type:"blob"})
|
||||
saveAs(file, "oshw_logo.zip")
|
||||
break
|
||||
default:
|
||||
console.log("unknown file type: "+filetype)
|
||||
}
|
||||
}
|
||||
|
||||
function change_unit() {
|
||||
var select = document.getElementById("unit")
|
||||
var unit = select.options[select.selectedIndex].value
|
||||
|
||||
if (logo.unit==unit) {
|
||||
return
|
||||
}
|
||||
// get values
|
||||
var pad_size = parseInt(pad_size_range.value,10)
|
||||
var pad_thickness = parseInt(pad_thickness_range.value,10)
|
||||
var pad_spacing = parseInt(pad_spacing_range.value,10)
|
||||
var pad_chip_spacing = parseInt(pad_chip_spacing_range.value,10)
|
||||
var chip_thickness = parseInt(chip_thickness_range.value,10)
|
||||
var text_thickness = parseInt(text_thickness_range.value,10)
|
||||
|
||||
// display values
|
||||
pad_size_text.innerHTML = pad_size
|
||||
pad_thickness_text.innerHTML = pad_thickness
|
||||
pad_spacing_text.innerHTML = pad_spacing
|
||||
pad_chip_spacing_text.innerHTML = pad_chip_spacing
|
||||
chip_thickness_text.innerHTML = chip_thickness
|
||||
text_thickness_text.innerHTML = text_thickness
|
||||
}
|
||||
</script>
|
||||
<div id="svg"></div>
|
||||
<p id="control">
|
||||
<form onchange="draw()">
|
||||
pads on:
|
||||
<input type="radio" name="pad_layer" id="pad_layer_copper" value="copper" checked="true">copper
|
||||
<input type="radio" name="pad_layer" id="pad_layer_silkscreen" value="silkscreen">silkscreen
|
||||
</form>
|
||||
unit: <select id="unit" onchange="change_unit()">
|
||||
<option value="mm">millimeter (mm)</option>
|
||||
<option value="in">inch (in)</option>
|
||||
<option value="mil">mil/thou (mil)</option>
|
||||
</select><br />
|
||||
pad size: <input id="pad_size_range" type="range" min="0" max="100" value="30" step="5" onchange="draw()" /> <span id="pad_size_text"></span><br />
|
||||
pad thickness: <input id="pad_thickness_range" type="range" min="1" max="20" value="15" step="1" onchange="draw()" /> <span id="pad_thickness_text"></span><br />
|
||||
pad spacing: <input id="pad_spacing_range" type="range" min="0" max="100" value="20" step="5" onchange="draw()" /> <span id="pad_spacing_text"></span><br />
|
||||
pad-chip spacing: <input id="pad_chip_spacing_range" type="range" min="0" max="100" value="15" step="5" onchange="draw()" /> <span id="pad_chip_spacing_text"></span><br />
|
||||
chip thickness: <input id="chip_thickness_range" type="range" min="1" max="20" value="10" step="1" onchange="draw()" /> <span id="chip_thickness_text"></span><br />
|
||||
text thickness: <input id="text_thickness_range" type="range" min="1" max="20" value="10" step="1" onchange="draw()" /> <span id="text_thickness_text"></span><br />
|
||||
<button type="button" onclick="download()">save</button>: <select id="filetype">
|
||||
<option value="json">CuVoodoo Land Pattern (.json)</option>
|
||||
<option value="svg">Scalable Vector Graphics (.svg)</option>
|
||||
<option value="pcb">gEDA pcb footprint (.fp)</option>
|
||||
<option value="kicad">KiCad s-expr. footprint (.kicad_mod)</option>
|
||||
<option value="zip">all (zip)</option>
|
||||
</select><br />
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
10
txt2json.sh
Executable file
10
txt2json.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env sh
|
||||
cp cv_json_format.txt cv_json_format.json
|
||||
# remove comments
|
||||
sed -i 's://.*$::g' cv_json_format.json
|
||||
# remove trailing spaces
|
||||
sed -i 's/\s*$//g' cv_json_format.json
|
||||
# remove lines with whitespace
|
||||
sed -i '/^$/d' cv_json_format.json
|
||||
# verify json
|
||||
cat cv_json_format.json | json_verify
|
Loading…
Reference in New Issue
Block a user