#!/usr/sbin/perl
# Program to convert HPGL files to
# AutoCAD vers 11+ dxf files

# See HPGL2SCR.ZIP (available on the "net")
# if you want background on this program
# (some of the scaling algorithms are described therein in hpgl2scr.doc)
# Many thanks for this work by William D. Palmer (wdp@ee.egr.duke.edu)

# See the AutoCAD manual (or dxf.doc.Z on the net)
# for further information on DXF file format

# Albert Putnam (putnam@msc.cornell.edu) Nov 18, 1992.
# Materials Science Center, Cornell University
# Work part of Cornell-IBM Joint Study on Computing for Scientific Research
# This software is provided as is and without warantee.

# Bugs:
# Entity capabilties are not complete.
# Some entities are not correctly represented given scaling considerations
#  If this is a problem - or too many entites are rejected
#  try hpgl2scr.perl
# Heaven help you if you have a ; in your label strings.

# usage: hpgl2dxf a.plt > a.dxf


open(FILE1,@ARGV[0]);            # open the file

$p1x  = 250;    $p1y = 279;              # initial scaling sizes
$p2x  = 10250;  $p2y = 7479;
$u1x  = $p1x;   $u1y = $p1y;
$u2x  = $p2x;   $u2y = $p2y;
$xfact = ($p2x - $p1x) / ($u2x - $u1x);  # scaling factors
$yfact = ($p2y - $p1y) / ($u2y - $u1y);
$height = .15;			         # character height
$layer = 0;				 # ACAD layer (=pen-1)
$true = 1;                               # useful variables
$false = 0;


$/ = ";" ;            # separator character is ; for hpgl
$draw = $false;       # assume the pen is up to start with

printf("  0\nSECTION\n  2\nENTITIES\n"); # prepare the header area

while (<FILE1>) {
 s/\n//;                  # get rid of newlines in the file
 chop;                    # get rid of the ; separator
 $a = substr($_,0,2);     # get the first two characters (the command)
 $b = substr($_,2);       # the rest of the record is command data

 # now act on the various commands

 # The absolute pen positioning command
 if ($a =~ "PA") { 
   while (length($b)!=0) {
     # divide up the line into the appropriate chunks
     ($x,$y,$b) = split(/,/,$b,3);
     # rescale coordinates
     $x = (($x - $u1x) * $xfact + $p1x) / 1000;
     $y = (($y - $u1y) * $yfact + $p1y) / 1000;
     if ( $draw ) {
       # it needs the last coordinate xl,yl to know where to start
       printf("  0\nLINE\n  8\n%d\n",$layer);
       printf(" 10\n%.4f\n 20\n%.4f\n 30\n%.4f\n",$xl,$yl,"0.0");
       printf(" 11\n%.4f\n 21\n%.4f\n 31\n%.4f\n",$x,$y,"0.0");
     }
     $xl = $x;
     $yl = $y;
   }
 }

 elsif ($a =~ "PU") {$draw = $false;}    #pen up

 elsif ($a =~ "PD") {$draw = $true;}     #pen down

 # The relative pen positioning command 
 elsif ($a =~ "PR") { 
   while (length($b)!=0) {
     # divide up the line into the appropriate chunks
     ($x,$y,$b) = split(/,/,$b,3);
     # rescale coordinates
     $x = $xl + (($x - $u1x) * $xfact + $p1x) / 1000;
     $y = $yl + (($y - $u1y) * $yfact + $p1y) / 1000;
     if ( $draw ) {
       # it needs the last coordinate xl,yl to know where to start
       printf("  0\nLINE\n  8\n%d\n",$layer);
       printf(" 10\n%.4f\n 20\n%.4f\n 30\n%.4f\n",$xl,$yl,"0.0");
       printf(" 11\n%.4f\n 21\n%.4f\n 31\n%.4f\n",$x,$y,"0.0");
     }
     $xl = $x;
     $yl = $y;
   }
 }

 # circle command (really should be ellipse -
 #     BUT it is quite hard to make DXF ellipse entity)
 # Note the HPGL manual says circles are always drawn (PD automatic)
 # Automatic return to initial state at end (PD/PU).
 elsif ($a =~ "CI") {
   ($radius) = split(/,/,$b,1);
   $radius = (($radius - $u1x) * $xfact + $p1x) / 1000;
   printf("  0\nCIRCLE\n  8\n%d\n",$layer);
  printf(" 10\n%.4f\n 20\n%.4f\n 30\n%.4f\n 40\n%.4f\n",$xl,$yl,"0.0",$radius);
 }

 # label command
 # manual is unclear whether labels are always drawn (PU/PD?)
 elsif ($a =~ "LB" && $draw) {
   printf("  0\nTEXT\n  8\n%d\n",$layer);
  printf(" 10\n%.4f\n 20\n%.4f\n 30\n%.4f\n 40\n%.4f\n",$xl,$yl,"0.0",$height);
   chop($b);
   printf("  1\n%s\n",$b);
 }

 # scaling
 elsif ($a =~ "IP") {
   ($p1x,$p1y,$ip2x,$ip2y) = split(/,/,$b,4);
   if (length($p1x)==0) {   # reset to defaults
     $p1x  = 250;    $p1y = 279;              # initial scaling sizes
     $p2x  = 10250;  $p2y = 7479;
   }
   if (length($ip2x)!=0) { $p2x = $ip2x; $p2y = $ip2y; }
   $xfact = ($p2x - $p1x) / ($u2x - $u1x);
   $yfact = ($p2y - $p1y) / ($u2y - $u1y);
 }

 # scaling
 elsif ($a =~ "SC") {
   ($u1x,$u1y,$u2x,$u2y) = split(/,/,$b,4);
   if (length($u1x)==0) {   # reset to defaults
     $u1x  = $p1x;   $u1y = $p1y;             #initial scaling sizes
     $u2x  = $p2x;   $u2y = $p2y;
   }
   $xfact = ($p2x - $p1x) / ($u2x - $u1x);
   $yfact = ($p2y - $p1y) / ($u2y - $u1y);
 }

 # relative character size
 elsif ($a =~ "SR") {
   ($width,$height) = split(/,/,$b,2);
   if (length($width)==0) { $width = 0.75; $height = 1.5; }
   $aspect = $width / $height * ($p2x - $p1x) / ($p2y - $p1y);
   $height = $height * ($p2y - $p1y) / 100000;
 }

 # absolute character size (may not work - untested)
 elsif ($a =~ "SI") {
   ($width,$height) = split(/,/,$b,2);
   if (length($width)==0) { $width = 0.19; $height = 0.27; }
   $aspect = $width / $height;
   $height = $height / 2.54;
 }

 # pen selection
 elsif ($a =~ "SP") {
   $layer = $b-1;
 }

 # some cleanup stuff
 elsif ($a =~ "O[AC]")
    {print STDERR "$a output position request: Pen at $xl,$yl\n";}
 elsif ($a =~ "O[PW]")
    {print STDERR "$a output window request: $p1x,$p1y,$p2x,$p2y\n";}
 elsif ($a =~ "V[A-Z]")
    {print STDERR "Velocity statement $a$b not needed\n";}
 elsif ($a =~ "A[A-Z]")
    {print STDERR "Statement $a$b not supported\n";}
 elsif ($a =~ "C[A-Z]")
    {print STDERR "Character set statement $a$b not supported\n";}
 elsif ($a =~ "D[CPR]")
    {print STDERR "Digitizer statement $a$b not supported\n";}
 elsif ($a =~ "DF")
    {print STDERR "Default reset statement $a$b not supported\n";}
 elsif ($a =~ "IN")
    {print STDERR "Initialize statement $a$b not supported\n";}
 elsif ($a =~ "[D-S][A-Z]")
    {print STDERR "Statement $a$b not supported\n";}
 elsif ($a =~ "[TXY][A-Z]")
    {print STDERR "Tick statement $a$b not supported\n";}
 elsif ($a =~ "U[A-Z]")
    {print STDERR "User defined char statement $a$b not supported\n";}
 elsif ($a =~ "[A-Z][A-Z]")
    {print STDERR "Statement $a$b unknown, check HPGL docn, or source\n";}

}

printf("  0\nENDSEC\n  0\nEOF\n");


