3 # Panelises PCB layouts
6 # pcb-panelise [options] layout1.pcb layout2.pcb ...
9 # -gTHOU set inter-board gap to THOU
10 # (should occur _before_ the board which _precedes_ the
11 # gap, and then affects all later gaps)
13 # Layouts are currently simply placed parallel from top to bottom.
14 # Making it put them somewhere else wouldn't be _too_ hard; basically,
15 # make an option for the user to specify xpos and ypos between layouts.
17 # Rotation will be slightly more difficult and will involve a careful
18 # review of Stuff, to see where additional transformations etc. are needed.
19 # It might be eaiser to use pcb to rotate the boards.
21 # We use a trick to make net and element names unique: we append
22 # spaces to the names in the 2nd and subsequent boards. This seems to
23 # work fine in pcb snapshot 1.99.20040530-0.0.1 but means that
24 # - you mustn't feed this program's output to itself!
25 # - you probably don't want to edit the output (but you didn't
26 # edit output files anyway, did you?)
28 # On the other hand, pcb's builtin netlist correspondence checker and
29 # DRC system ought to work properly.
35 our ($line,$indent,$command,$lbrack,$rbrack);
36 our (@a, $output_file, $accumulate);
38 our ($xpos,$ypos,$spaces,@titles);
39 our ($xmax,$ymax,$gap);
40 our ($cutlinewidth,$idstring_size);
46 # 100s of thou like in PCB
57 my ($filename,$fn,$f,$argstring,@stack);
60 foreach $filename (@ARGV) {
61 if ($filename =~ m/^\-g(\d+)$/) {
64 } elsif ($filename =~ m/^\-/) {
67 $f = new IO::File $filename, 'r' or die $filename;
73 if (m/^(\s*) ( [A-Z][A-Za-z]* ) \s* ([[(]) (.*) ([])]) \s* $/x) {
74 ($indent, $command, $lbrack, $argstring, $rbrack) =
76 die unless ($lbrack eq '[') == ($rbrack eq ']');
77 foreach $q (qw(' ")) {
78 $argstring =~ s/ $q ([^$q]*) $q /
79 $z= $1; $z =~ s, ,\001,g; $q.$z.$q;
82 @a= split / /, $argstring;
83 #print STDERR "$argstring>".join("|",@a)."<\n";
86 m/^(?: \-? (?: 0 | [1-9]\d* ) (?: \. \d* )?
87 | 0x[0-9a-f]{8} | 0x[0-9a-f]{16} |
88 \" (?: \w | [-():,.] | \001 | \$ )* \" |
92 if (defined $accumulate) {
95 $fn= join '__', 'op',@stack,$command;
98 } elsif (m/^ (?: \s+ \[ \-? \d+ \s+ \-? \d+ \] )+ \s* $/x) {
100 $fn= join '__', 'polygondata',@stack;
102 } elsif (m/^ \s* \( \s* $/x) {
103 die unless defined $command;
104 push @stack, $command;
106 $fn= join '__', 'begin',@stack;
108 } elsif (m/^ \s* \) \s* $/x) {
109 $fn= join '__', 'end',@stack;
121 die if defined $accumulate;
122 $f->error and die "$filename $!";
127 print $output_file or die $!;
130 sub transform ($;\@) {
132 $ar= \@a unless defined $ar;
133 defined $ar->[$ix] or die;
134 defined $ar->[$ix+1] or die;
136 $ar->[$ix+1] += $ypos;
140 return if length $spaces;
144 die unless defined $command;
145 $output_file .= $indent. $command. $lbrack. join(' ',@a). $rbrack. "\n";
148 $output_file .= $line;
151 our (%identical_map);
154 if (!defined $key) { $key= $command; }
155 if (!exists $identical_map{$key}) {
156 $identical_map{$key}= $line;
159 die unless $identical_map{$key} eq $line;
163 our ($define_identical_key, %define_identical_map);
164 sub define_identical_do () { $define_identical_key= $line; }
165 sub define_identical_begin () { $accumulate=''; }
166 sub define_identical_end () {
167 if (exists $define_identical_map{$define_identical_key}) {
168 die unless $define_identical_map{$define_identical_key} eq
171 $define_identical_map{$define_identical_key}= $accumulate;
172 $output_file .= $define_identical_key."(\n".$accumulate.")\n";
177 our (@thisextent, @last_horizline);
178 our ($netlist_aside,$netlist_data);
179 our ($layer,$layer_aside,%layer_name,%layer_data);
182 my ($xlhs,$xrhs,$y) = @_;
183 $layer_data{10} .= "\tLine[".
184 "$xlhs $y $xrhs $y $cutlinewidth 0 0x00000020".
190 if (@last_horizline) { horizline(@last_horizline); }
193 $a[0] =~ m/^"(.+)"$/ or die;
196 @thisextent= @a[1..2];
197 transform(0,@thisextent);
198 $xmax= $xpos + $thisextent[0] if $xpos + $thisextent[0] > $xmax;
199 $ymax= $thisextent[1] if $thisextent[1] > $ymax;
200 if (length $spaces) { horizline($xpos,$thisextent[0],$ypos); }
204 @last_horizline= ($xpos,$thisextent[0],$thisextent[1]);
205 if ($idstring_size && !length $spaces) {
206 $layer_data{10} .= sprintf
207 ("\tText[%d %d %d %d \"%s\" 0x%08lx]",
208 $xpos+$gap, $thisextent[1] + $idstring_size * 10,
209 0, $idstring_size, 'assembled by '.
214 $ypos= $thisextent[1] + $gap;
218 sub op__Grid { fromfirst(); }
219 sub op__Cursor { fromfirst(); }
220 sub op__Thermal { identical(); }
221 sub op__DRC { identical(); }
222 sub op__Flags { identical(); }
223 sub op__Groups { identical(); }
224 sub op__Styles { fromfirst(); }
226 sub op__Symbol { define_identical_do(); }
227 sub begin__Symbol { define_identical_begin(); }
228 sub end__Symbol { define_identical_end(); }
230 sub op__Via { transform(0); copy(); }
232 $a[2] =~ s/^\"(.*)\"/\"$1$spaces\"/ or die;
236 sub begin__Element { copyline(); }
237 sub end__Element { copyline(); }
238 sub op__Element__Pin { copy(); }
239 sub op__Element__ElementLine { copy(); }
240 sub op__Element__ElementArc { copy(); }
243 if (exists $layer_name{$a[0]}) {
244 die unless $layer_name{$a[0]} eq $a[1];
246 $layer_name{$a[0]}= $a[1];
250 sub begin_aside (\$) {
252 $$asideref= $output_file;
257 $output_file= $$asideref;
261 begin_aside($layer_aside);
263 sub op__Layer__Line {
268 sub op__Layer__Text {
276 sub op__Layer__Polygon {
279 sub begin__Layer__Polygon { copyline(); }
280 sub polygondata__Layer__Polygon {
282 $line =~ s/ \[ (\-?\d+) \ (\-?\d+) \] /
284 transform(0,@polypoint);
287 $output_file .= $line;
289 sub end__Layer__Polygon { copyline(); }
291 $layer_data{$layer} .= $output_file;
292 end_aside($layer_aside);
299 begin_aside($netlist_aside);
301 sub op__NetList__Net {
302 $a[0] =~ s/^\"(.*)\"$/\"$1$spaces\"/ or die;
305 sub begin__NetList__Net { copyline(); }
306 sub op__NetList__Net__Connect {
307 $a[0] =~ s/^\"([^-]+)\-(\d+)\"$/\"$1$spaces-$2\"/ or die;
310 sub end__NetList__Net { copyline(); }
312 $netlist_data .= $output_file;
313 end_aside($netlist_aside);
317 $output_file= ('# made by pcb-panelise $Id$'."\n".
318 "PCB[\"".join('+',@titles).".pcb\" $xmax $ymax]\n".
320 foreach $layer (sort keys %layer_data) {
321 $output_file .= "Layer($layer $layer_name{$layer})\n";
322 $output_file .= "(\n";
323 $output_file .= $layer_data{$layer};
324 $output_file .= ")\n";
326 $output_file .= "NetList()\n";
327 $output_file .= "(\n";
328 $output_file .= $netlist_data;
329 $output_file .= ")\n";