#!/usr/pkg/bin/perl
use strict; 
use warnings;
use Getopt::Std;
use GDS2;
use Math::Trig;

use feature qw(declared_refs refaliasing say);

my($VERSION);
$VERSION = "2022-12-29 11:46" ; # written by emacs time-stamp
## $VERSION .= ' UTC';
$VERSION =~ s/ /-/g;
$VERSION =~ s/:/./g;

push(@INC, '../fcp-project/');
push(@INC, '../Perl_GDSII_Tutorial/code/');
push(@INC, '.');
# new one, text_flat_r, for rotated cw90, 
require "arc.pm";
require "text2gds.pm";
require 'read-grep-fcp.pm';

my $TOP_PITCH = 100;
my $R3 = 1.7320508;
my $PI = 3.149259265;
my %SQUARE;
my %CIRCLE_HEA;
my $LABEL_LAYER = 0;
my $LABEL_23    = 0;

my %CP18_LIST;	# correct the CP name instantiated
my %CP17_LIST;	# correct the CP name instantiated
my %HASH;

sub large_circle {
   my ($args)  	   = @_;    
   my $size        = $args -> {-size};
   my $sleeve_size = $args -> {-sleeve_size};
   my $debug	   = $args -> {-debug};
   my $gds2File    = $args -> {-gds2File};
   my $name	   = sprintf("HoleSIPH%02dnm", $size * 1000);
   
   my $centerSize = int(($size - $sleeve_size * 2 + 0.05) * 100) * 10;
#   print STDERR $centerSize,"\n";
   my $peripheral = $size * $PI ;
   my $centerCP = sprintf("HoleSIPH%2dnm", $centerSize);

   my $count_raw = int($peripheral/$sleeve_size + 0.05);
   my $count     = int(($count_raw + 3)/4 ) * 4;
#      print STDERR $count,"\n";
   my $inner_center = $size/2 - $sleeve_size/2;
   
   $gds2File -> printBgnstr(-name => $name);
   $CP18_LIST{$centerCP}++;
   $gds2File -> printSref(-name => $centerCP, -xy => [0,0]);
   my @POINT = arc::arc(0, 0,  0, 360, $size/2 - $sleeve_size/2, $count, 1 ,1 );
   my $index = 0;
   my @COORD = @POINT;
   while (my $x = shift @COORD) {
#       print STDERR 'Y: '. $y . ' X: '. $x . ' ';
       my $y = shift @COORD;
# get radian angle
       my $theta = atan($y/$x);
# convert from radian, 
       my $angle = $theta * 180 / $PI;
       if ($angle <   0 ) { $angle += 90;}
       $angle = int(($angle + 2.5)/ 5 ) * 5;
       if ($angle == 90 ) { $angle =   0;}       

       my $SQCP = sprintf("SqSIPHA%dW%dnm", $angle, $sleeve_size * 1000);
       if (defined($x)  & defined($y) ) {
	   $CP18_LIST{$SQCP}++;
       $gds2File -> printSref(-name => $SQCP, -xy => [ $x, $y]);
       }
   }

#   $gds2File -> printBoundary (-xy=> [@POINT], -layer => 20);
   if ($debug) {
   my $string = sprintf("%02d %02d -> %02d", $size * 1000, $count_raw, $count);
   text2gds::text_flat( 0.8, 0, 10, 0.01,  $string, $gds2File);
   }
   $gds2File -> printEndstr();
   return $name;
}

sub square_unit {
   my ($args)   = @_;    
   my $pitch    = $args -> {-pitch};
   my $ratio    = $args -> {-ratio};
   my $size     = $pitch * $ratio;

   my $real     = $args -> {-real};
   my $span     = $args -> {-span};

   my $unit     = $args -> {-unit};
   my $prefix   = $args -> {-prefix};
   my $label_location = $args -> {-label_location};
   my $label_enable = $args -> {-label_enable};
   my $gds2File = $args -> {-gds2File};

   if ($size < 0.3 ) { $span = 5; $real = 4.5;}
   my $size_info = sprintf("S%03d-%03d-P%03d", $real,  $size * 1000, $pitch * 1000);

   my $name     = sprintf("square_unit-%s-%s", $prefix, $size_info);  
      if ($HASH{$name}++ > 0) { return $name;}

 if ($size_info =~ /01$/)  {
       print STDERR __LINE__ . ' ' . $size_info. "\n";
       return $name;}

# ----------------------------------------------------------------------
#                    children structure
# ----------------------------------------------------------------------
   $gds2File -> printBgnstr ( -name => $name .'-01');
   my $pitchY   = int ($pitch * $R3 * 1000) / 1000; # round to 1 nm
   my $columns  = int($real/$pitch);
   my $rows     = int($real/$pitchY);

   my $realX    = int ($columns * $pitch  * 4000) / 4000;
   my $realY    = int ($rows    * $pitchY * 4000) / 4000;

   $gds2File -> printAref (
    -name =>    $unit,
    -columns => $columns,
    -rows =>    $rows,
       -xy   => [ 
         - $realX/2 + $pitch/2,  - $realY/2 + $pitch/2 * $R3/2,
           $realX/2 + $pitch/2,  - $realY/2 + $pitch/2 * $R3/2,
         - $realX/2 + $pitch/2,    $realY/2 + $pitch/2 * $R3/2,
       ]
       );
   $gds2File -> printEndstr ;
# ----------------------------------------------------------------------
#        place  two cells
# ----------------------------------------------------------------------
   $gds2File -> printBgnstr ( -name => $name);
   $gds2File -> printSref( -name => $name . '-01', -xy => [ 0,         -$pitchY/4]);
   $gds2File -> printSref( -name => $name . '-01', -xy => [ $pitch /2,  $pitchY/4]);
   my $wave_length = $pitch  * 1.6;
   my $label_text  = $size_info . ' '. sprintf("%4.3f", $size / $pitch) ;

   my $large_font = $span/100 * 0.5;
   my $small_font = $span/100 * 0.1;
   if ($label_enable) {
       text2gds::text_flat( 0,
                            (- $span/2 + ( 1/100 * $span)) * $label_location * -1 ,
                            0, $large_font, $label_text, $gds2File);
   if ( $small_font > 0.05) {
       text2gds::text_flat( -0.33 * $span,
                           (-0.43 * $span) * $label_location * -1,
                            0, $small_font, $label_text, $gds2File);
   }
   }
#      text2gds::text_flat( 1.2 * $span, 0, 0, 0.1, $size * 1000, $gds2File);
       text2gds::text_flat( 7, 0, 0, 0.16, $size * 1000, $gds2File);
   $gds2File -> printEndstr ;
# ----------------------------------------------------------------------
   return $name;
}

# ---------------------------------------------------------
#   M A I N 
# ---------------------------------------------------------

sub main  {

my $filename = $0;
   $filename =~ s/\.txt$//;
my $debug = 0;

   $filename .= '-'.$VERSION.'.gds';
print $filename,"\n";                    # for  klayout `perl LandS`

my $gds2File = new GDS2(-fileName => '>'. $filename);
$gds2File -> printInitLib(-name=>'contrast-curve',  # can be any name
                          -uUnit =>  0.00025,
                          -dbUnit => 0.00025/1000000);

my %LIST;
# make the line width  as a part, and register in %LIST
#---------------------------------------------------------
#                C P  structure
#---------------------------------------------------------
my @LIST;

foreach my $diameter ( 0.35, 0.40, 0.44, 0.45, 0.5, 0.6) { # 0.44 is required for 600 nm circle
	 push(@LIST,  large_circle({
		  -size		=> $diameter,
		  -sleeve_size	=> 0.10,
		  -debug	=> $debug,
		  -gds2File	=> $gds2File })
	      )
}


my $SPAN = 10;

my (@LARGE_LIST);

foreach my $CP17 ( qw(10 20 30 40 50 60 80 90)) {
    push(@LARGE_LIST, $CP17 /1000);
}

foreach my $CP18 ( 5..30) {
    push(@LARGE_LIST, $CP18 /100);
}
push (@LARGE_LIST, ( 0.4, 0.45, 0.5, 0.6));


my (@TOP_LIST);
foreach my $diameter ( @LARGE_LIST ) {
    my $unit_name;
    if ( $diameter < 0.05 ){
	$unit_name = sprintf("HoleDT%dnm",   $diameter * 1000);
	$CP17_LIST{$unit_name}++; 
    } else {
	$unit_name = sprintf("HoleSIPH%dnm", $diameter * 1000);
	$CP18_LIST{$unit_name}++; 
    }
    
    my $structure = 
    square_unit ({ -span => $SPAN, -real => $SPAN * 0.9, -pitch => $diameter * 2, -prefix=> 'S',
                               -ratio => 0.5,
		   -size => $diameter,
		   -unit => $unit_name,
                   -label_location => -1,
                   -label_enable   =>  1,
                               -gds2File => $gds2File});
    push(@TOP_LIST, $structure);
}



my @CP18_LIST = keys %CP18_LIST ;

    read_grep_fcp::read_grep_fcp({ -gds2File => $gds2File,
                                 -STR => '../fcp-project/18-SIPH.str',
                                 -FCP => '../fcp-project/18-SIPH.fcp',
                                 -grep => \@CP18_LIST
                               });
my @CP17_LIST = keys %CP17_LIST ;

#foreach my $d ( 20, 30, 40, 50, 60, 80, 90) {
#   push(@CP17_LIST, sprintf("HoleDT%dnm", $d));
#	}
     read_grep_fcp::read_grep_fcp({ -gds2File => $gds2File,
                                  -STR => '../fcp-project/17-Trimming.str',
                                  -FCP => '../fcp-project/17-Trimming.fcp',
                                  -grep => \@CP17_LIST,
                                });
my $rough_height =  $#TOP_LIST * $SPAN;
my $half = int ($#TOP_LIST/2);

my @SET = qw (CP17 CP18);
# ------------------------------------------------------
$gds2File -> printBgnstr ( -name => $SET[0]);
foreach my $index (0..3) {
    $gds2File -> printSref ( -name => $TOP_LIST[$index], -xy => [ 0, $index * $SPAN - $rough_height/2]);
}
$gds2File -> printEndstr ();
# ------------------------------------------------------
$gds2File -> printBgnstr ( -name => $SET[1]);
foreach my $index (4 .. $#TOP_LIST) {
    $gds2File -> printSref ( -name => $TOP_LIST[$index], -xy => [ 0, $index * $SPAN - $rough_height/2]);
}
$gds2File -> printEndstr ();
# ------------------------------------------------------

$gds2File -> printBgnstr ( -name => 'top');
foreach my $i (0.. $#SET) {
    $gds2File -> printSref ( -name => $SET[$i],  -xy => [0,0]);
}
my $credit = $0 . ' ' . $VERSION;
text2gds::text_flat( 0, - $rough_height/2 - 7, 17, 0.1, $credit, $gds2File);
$gds2File -> printEndstr ();

$gds2File -> printEndlib ();
}
main();
__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
