#! /usr/bin/perl

#
# This is draw-sboard
# Created by M J Oldfield, m@mjo.tc
# Created on 9th February, 2009
#

use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;

# Parse arguments
my %Opt = (
  magnification => 2,
  step_size     => 7.2, # The size of one step in points (0.1in = 7.2pts)
  x_offset      => 36,  # X-origin (in points)
  y_offset      => 36,  # Y-origin (in points)
 );

GetOptions(\%Opt, "magnification=f", "rotate!", "filename=s", "help!");

my $show_usage = $Opt{help};
$show_usage++ unless 2 == grep { /^\d+$/ && $_ > 0} @ARGV;

pod2usage(-verbose => 2) 
  if $show_usage;

# Get arguments
my ($strips, $holes) = @ARGV;
my $mag   = $Opt{magnification};
my $scale = $mag * $Opt{step_size};

my ($x_size, $y_size, $s_a, $s_b, $tag) = $Opt{rotate} 
                                        ? ($holes,  $strips, $scale, 0,      'r')
                                        : ($strips, $holes,  0,      $scale, '' );


my $filename = $Opt{filename} || sprintf("%dx%d@%d%s.ps",
                                         $strips, $holes, 100.0 * $mag, $tag);

# Offset of origin
my $bb_x0 = $Opt{x_offset};
my $bb_y0 = $Opt{y_offset};

# Render PostScript settings
my $ctm = sprintf("[%f %f %f %f %f %f]",
                  $s_a, $s_b, $s_b, $s_a, $bb_x0, $bb_y0);

my $bb = sprintf("%d %d %d %d", $bb_x0, 
                                $bb_y0,
                                $bb_x0 + $scale * $x_size,
                                $bb_y0 + $scale * $y_size);


open(my $fh, ">", $filename)
  or die "Can't open $filename: $!\n";
print {$fh} template($strips, $holes, $ctm, $bb);
close($fh);

print STDERR "Wrote template to $filename\n";

sub template
  {
    my ($strips, $holes, $ctm, $bb) = @_;

    # Physical parameters of picture:
    my $delta   = 0.1;  # 1 - track width
    my $dot_r   = 0.2;  # Hole size
    my $cu_gray = 0.95; # Shade of track colour

    my $date    = localtime();

    return <<"EOF";
%!PS-Adobe-3.0
%%Pages: 1
%%BoundingBox: $bb
%%Creator: $0
%%CreationDate: $date
%%EndComments

%%Page:1

/holedict 8 dict def
/hole 
{  
   holedict begin

   /y exch def
   /x exch def

   x $dot_r add y moveto 
   x y $dot_r 0 360 arc closepath

   end
} def

/stripdict 8 dict def
/strip
{
   stripdict begin

   /y exch def

   newpath

   /x0 0 def   
   /y0 y 1 sub $delta add def
   /x1 $holes def
   /y1 y $delta sub def

   x0 y0 moveto x1 y0 lineto x1 y1 lineto x0 y1 lineto closepath

   1 1 $holes { dup 0.5 sub y 0.5 sub hole } for 

   gsave $cu_gray setgray eofill grestore
   gsave 0.5      setgray stroke grestore

   end
} def

/board
{
  0.05 setlinewidth
  1 1 $strips { dup strip } for
} def

/outline
{
  newpath
  0 0 moveto $holes 0 lineto $holes $strips lineto 0 $strips lineto
  closepath 
  0 setgray
  stroke
} def

$ctm concat

board

outline

showpage

%%EOF%%
EOF
  }

__END__

=head1 NAME
 
draw-sboard - Draw a stripboard template in PostScript
  
=head1 USAGE

  draw-sboard 30 50 
 
  draw-sboard 20 20 --rotate

  draw-sboard 20 20 --magnification=3.0

  draw-sboard 30 30 --filename=board.ps
 
=head1 REQUIRED ARGUMENTS

You must supply two integers: the number of rows and the number of holes.

=head1 OPTIONS

=over

=item --rotate

Normally the strips are vertical (which is aligned with the long edge of the paper
in portrait mode), but if this is specified then the strips will be horizontal.

=item --magnification=[factor]

Set the magnification factor of the template. A factor of 1.0 should be real size
(0.1in spacing) but it defaults to a factor of 2.0.

=item --filename=[file]

Set the output filename. If not supplied the program makes up a
filename based on the arguments supplied.

=back
 
=head1 DESCRIPTION

Although one can design stripboard layouts on normal paper, especially
if one uses quadrille pads, I prefer drawing them on something which
actually shows the tracks.

The program fills that need: it draws blank stripboard rectanges of
arbitrary size, magnification, and orientation.

=head2 AUTOMAGIC FILENAMES

If no filename is specified, the program makes up its own name from
the arguments specified. Here are some examples:

=over

=item 20x30@100.ps

20 strips each of 30 holes at 100% magnification i.e. life sized;

=item 30x20@200r.ps

30 strips each of 20 holes at 200% magnification i.e. double life
size, rotated so that strips run horizontally.

=back

=head1 DEPENDENCIES

We need C<Getopt::Long> and C<Pod::Usage>.

=head1 INCOMPATIBILITIES

The generated PostScript might not conform to standards, in fact it probably doesn't.

=head1 BUGS AND LIMITATIONS

The PostScript output could be improved.

Please report problems to the author.

Patches are welcome.
 
=head1 AUTHOR

M J Oldfield, m@mjo.tc

=head1 LICENCE AND COPYRIGHT
 
Copyright (c) 2009, M J Oldfield. All rights reserved.
 
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L<perlartistic>.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 



