我讨厌回答我自己的问题,但是我走了。我希望我不会因为回答而获得积分,那只会因为接受答案而很奇怪?(顺便说一句,我在Element14论坛上没有得到任何回应。)
解决方案是使用DRAW命令,而不是ROUTE。DRAW将在您指定的位置精确地放置一个线段(与ROUTE不同,ROUTE尝试连接到未布线的航空线。ROUTE在脚本中实质上是无用的。)。下一个问题是通孔:我无法(或不想)区分手动通孔和自动布线通孔,因此我保留了连接两个(或更多)手动线段的所有通孔。其他通孔被删除。
所以我的最终脚本要做的是:
prepare a ripup command
for all copper segments that are not 0.01 wide (the width I use for autorouting)
check both endpoints for a via at that location
prepare the via to be resurrected when it is visited the 2nd time
prepare a command that resurrects the copper segment
execute the prepared commands
请注意,它可能不适用于两层以上,也不适用于铜层上的线段。
恕我直言,鹰式ULP和命令语言的整个概念很麻烦。ULP在只读环境中运行,它影响电路,电路板或库的唯一方法是创建命令列表。这消除了一些有用的编程技术,但是更糟糕的是,这些命令的设计不易于从ULP创建。您需要各种转换(在这种情况下:坐标,形状名称)才能从ULP世界转换为CMD世界。
(编辑)在运行此ULP之前,请设置“电线弯曲”选项以允许任意角度,否则Eagle会尝试将复活的电线调整为允许的角度,这可能会导致流血的混乱。恕我直言,这是ULP / SCR问题的另一个示例。
这是ULP代码:
// gather the commands that must be run on exit
string RunOnExit = "";
void cmd( string s ) { RunOnExit += s + "\n"; }
// return an x or y position in the form that can be used in a command
real f( int x ){
board( B ) switch( B.grid.unit ) {
case 0: return u2mic(x);
case 1: return u2mm(x);
case 2: return u2mil(x);
case 3: return u2inch(x);
}
}
// return the string form of the a via's shape
string sn( int x ){
if( x == VIA_SHAPE_SQUARE ) return "square";
if( x == VIA_SHAPE_ROUND ) return "round";
if( x == VIA_SHAPE_OCTAGON ) return "octagon";
if( x == VIA_SHAPE_ANNULUS ) return "annulus";
if( x == VIA_SHAPE_THERMAL ) return "thermal";
return "unknown-via-shape";
}
// count the number of times x occurs in s
int n_ocurrences( string s, string x ){
int i, n = 0;
while( 1 ){
i = strstr( s, x );
if( i == -1 ) return n;
s = strsub( s, i + strlen( x ));
n++;
}
}
// add a via, but only when it is visited the second time
string via_list = "";
void add_via( int a, int b ){
// for all via's
board( B ) B.signals( S ) S.vias( V ){
// if the via is at the current location
if(( V.x == a ) && ( V.y == b )){
string s, coo;
// the coordinates of the via are used as its identification
sprintf( coo, "(%.6f %.6f)", f( V.x ), f( V.y ));
// if this is the second visit to this via
via_list += coo;
if( n_ocurrences( via_list, coo ) == 2 ){
// resurrect this via
sprintf( s, "VIA '%s' %f %s %s;",
S.name, f( V.drill ), sn( V.shape[ 1 ] ), coo );
cmd( s );
}
}
}
}
if( !board ){
dlgMessageBox("start this ULP in Board", "OK");
exit( 0 );
}
board( B ){
// first delete all coper segments,
// later we will resurrect what we want to keep
cmd( "RIPUP;" );
// for all wire segments in the top and bottom copper layers
B.signals(S) S.wires(W) {
if( ( W.layer == 1 ) || ( W.layer == 16 ) ){
// that are not 0.01 width (that is what the autorouter uses)
if( f( W.width ) != 0.01 ){
string s;
// resurrect via's adjacent to this wire segment
add_via( W.x1, W.y1 );
add_via( W.x2, W.y2 );
sprintf( s, "CHANGE LAYER %d;", W.layer );
cmd( s );
// resurrect this wire segment
sprintf(
s, "WIRE '%s' %f (%.6f %.6f) (%.6f %.6f);",
S.name, f( W.width),
f(W.x1), f(W.y1), f(W.x2), f(W.y2));
cmd( s );
}
}
}
// dlgMessageBox( RunOnExit, "OK");
exit( RunOnExit );
}