PCB javascript解析Gerber274X格式实现方法
解析钻Gerber274X格式前首先得了解此格式,这样才能更好的解析呀。
一个Gerber274X里面包含的基本信息如下:
1.单位:公式mm,英制inch
2.省零方式:前省零,后省零
3.坐标方式:绝对坐标,相对坐标
4.坐标位数:3:5,2:6
5.Gerber D码形状
6.Gerber坐标信息
更多Gerber 274X格式详见(1M带宽,需等20秒)
http://pcbren.cn/ShareFiles/Gerber274x.pdf
一.数据结构信息
1、数据块(Data Blocks)
RS-274X 文件是由数据块组成的,每个数据块都是以(*) 结尾,每个数据块都包括了一个或多个参数,如示例
X0Y0D02*
X10000Y0DO1*为了增强可读性,建议相关的数据块在一行(因为一个数据块可以在多行),
2、数据类型
数据类型主要包括以下几种类型,坐标数据(Coordinate Data),功能指令(Function Codes) ,参数(Parameters)
3、坐标数据
坐标数据主要是定义在平面的中点数据,在RS274D的术语中称为地址。
坐标数据可能是:
1)X和Y坐标定义的点,
2)相对于X,Y方向的便移量数据,称为I,J数据
FS(Format Specification) 格式定义指示了数字如何被解释的。
坐标系采用右手坐标系。
坐标是模态(modal) 的,如果一个X被忽略,则X将保留上一次的X坐标值,如果在当前层的第一个X被忽略,因为没有上一次的X的坐标值,那么X坐标将被视为零。类似地,Y坐标也是这样处理的。
偏移量不是模态上的,如果I或J被忽略,则缺省值为零。
注意:
GERBER的读者有时候会错误地处理缺省值零。为了清晰和鲁棒性,推荐总是显式地指定第一个坐标(即便就是零,也显式指定),这样就不用考虑缺省的零。
示例:
1: X100Y200* 点 (+100, +200)
2: Y-300* 点 (+100, -300)
3: I200J100* 平移 (+200, +100)
4: X300Y200I150J50* 点(+300, +200) 且 平移(+150, +50)
5: X+100I-50* 点 (+100, +200) 且 平移 (-50, 0)
4、功能指令(Function Codes):
功能指令描述的是如何解析相关联的坐标数据。如,画一条线或画一个圆。(通常,但不是所有,这些代码是延续已经过时的RS-274D的格式,它们被称为字(words)或代码(codes))。
如
G74*
每个指令都会影响到其后的数据块,直到遇到另外一个相同类型的代码或生成新层时结束。我们称这种持续性的活动为模态(modal)。例如G02指示的是顺时针圆弧插补(CCI, clockwise circular interpolation)。在遇到另外一个插补指令或生成新层之前,该指令后的所有坐标数据都被解释为顺时针圆弧插补。指令的细节描述后序再讨论。
5、参数 (Parameters)
参数定义了整个图像或单层的各种特征。它们被用于解释其他的数据类型,(通常,这些参数被称为Mass 参数)。控制整个图像的参数通常会放在文件的开始处。产生新层的参数被放置在文件恰当的位置。参数由两个字符加一个或多个紧随其后的可选修改符组成。参数的限定符号为“%”.每个包含在数据块内的参数必须以“*”结束。并且参数限定符必须立即跟在块结束符后面,不允许插入空格。
例如:
%FSLAX23Y23*%
参数必须是在成对的参数限定符内,限定符内可以放一个或多个参数,两个限定符之间最大的字符数为4096个。
例如:
%SFA1.0B1.0*ASAXBY*%
为了提高可读性,两个参数间允许换行,如:
%SFA1.0B1.0*
ASAXBY*%
当然,为了简化和可读性,推荐每行是只设置一个参数。与参数联合的所有数值都使用显式的小数点,如果不使用小数点,数值应当认为是整数。
参数的语法为:
%参数指令<必选修饰符>[可选修饰符]%
语法 说明 参数指令 (parameter code) 两个字符的指令,如AD,AM,FS等 必选修饰符(required modifiers) 必须是完整的定义 可选修饰符(optional modifiers) 依赖必选修饰符的定义
此数据结构仅用于测试用JS解析Gerber格式绘出图形, 数据结构构建与解析方式不是很完美.后续需改进。

二.JS代码实现:
function loadGerber274X(text) {
text = text.replace(/\s+/g, '');
var sections = text.split('%');
var g = {offA: 0, offB: 0, shapes: [], cmds: [], scale: 1}, shape = 0, macros = {}, mode = 1, inverted = false, prevX = 0, prevY = 0;
function numVal(x) {
if(x[0] == '+')
return numVal(x.slice(1));
if(x[0] == '-')
return -numVal(x.slice(1));
if(x == '0')
return 0;
if(g.omitLead)
while(x.length < g.num)
x = '0'+x;
else
while(x.length < g.num)
x += '0';
return parseFloat(x.slice(0, g.int)+'.'+x.slice(g.int), 10);
}
for(var i = 0; i < sections.length; i++) {
if(!sections[i].length)
continue;
sections[i][sections[i].length-1] == '*' && (sections[i] = sections[i].slice(0, -1));
sections[i] = sections[i].split('*');
for(var j = 0; j < sections[i].length; j++) {
var d = sections[i][j];
if(i%2) { // Parameters.
if(d[0] == 'F' && d[1] == 'S') {// Format Specification.
var r = /^([LT]?)([AI])X(\d)(\d)Y(\d)(\d)$/.exec(d.slice(2)); // assert(r);
g.omitLead = !r[1] || r[1] == 'L';
g.abs = r[2] == 'A';
if(!g.abs) throw new Error('Need absolute values');
g.int = +r[3], g.dec = +r[4], g.num = g.int+g.dec;
} else if(d[0] == 'O' && d[1] == 'F') {// Offset.
var r = /^(?:A([-+\d.]+)|)(?:B([-+\d.]+)|)$/.exec(d.slice(2)); // assert(r);
g.offA = parseInt(r[1], 10), g.offB = parseInt(r[2], 10);
} else if(d == 'IPNEG') // Image Polarity.
throw new Error('Negative image polarity');
else if(d[0] == 'L' && d[1] == 'P') { // Layer Polarity.
if(inverted && d[2] == 'D') // Switch to dark.
g.cmds.push([16<<2, inverted = false]);
else if(!inverted && d[2] == 'C') // Switch to clear.
g.cmds.push([16<<2, inverted = true]);
} else if(d[0] == 'A' && d[1] == 'M') { // Aperture Macro.
var macro = [];
for(j++; j < sections[i].length; j++)
macro.push(sections[i][j]/*.split(',')*/);
macros[d.slice(2)] = macro;
} else if(d[0] == 'A' && d[1] == 'D' && d[2] == 'D') { // Aperture Definition.
var r = /^(\d+)([^,]+)(?:,(.+)|)$/.exec(d.slice(3)); // assert(r);
var j = r[1]-10, args = [];
if(r[3])
args = r[3].split('X');
if(macros[r[2]]) {
function applyArgs(m) {
m = m.replace(/\$(\d+)/g, function(s, n) {
return +args[n-1] || 0;
}).toLowerCase(), repl = true;
while(repl == true)
repl = false, m = m.replace(/([\d.]+)x([\d.]+)/g, function(s, a, b) {return repl = true, a*b});
repl = true;
while(repl == true)
repl = false, m = m.replace(/([\d.]+)\/([\d.]+)/g, function(s, a, b) {return repl = true, a/b});
repl = true;
while(repl == true)
repl = false, m = m.replace(/([\d.]+)\+([\d.]+)/g, function(s, a, b) {return repl = true, a+b});
repl = true;
while(repl == true)
repl = false, m = m.replace(/([\d.]+)-([\d.]+)/g, function(s, a, b) {return repl = true, a-b});
return m;
}
var m1 = macros[r[2]], m2 = [];
for(var k = 0; k < m1.length; k++) {
var eq = /^\$(\d+)=(.+)$/.exec(m1[k]);
if(eq)
args[eq[1]-1] = +applyArgs(eq[2]);
else
m2.push(applyArgs(m1[k]).split(',').map(function(x) {return +x}));
}
g.shapes[j] = ['M', m2];
} else
g.shapes[j] = [r[2]].concat(args.map(function(x) {return +x}));
if(j < shape)
shape = j;
} else if(d == 'MOIN') // Specify Inches.
g.scale = 25.4;
else if(d == 'MOMM') // Specify MMs.
g.scale = 1;
else
console.log(d);
} else { // Function codes.
if(d[0] == 'G' && d[1] == '0' && d[2] == '4' || d[0] == 'M')
continue;
if(d[0] == 'G' && d[1] == '5' && d[2] == '4')
d = d.slice(3);
if(d == 'G70') { // Specify Inches.
g.scale = 25.4;
continue;
}
if(d == 'G74') { // Set Single quadrant mode.
mode &= ~4;
continue;
}
if(d == 'G75') { // Set Multi quadrant mode.
mode |= 4;
continue;
}
if(d == 'G36') { // Start Outline fill.
if(!(mode & 8))
g.cmds.push([8<<2, true]);
mode |= 8;
continue;
}
if(d == 'G37') { // End Outline fill.
if(mode & 8)
g.cmds.push([8<<2, false]);
mode &= ~8;
continue;
}
var cmode = 0;
if(d[0] == 'G' && d.length > 4) {
var r = /^\d*/.exec(d = d.slice(1)); // assert(r);
mode = (mode & 12) | (cmode = parseInt(r[0], 10));
d = d.slice(r[0].length);
}
function getNum(offset) {
var r = /^[-+\d]*/.exec(d = d.slice(offset)); // assert(r);
d = d.slice(r[0].length);
return numVal(r[0]);
}
var x = prevX, y = prevY, oi = 0, oj = 0, hasX = false, hasY = false;
if(d[0] == 'X')
x = getNum(1), hasX = true;
if(d[0] == 'Y')
y = getNum(1), hasY = true;
if(d[0] == 'I')
oi = getNum(1), (!(mode&2) && (x += oi, hasX = true));
if(d[0] == 'J')
oj = getNum(1), (!(mode&2) && (y += oj, hasY = true));
if(d[0] == 'D') {// Draw.
if(d[1] == '0')
g.cmds.push([(mode<<2) | d[2], shape, x, y, oi, oj]);
else
shape = d.slice(1)-10;
} else if(hasX && (x != prevX) || hasY && (y != prevY))
g.cmds.push([(mode<<2) | 1, shape, x, y, oi, oj]);
else
console.log(d);
prevX = x, prevY = y;
}
}
}
return g;
};
三.Gerber274X解析绘图Web效果图
JS解析展示,无交互功能,虽然是在前端,但最佳作法解析动作放在后端,后端解析后的数据或图像传送到前端

部份Gerber274X解析说明引用了:
https://www.cnblogs.com/begincsdn/archive/2012/07/07/2580279.html
PCB javascript解析Gerber274X格式实现方法的更多相关文章
- PCB javascript解析钻孔(Excellon)格式实现方法
解析钻孔(Excellon)格式前首先得了解此格式,这样才能更好的解析呀. 一个钻孔里面包含的基本信息如下: 1.单位:公式mm,英制inch 2.省零方式:前省零,后省零 3.坐标方式:绝对坐标,相 ...
- javascript 解析ajax返回的xml和json格式的数据
写个例子,以备后用 一.JavaScript 解析返回的xml格式的数据: 1.javascript版本的ajax发送请求 (1).创建XMLHttpRequest对象,这个对象就是ajax请求的核心 ...
- Android中解析XML格式数据的方法
XML介绍:Extensible Markup Language,即可扩展标记语言 一.概述 Android中解析XML格式数据大致有三种方法: SAX DOM PULL 二.详解 2.1 SAX S ...
- URL地址中中文乱码详解(javascript中encodeURI和decodeURI方法、java.net.URLDecoder.encode、java.net.URLDecoder.decode)
引言: 在Restful类的服务设计中,经常会碰到需要在URL地址中使用中文作为的参数的情况,这种情况下,一般都需要正确的设置和编码中文字符信息.乱码问题就此产生了,该如何解决呢?且听本文详细道来. ...
- 使用google的GSON解析json格式的数据
GSON是谷歌提供的开源库,用来解析Json格式的数据,非常好用.如果要使用GSON的话,则要先下载gson-2.2.4.jar这个文件,如果是在Android项目中使用,则在Android项目的li ...
- JavaScript 解析 Django Python 生成的 datetime 数据 时区问题解决
JavaScript 解析 Django/Python 生成的 datetime 数据 当Web后台使用Django时,后台生成的时间数据类型就是Python类型的. 项目需要将几个时间存储到数据库中 ...
- 用jquery解析JSON数据的方法以及字符串转换成json的3种方法
用jquery解析JSON数据的方法,作为jquery异步请求的传输对象,jquery请求后返回的结果是 json对象,这里考虑的都是服务器返回JSON形式的字符串的形式,对于利用JSONObject ...
- 解析json格式数据
实现目标 读取文件中的json格式数据,一行为一条json格式数据.进行解析封装成实体类. 通过google的Gson对象解析json格式数据 我现在解析的json格式数据为: {",&qu ...
- php判断是否为json格式的方法
php判断是否为json格式的方法. 首先要记住json_encode返回的是字符串, 而json_decode返回的是对象 判断数据不是JSON格式: 复制代码代码如下: function is_n ...
随机推荐
- jquery的delegate()方法
delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数. 使用 delegate() 方法的事件处理程序适用于当前或未来的元素(比如 ...
- Spring学习开发之路——使用JavaBean代替EJB
Spring框架是由于软件开发的复杂性而创建的.Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Spring的用途不仅仅限于服务器端的开发.从简单性.可测试性和松耦 ...
- 解决移动端 手机号input 属性为 number,maxlength无效情况
<input type="number" oninput="if(value.length>11)value=value.slice(0,11)" ...
- 洛谷——P2734 游戏 A Game
P2734 游戏 A Game 题目背景 有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,游戏由玩家1开始,两人轮流从序列的任意一端取一个数,取数后该 ...
- python使用xlrd和xlwt读写Excel文件
版权声明:本文为博主原创文章,未经允许不得转载. 安装模块 如果使用的是Linux系统,并且安装了pip,可以直接使用pip安装xlrd, xlwt: pip install xlwt pip ins ...
- mysql批量替换某个字段的部分内容
举例说明 有数据表person,结构如下 id name urls 1 张三 xh.jpg 2 李四 xh.jpg 3 王五 3.jpg 需求:将urls字段中的xh替换为id字段的值 语句: UPD ...
- 2018百度之星资格赛T2 子串查询
[题解] 很容易想到暴力做法:对于每个询问暴力查找区间内的最小字母,统计其出现次数.效率O(N^2),无法通过全部数据. 我们可以换一个思路,设f[i][j]为第i个字母(字母‘A'到’Z'分别对应0 ...
- 百练4152:最佳加法表达式(dp+高精度)
描述 给定n个1到9的数字,要求在数字之间摆放m个加号(加号两边必须有数字),使得所得到的加法表达式的值最小,并输出该值.例如,在1234中摆放1个加号,最好的摆法就是12+34,和为36 输入有不超 ...
- Maven学习总结(32)——Maven项目部署到Tomcat8中
1.环境准备 Maven.Tomcat8.Eclipse 2.maven中的镜像配置 大家知道,mavne默认使用的是国外的镜像,但是速度很慢,这里建议大家使用阿里的中央仓库镜像. 阿里出品,必出精品 ...
- win7 32位机安装VMware win7 64位虚拟机
VMware10虚拟机怎么安装win7系统(详细教程):https://jingyan.baidu.com/article/86f4a73ec62e8f37d65269a1.html 然而上述教程想不 ...