#!/usr/local/bin/perl -w
# GDSII generation 
#
use GDS2;
use strict;
use Getopt::Std;

require '../pm/text2gds.pm';
require './Squares';
require './Stripes';
require './Gaps';
require './Common';

my($VERSION);
$VERSION = "2018-07-17 07:36" ; # written by emacs time-stamp
$VERSION .= ' UTC';

our(@ARGV);
our(%opts);

my $DEBUG = 0;
my $VERBOSE = 0;

my ($gds2File);
my ($project) = $0;

# height of each block
my ($H) = 20;
    $H =  4000;
my ($UpperHeight) = 9200;

my @set = qw (
        1.0     1.5   2.2      3.3     4.7   6.8
        10       15    22      33      47    68    100
    );

my @ratio  = qw ( 1  2.2 4.7 );

my @LINEname;
my @boxX5name;

my @line20name;
my @line32name;
my @line57name;

my @box20name;
my @box32name;
my @box57name;

my  @LINEPTR; 		# structure name pointer array for L and S
my  @LINEspan;		# size of line block (but not used for now)

my  @BOXPTR;		# structure name pointer array for boxes
my  @BOXspan;

sub usage() {
    print <<USAGE;
 $0  [-h] [-2] [-3] [-d] [-v] [-L]
   Generating DrieCond GDSII format (100nm to 100um, height is 4.0 mm)
   Output filename is $0.gds or $0-20nm.gds depending option.
 where:
  -h  Show this help
  -d  debug to show internal value
  -v  verbose
  -2  Add 20nm and 50nm also
  -L  bottom half only
  -3  limited down to 300nm (for LaserWriter)
  -6  limited down to 680nm (for LaserWriter)
USAGE
}

# Prepare primitive structure
# --------------------------------------------------
sub markL($$) {
    my ($size)  = shift;
    my ($gds2File) =	shift;

    my ($a) = $size;
    my ($b) = $size * 0.5;

    my ($structure) = sprintf("MarkLsize%02d", $size);
    $gds2File -> printBgnstr(-name => $structure);
    $gds2File -> printBoundary(
                        -layer=> 0,
			-xy=>[0,    - $b,
			      0,    - $a,
			      - $a, - $a,
			      - $a,    0,
			      - $b,    0,
			      - $b,  - $b]);

    $gds2File -> printEndstr;
    return $structure;
}


# small box only structure
sub box($$) {
    my ($size)  =	shift;
    my ($gds2File) =	shift;

    my ($structure) = sprintf("box-%5.3f", $size);

    $gds2File -> printBgnstr(-name => $structure);
    $gds2File -> printBoundary(
                        -layer=> 0,
			-xy=>[0,	0,
			      $size,   0,
			      $size,   $size,
			      0,        $size,
			      0,        0 ]);
    $gds2File -> printEndstr;
    return $structure;
}

sub box4X5 ($$$$$) {
    my ($name)  =	shift;
    my ($width) =	shift;
    my ($length) =	shift;
    my ($pitch)  =	shift;

    my ($gds2File) =	shift;

    my ($structure) = sprintf("box4x5-%4.2f-%4.2f", $width, $pitch);

    $gds2File -> printBgnstr(-name => $structure);

    my($columns)  = 5;
    my($rows)  = int($length / $pitch );
    my ($intlength ) = $rows * $pitch;
    my($even_height) = int (($pitch * $columns * 0.2) * 100) /100;  # in even nm unit    
#    my($x) =  $column * 5;
#    my($y) =  $rows * 

    $gds2File -> printAref(
	-name =>  $name,
	-columns => $columns,
	-rows =>    $rows,
	-xy   =>   [0,   0,
    		    $pitch * $columns,
		    $even_height,
		    0, $intlength]);
    $gds2File -> printEndstr;    
    return $structure;
}

sub boxX5 ($$$$$) {
    my ($name)  =	shift;
    my ($width) =	shift;
    my ($length) =	shift;
    my ($pitch)  =	shift; # 2 * $width, 3.2  * $width, 5.7 * $width  ( 26.79 etc)

    my ($gds2File) =	shift;

    my ($structure) = sprintf("box5-%4.2f-%4.2f", $width, $pitch);
    my($columns)  = 5;
    my($rows)  = int($length/$pitch);
    my($intlength) = $rows * $pitch;
# if 0.125 is changed to 0.1 warning is reduced from 17 to 8)
# if 100 was 1000, warning was 17 but now 0, but -20nm version still have 17
    my($even_height) = int (($pitch * 5 * 0.2) * 100) /100;  # in even nm unit
    if ($rows < 65000) {
#	print  __LINE__ . ' '. $rows. "\n" if $DEBUG;
    $gds2File -> printBgnstr(-name => $structure);
    $gds2File -> printAref(
	-name =>  $name,
	-columns => $columns,
	-rows =>    $rows,
	-xy   =>   [0,   0,
		    int($pitch * 5 * 50)/50,    $even_height,
#		    $pitch * 5        * 0.125,    # Triangle ratio for slant shape layout
		    0, int($intlength/$rows * 50) *  $rows /50]);
    $gds2File -> printEndstr;    
    } else {
#	print __LINE__ . ' '. $rows . "\n" if $DEBUG;
	my $quad = box4X5($name, $width, $length/4, $pitch, $gds2File);

    $gds2File -> printBgnstr(-name => $structure);
    $gds2File -> printAref(
	-name =>  $quad,
	-columns => 1,
	-rows =>    4,
	-xy   =>   [0,   0,
		    0,   0,
		    0,  int ($length/4) * 4]);
	$gds2File -> printEndstr;
    }	
     return $structure;
}

sub vertical_line ($$$) {
    my ($width)  =	shift;
    my ($length) =	shift;
    my ($gds2File) =	shift;

    my ($structure) = sprintf("v-%5.3f-%03d", $width, $length);
    $gds2File -> printBgnstr(-name => $structure);
    $gds2File -> printBoundary(
                        -layer=> 0,
			-xy=>[0,	0,
			      $width,   0,
			      $width,   $length,
			      0, $length,
			      0,        0 ]);
    $gds2File -> printEndstr;
    return $structure;
}

sub verticalx5 ($$$$$) {
    my ($name)  = shift;
    my ($width) = shift;
    my ($length) = shift;
    my ($pitch)  = shift;

    my ($gds2File) =	shift;

    my ($structure) = sprintf("v5-%4.2f-%03d-%2.3f",
			      $width, $length, $pitch);

    $gds2File -> printBgnstr(-name => $structure);
    $gds2File -> printAref(
	-name =>  $name,
	-columns => 5,
	-rows =>    1,
	-xy   =>   [0,   0,
		int ($pitch * 5 * 50)/50,   0,
		0,   0]);
    $gds2File -> printEndstr;    
    return $structure;
}

sub place_text($$$$ $$$){
    my ($string) = shift;
    my ($x) 	= shift;
    my ($y)	= shift;
    my ($opt3)	= shift;

    my ($size)  = shift;
    my ($vertical) = shift; # not used here now
    my ($gds2File) = shift;

    my ($char_count) = length ($string);
    my ($name);
    my (@Chars);

    my $pitch;
    for my $loc ( 0 .. $char_count - 1) {
	if   ($size < 0.10) { $name = 'tiny_'   . substr($string, $loc, 1); $pitch = 0.35 * $opt3; }
	elsif($size <= 1.5 && !$opts{'1'}) { $name = 'small_'  . substr($string, $loc, 1); $pitch = 0.9  * $opt3; }
        elsif($size < 10 || $opt3 > 1) 
	                    { $name = 'normal_' . substr($string, $loc, 1); $pitch = 7    * $opt3; }
	else                { $name = 'large_'  . substr($string, $loc, 1); $pitch = 70   * $opt3; }
	
	$gds2File -> printSref(
	    -name => $name, 
	    -xy   =>[$x,  $y + $pitch * $loc],
	    -angle => 90.0,
	    );
	push(@Chars, $name);
    }
}
sub letters($$$) {
     my($width, $prefix, $gds2File) = @_;
 
     foreach my $i ( 0 .. 8 ) {
 	my($string) = sprintf("%d", $i);
 	#               layer dotsize, structure name text
 	text2gds::text(0, $width , $prefix . $string, $string, $gds2File );
     }
#    text2gds::text(0, $width , $prefix . ',',   ',', $gds2File );
     if ( $prefix ne 'large_'){
     text2gds::text(0, $width , $prefix . '.',   '.', $gds2File );
     }
 }

sub LineBlock($$$$ $) {
    my $seq	= shift;
    my $gap	= shift;
    my $H	= shift;
    my $opt3	= shift;

    my $gds2File   = shift;

    my $blockname = sprintf ("LineBlock-%02d", $seq);
    my $origin = 0;
    my @Chars;	# to collect the necessary char name structure
    
    $gds2File -> printBgnstr(-name=> $blockname);

    foreach my $i (0 .. $#set) {
	$gds2File -> printSref(
	    -name => ${${LINEPTR}[$seq]}[$i],
	    -xy   => [$origin ,0]
	    );
	
	my($size) = $set[$i];
	# label shift, default value
	my ($lowY)  = -300;
	my ($highY) =  120;
 	my ($X)  = $size * 5;
	my ($xoffset) = 9;
	my ($yoffset) = 0;

	if      ($size < 0.01) { $X = 0.05 * $size - 0.7; $lowY  = -14 * $opt3; $highY = 15  ;
	} elsif ($size < 0.1)  { $X =   10 * $size - 0.7; $lowY  =  -5 * $opt3; $highY =  2.5; $yoffset  =  3;	$xoffset = 0.6;
	} elsif ($size <  10)  {                          $lowY  = -25; $highY =  5  ;
	} elsif ($size < 100)  {                          $lowY  = -200;$highY = 50  ;
	}
	 if ($opt3 > 1 ) { 
	     if ($size <= 1.5)  {$lowY = -15;} else {$lowY = -80;}
	}
# upper
	push (@Chars, place_text($size, $xoffset + $origin + $X, $highY + $H,     $opt3, $size, 1, $gds2File));
# below
	push (@Chars, place_text($size, $xoffset + $origin + $X, $yoffset +$lowY, $opt3, $size, 1, $gds2File));

	# prepare for next origin
	$origin += $size * 5 * 2 * $gap ;    # 1.5 is the ratio for gap
    }

    $gds2File -> printSref( -name => 'MarkLsize40', -xy   => [0, 0]                  );
    $gds2File -> printSref( -name => 'MarkLsize40', -xy   => [0, $H], -reflect => 1   );
    $gds2File -> printEndstr;
    return $blockname, $origin, @Chars;
}

sub BoxBlock($$$$ $) {
    my $seq   = shift;
    my $gap   = shift;
    my $H     = shift;
    my $opt3	= shift;

    my $gds2File   = shift;

    my $blockname = sprintf ("BoxBlock-%02d", $seq);
    my $origin = 0;
    my (@Chars);

    $gds2File -> printBgnstr(-name=> $blockname);
    foreach my $i (0 .. $#set) {
	$gds2File -> printSref(
	    -name => ${${BOXPTR}[$seq]}[$i],
	    -xy   => [$origin ,0]
	    );

	my($size) = $set[$i];

	my ($lowY)  = -300;
	my ($highY) =  25;

 	my ($X)  = $size * 5;
	if ($size < 0.01)     { $X     = (0.05 * $size);$highY = 0.2;	$lowY  =    3;
	} elsif ($size < 0.1) { $X     = (10 * $size);	$highY = 0.2;	$lowY  =   -2;
	} elsif ($size < 1.0) {                         $highY = 1.8;	$lowY  =   -7;
	} elsif ($size < 10)  {	                        $highY =   5;	$lowY  =  -25;
	} elsif ($size < 100) {				$highY =   5;	$lowY  = -200;
	}
	 if ($opt3 > 1 ) { 
	     if ($size <= 1.5)  {$lowY = -15;} else {$lowY = -80;}
	}
	my $x_offset = 10;
	if ( $size <= 10 ) {
	push (@Chars, place_text($size, $origin + $X + $x_offset, $highY + $H, $opt3, $size, 1, $gds2File));
	}
	push (@Chars, place_text($size, $origin + $X + $x_offset , $lowY,       $opt3, $size, 1, $gds2File));

	$origin += $size * 5 * 2 * $gap ;    # 1.5 is the ratio for gap
    }

    $gds2File -> printSref( -name => 'MarkLsize40', -xy   => [0, 0]                  );
    $gds2File -> printSref( -name => 'MarkLsize40', -xy   => [0, $H], -reflect => 1   );
    $gds2File -> printEndstr;
    return $blockname, $origin, @Chars;
}

## --------------------------------------------
##          M A I N  R O U T I N E 
## --------------------------------------------

my ($filename) = $project;
my ($shiftX,  $shiftY) = (-10762.5,   -9045);	#  WHOLE coordinate in TOP, may be adjusted later
 ($shiftX,  $shiftY) = (-10300,   -940);	#  WHOLE coordinate in TOP, may be adjusted later
my ($BottomOnly) = 0;

my $bottom_shift;
my $upper_shift;

if ($opts{'H'} ) {
    $bottom_shift = -2 * $H;}


getopts('vdhH:12L3', \%opts);

if ($opts{'h'} ) { usage(); exit;}
if ($opts{'H'} ) {

    $H		= $opts{'H'};
    $bottom_shift -=  0.5 * $opts{'H'};
    $upper_shift   =  0.5 * $opts{'H'};

    $filename .= sprintf("-%dmm", int($H/1000));
}
if ($opts{'d'} ) { $DEBUG	= 1; }
if ($opts{'v'} ) { $VERBOSE = 1; }
if ($opts{'L'} ) {
    $filename .= '-L';
    $BottomOnly = 1;
#    $shiftX  = -10762.5	#  WHOLE coordinate in TOP, will be adjusted later
    $shiftY  += 4745;
}
#  none               0.1  0.15  0.22          0.33 0.47 0.68
#  1                                                           1.0 ...
#  2   0.02  .. 0.068
#  3                                 0.28 0.30 0.33 0.47 0.68

if ($opts{'2'} ) {
    unshift @set, qw(0.02 0.033 0.047 0.05 0.068);
    $filename .= '-20nm';
}
if (! $opts{'3'} && ! $opts{'1'} ){ 
    unshift @set, qw( 0.1  0.15  0.22 0.33 0.47 0.68)
  # no filename adjustment for here
}
if ( $opts{'3'} ) {
    unshift @set, qw( 0.28 0.30 0.33 0.47 0.68);
    $filename .= '-280nm';
 } else {
    $filename .= '-1um';
}
$bottom_shift = - $H ;
$upper_shift  = $H;

$filename .= '.gds';

$gds2File = new GDS2(-fileName=> '>'. $filename);
$gds2File -> printInitLib(-name=>'LibraryName');

print STDERR sprintf("%04d ", __LINE__), 'Output file: ', $filename, "\n"  if $VERBOSE;

# ---------------------------------------------------------------------
# prepare character string structure 0 .. 9 and (. ,)
my $opt3 = 1;
if ( $opts{'3'} ) {
 letters( 0.15, 'tiny_', $gds2File);
 letters( 0.4, 'small_', $gds2File);
 letters( 3,   'normal_', $gds2File);
 letters( 30,  'large_', $gds2File);
 $opt3 = 3;
} else {
 letters( 0.05, 'tiny_', $gds2File);
 letters( 0.1, 'small_', $gds2File);
 letters( 1,   'normal_', $gds2File);
 letters( 10,  'large_', $gds2File);
}
my $width = 4.5 * $opt3 - 3.5;


my $x =  -5 * $opt3 + 5;
print __LINE__, ' ' , $width, "\n";
print __LINE__, ' ' , $x, "\n";
# prepare Filename ID structure
    text2gds::text(0, $width , 'filename' , $filename,  $gds2File );

# my $localtime = scalar(localtime());
# prepare timestamp cell structure
    text2gds::text(0, $width , 'script-version', 'Script Version: '. $VERSION, $gds2File );

# ---------------------------------------------------------------------
# prepare structure 

foreach my $i (0 .. $#set) {
    my $L = $set[$i];

       $LINEname[$i] =   vertical_line(           $L, $H,         $gds2File);
      $boxX5name[$i] =             box(           $L,             $gds2File);
                                                            # pitch
    $line20name[$i]  = verticalx5   ($LINEname[$i], $L, $H, $L * 2,   $gds2File);  # 1:1
    $line32name[$i]  = verticalx5   ($LINEname[$i], $L, $H, $L * 3.2, $gds2File);  # 1:2.2
    $line57name[$i]  = verticalx5   ($LINEname[$i], $L, $H, $L * 5.7, $gds2File);  # 1:4.7

    @LINEPTR = ( \@line20name, \@line32name,  \@line57name);
    @LINEspan = ( 2   * 5,    # 1:1
		  3.2 * 5,    # 1:2.2
		  5.7 * 5);   # 1:4.7

    $box20name[$i]   = boxX5        ($boxX5name[$i], $L, $H, $L * 2,   $gds2File);
    $box32name[$i]   = boxX5        ($boxX5name[$i], $L, $H, $L * 3.2, $gds2File);
    $box57name[$i]   = boxX5        ($boxX5name[$i], $L, $H, $L * 5.7, $gds2File);    

    @BOXPTR = ( \@box20name, \@box32name,  \@box57name);
    @BOXspan = (  2   * 5,   # 1:1
		  3.2 * 5,   # 1:2.2
		  5.7 * 5);  # 1:4.7
}

# prepare  3 pitch x (box or line)  ---> 6 blocks
# parameter is structure name,
my $origin = 0;

markL(40, $gds2File);
# ----------------------------------------------------------------------

my(@LineName);
my(@BlockName);

my($location);  # variable to controll x direction placement structure to structure
my @originX;
my @Chars;
my @CHARS;

$originX[0] = 0;
                             # sequense, #gap
$opt3 = 1;	# text size variation
if ($opts{'3'} ) {  $opt3 = 3; }  # place_text option (large pitch)

 ($LineName[0], $origin, @Chars) = LineBlock( 0, 1.5, $H, $opt3, $gds2File); $location += $origin; print sprintf("%04d ", __LINE__), $location,"\n" if $DEBUG;  

$originX[1] = $location;
 ($LineName[1], $origin, @Chars) = LineBlock( 1, 2.2, $H, $opt3, $gds2File); $location += $origin; print sprintf("%04d ", __LINE__), $location,"\n" if $DEBUG;

$originX[2] = $location;
 ($LineName[2], $origin, @Chars) = LineBlock( 2, 3.3, $H, $opt3, $gds2File); $location += $origin; print sprintf("%04d ", __LINE__), $location,"\n" if $DEBUG;

$originX[3] = $location;

 $location = 0;
($BlockName[0], $origin, @Chars) = BoxBlock( 0, 1.5,  $H, $opt3, $gds2File); $location += $origin; print sprintf("%04d ", __LINE__), $location,"\n" if $DEBUG;


($BlockName[1], $origin, @Chars) = BoxBlock( 1, 2.2,  $H, $opt3, $gds2File); $location += $origin; print sprintf("%04d ", __LINE__), $location,"\n" if $DEBUG;


($BlockName[2], $origin, @Chars) = BoxBlock( 2, 3.3,  $H, $opt3, $gds2File); $location += $origin; print sprintf("%04d ", __LINE__), $location,"\n" if $DEBUG;


$location -= 100 * (4.7 + 4 + 0.5 ) ; # adjust over run
#$shiftX = - $location / 2;

print sprintf("%04d ", __LINE__), $location,' -> ', $shiftX, "\n" if $DEBUG;

# -----------------------------------------------------------------------
my($SquareX_L, $SquareY_L,
   $SquareX_H, $SquareY_H,
    ) = Squares::Squares($gds2File);

print __LINE__,  ' X: ', $SquareX_L, "\t".' Y:' , $SquareY_L,"\n";
print __LINE__,  ' X: ', $SquareX_H, "\t".' Y:' , $SquareY_H,"\n";


if (!$opts{'3'}) {
Stripes::StripeBlock($gds2File);
}
my ($GapsName);
($GapsName, @Chars)  = Gaps::Gaps($gds2File);

push(@CHARS,@Chars);

my %AVOID_DUPE;
foreach my $c (@CHARS){
    if (defined $AVOID_DUPE{$c}) { next ;}
    else {
	$AVOID_DUPE{$c}++;
    my ($prefix, $width, $char) = split '-', $c;
    common::letters_by_name($prefix.'-', $width, $char, $gds2File);
    }
}

$gds2File -> printBgnstr(-name => 'LOWER-nocenter');
my $filenamey = -500 * $opt3 + 450;
my $versiony  = -600 * $opt3 + 530;

print __LINE__ .  ' ' . $filenamey. "\n";
print __LINE__ .  ' ' . $versiony. "\n"; 

$gds2File -> printSref( -name => 'filename',       -xy   => [  -8,  $filenamey]);
$gds2File -> printSref( -name => 'script-version', -xy   => [  -8,  $versiony ]);

$gds2File -> printSref( -name => 'LineBlock-00',   -xy   => [ $originX[0] -170, $H+400]);
$gds2File -> printSref( -name => 'LineBlock-01',   -xy   => [ $originX[1] -170, $H+400]);
$gds2File -> printSref( -name => 'LineBlock-02',   -xy   => [ $originX[2] -170, $H+400]);

$gds2File -> printSref( -name => 'BoxBlock-00',    -xy   => [ $originX[0] -170,  $opt3 * -400 + 400]);
$gds2File -> printSref( -name => 'BoxBlock-01',    -xy   => [ $originX[1] -170,  $opt3 * -400 + 400]);
$gds2File -> printSref( -name => 'BoxBlock-02',    -xy   => [ $originX[2] -170,  $opt3 * -400 + 400]);
$gds2File -> printEndstr;


$gds2File -> printBgnstr(-name => 'LOWER');
$gds2File -> printSref( -name => 'LOWER-nocenter',    -xy   => [ - 1/2 * $originX[3] + 100 , -$H -200]);
$gds2File -> printEndstr;

# -------------------------------------------------------------
$gds2File -> printBgnstr(-name => 'WHOLE');

$gds2File -> printSref( -name => 'LOWER',          -xy   => [ 11000, $bottom_shift] );

if ( ! $BottomOnly ) {
$gds2File -> printSref( -name => 'Squares',        -xy   => [ 21000, 9000]);
if (!$opts{'3'} && !$opts{'1'}) {
$gds2File -> printSref( -name => 'StripeBlock',    -xy   => [ 0,     $H + 2100]);
}
$gds2File -> printSref( -name => $GapsName,        -xy   => [ 0,     1300]);
}

$gds2File -> printEndstr; # end WHOLE
# -------------------------------------------------------------

$gds2File -> printBgnstr(-name => 'TOP');
print __LINE__ .' ' . $shiftX . ' '.  $shiftY. "\n";
$gds2File -> printSref( -name => 'WHOLE',          -xy   => [$shiftX, $shiftY]);
$gds2File -> printEndstr;

$gds2File -> printEndlib();
__END__
See perldoc GDS2 for help

perl DrieCondPerl
; please note I have copy in ~/.emacs-sub/time-stamp-setup.el
(require 'time-stamp)
(add-hook 'write-file-hooks 'time-stamp)
(setq time-stamp-active t)
;; (setq time-stamp-time-zone "UTC")
(setq time-stamp-time-zone nil)
(setq time-stamp-format "%04y-%02m-%02d %02H:%02M");
(setq time-stamp-start "$VERSION = \"") ;
(setq time-stamp-end "\"") ;
(setq time-stamp-line-limit 20) ; ; default is 8

# debug format
  print STDERR sprintf("%4d <", __LINE__ ),  (caller 0)[3], '>:', (caller 0)[2], ' ',
