Я ненавижу отвечать на свой вопрос, но я иду. Надеюсь, я не получу баллы за ответы, это было бы странно, только за принятие ответа? (Кстати, я не получил никакого ответа на форуме Element14.)
Решением является использование команды DRAW, а не ROUTE. DRAW разместит сегмент провода именно там, где вы укажете (в отличие от 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 );
}