package be;
#
#       history
#
#       20-OCT-1999 IK  setting \unitlength in an enclosing group
#       19-JAN-2000 IK  inhibit undesired space (thanks to B. Seckinge)
#

($BE_PS, $BE_PSLATEX, $BE_LATEX) = (1, 2, 3);
my $type = $BE_PSLATEX;

# BE_PS:        drawing and text as PostScript
# BE_PSLATEX:   drawing as PostScript, text as LaTeX picture environment
# BE_LATEX:     drawing and text as LaTeX picture

#
#  create new backend object.
#  $be = be->new($type)
#

sub new
{
   my $r_be;
   my $pck = shift;    # first parameter is class name
   if (ref($pck))
   # called as instance method $beobject->new()
   {
       $r_be = { "type" => $pck->{"type"}
                };
   }
   else
   # called as class method be->new()
   {
       if (@_)
       {
           $r_be = { "type" => $_[0]
                   };
       }
       else
       {
           $r_be = { "type" => $BE_PSLATEX
                   };
       }
   }
   bless $r_be, 'be';
return $r_be;
}

# helper function for LaTeX output
# converts angle Phi to dx/dy in [0,4]
sub phi2delta
{
   my ($phi, $len, $dx, $dy, $proj) = @_;
   my $c30 = cos(30*3.1415927/180);
   $phi = $phi%360;
   SW:
   {
       $$dx = 2, $$dy = 1, $$proj = $c30*$len, last SW if $phi==30;
       $$dx = -2, $$dy = 1, $$proj = $c30*$len, last SW if $phi==150;
       $$dx = -2, $$dy = -1, $$proj = $c30*$len, last SW if $phi==210;
       $$dx = 2, $$dy = -1, $$proj = $c30*$len, last SW if $phi==330;
       $$dx = 1, $$dy = 2, $$proj = $len/2, last SW if $phi==60;
       $$dx = -1, $$dy = 2, $$proj = $len/2, last SW if $phi==120;
       $$dx = -1, $$dy = -2, $$proj = $len/2, last SW if $phi==240;
       $$dx = 1, $$dy = -2, $$proj = $len/2, last SW if $phi==300;
       $$dx = 1, $$dy = 0, $$proj = $len, last SW if $phi==0;
       $$dx = -1, $$dy = 0, $$proj = $len, last SW if $phi==180;
       $$dx = 0, $$dy = 1, $$proj = $len, last SW if $phi==90;
       $$dx = 0, $$dy = -1, $$proj = $len, last SW if $phi==270;
       $$dx = 1, $$dy = 1, $$proj = sqrt($len), last SW if $phi==45;
       $$dx = -1, $$dy = 1, $$proj = sqrt($len), last SW if $phi==135;
       $$dx = -1, $$dy = -1, $$proj = sqrt($len), last SW if $phi==225;
       $$dx = 1, $$dy = -1, $$proj = sqrt($len), last SW if $phi==315;
       print "warning: not converting angle $phi!\n";
   }
}


#
#  draw normal line giving starting point, length and direction
#  $be->line($x, $y, $phi, $len, [,$rem])
#
sub line
{
   my $r_be = shift;
   my ($x, $y, $phi, $len, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "gs %.2f %.2f tr %.2f rotate ".
               "0 0 m %.2f 0 rlineto stroke gr %s\n",
               $x, $y, $phi, $len,
               $rem ? "  %%$rem" : "";
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       my ($xe, $ye) = ($x+cos($phi*$::pi/180)*$len, $y+sin($phi*$::pi/180)*$len);
       sprintf "\\drawline(%.2f,%.2f)(%.2f,%.2f) %s\n",
               $x, $y, $xe, $ye, $rem ? "  %%$rem" : "";
   }
}


#
#  draw general line connecting two points, giving dash pattern
#  $be->draw($x0, $y0, $x1, $y1 [,$cLineType])
#
sub draw
{
   my $r_be = shift;
   my ($x0, $y0, $x1, $y1, $cLineType) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "gs %s 0 setdash %.2f %.2f m %.2f %.2f l stroke gr\n",
               $cLineType, $x0, $y0, $x1, $y1;
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       sprintf "\\drawline(%.2f,%.2f)(%.2f,%.2f)\n",
               $x0, $y0, $x1, $y1;
   }
}


#
#  draw marker at given point
#  $be->mark($x0, $y0, $iType, $iSize)
#
sub mark
{
   my $r_be = shift;
   my ($x, $y, $iType, $iSize) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "%.2f %.2f %.2f m%d\n", $iSize, $x, $y, $iType;
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       sprintf "\\put(%.2f,%.2f){\\circle*{%d}}\n", $x, $y, $iSize;
   }
}


#
#  chemical bond in different shapes
#  $be->bond($x, $y, $phi, $len, $type [,$rem])
#
sub bond
{
   my $r_be = shift;
   my ($x, $y, $phi, $len, $type, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "%.2f %.2f %.2f %.2f b%d%s\n",
               $phi, $x, $y, $len, $type, $rem ? "  %%$rem" : "";
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       my ($xe, $ye) = ($x+cos($phi*$::pi/180)*$len, $y+sin($phi*$::pi/180)*$len);
       my ($dx1, $dy1) = (cos((45+$phi)*$::pi/180)*4, sin((45+$phi)*$::pi/180)*4);
       my ($dxe1, $dye1) = (cos((135+$phi)*$::pi/180)*4, sin((135+$phi)*$::pi/180)*4);
       my ($dx2, $dy2) = (cos((-45+$phi)*$::pi/180)*4, sin((-45+$phi)*$::pi/180)*4);
       my ($dxe2, $dye2) = (cos((-135+$phi)*$::pi/180)*4, sin((-135+$phi)*$::pi/180)*4);
       SW: {
       (sprintf "\\drawline(%.2f,%.2f)(%.2f,%.2f)\n",
               $x, $y, $xe, $ye), last SW if $type==0;
       (sprintf "\\drawline(%.2f,%.2f)(%.2f,%.2f) ".
               "\\drawline(%.2f,%.2f)(%.2f,%.2f)\n",
               $x, $y+$dy1, $xe, $ye+$dye1,
               $x, $y+$dy2, $xe, $ye+$dye2), last SW if $type==5;
       (sprintf "\\drawline(%.2f,%.2f)(%.2f,%.2f) ".
               "\\drawline(%.2f,%.2f)(%.2f,%.2f)\n",
               $x, $y, $xe, $ye,
               $x+$dx1, $y+$dy1, $xe+$dxe1, $ye+$dye1), last SW if $type==6;
       (sprintf "\\drawline(%.2f,%.2f)(%.2f,%.2f) ".
               "\\drawline(%.2f,%.2f)(%.2f,%.2f)\n",
               $x, $y, $xe, $ye,
               $x+$dx2, $y+$dy2, $xe+$dxe2, $ye+$dye2), last SW if $type==7;
       (sprintf "\\drawline(%.2f,%.2f)(%.2f,%.2f) ".
               "\\drawline(%.2f,%.2f)(%.2f,%.2f) ".
               "\\drawline(%.2f,%.2f)(%.2f,%.2f)\n",
               $x, $y, $xe, $ye,
               $x+$dx1, $y+$dy1, $xe+$dxe1, $ye+$dye1,
               $x+$dx2, $y+$dy2, $xe+$dxe2, $ye+$dye2), last SW if $type==8;
       (sprintf "{\\allinethickness{2pt}\\drawline(%.2f,%.2f)(%.2f,%.2f)}\n",
               $x, $y, $xe, $ye), last SW if $type==9;
       (sprintf "{\\allinethickness{2pt}\\dottedline(%.2f,%.2f)(%.2f,%.2f)}\n",
               $x, $y, $xe, $ye), last SW if $type==4;
       (sprintf "\\dottedline(%.2f,%.2f)(%.2f,%.2f)\n",
               $x, $y, $xe, $ye), last SW if $type==13;
       (sprintf "\n"), last SW if $type==12;
       my ($dx, $dy, $proj);
       &phi2delta($phi, $len, \$dx, \$dy, \$proj);
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}}\n",
               $x, $y, $dx, $dy, $proj), last SW if $type==10;
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}}\n",
               $x+$proj, $y, -$dx, $dy, $proj), last SW if $type==11;
       print "warning: not drawing bond type $type\n";
       }
   }
}

#
#  chemical arrow
#  $be->arrow($x, $y, $phi, $len, $type [,$rem])
#
sub arrow
{
   my $r_be = shift;
   my ($x, $y, $phi, $len, $type, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "%.2f %.2f %.2f %.2f ar%d%s\n",
               $len, $phi, $x, $y, $type,
               $rem ? "  %%$rem" : "";
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       my ($dx, $dy, $proj);
       &phi2delta($phi, $len, \$dx, \$dy, \$proj);
       SW: {
       (sprintf "\\put(%.2f,%.2f){\\line(%d,%d){%.2f}}\n",
               $x, $y, $dx, $dy, $proj), last SW if $type==0;
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}}\n",
               $x, $y, $dx, $dy, $proj), last SW if $type==1;
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}}\n",
               $x+$proj, $y, -$dx, $dy, $proj),
               last SW if $type==2;
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}} ".
               "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}}\n",
               $x, $y+3, $dx, $dy, $proj,
               $x+$proj, $y-3, -$dx, $dy, $proj),
               last SW if $type==3;
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}} ".
               "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}}\n",
               $x, $y, $dx, $dy, $proj,
               $x+$proj, $y, -$dx, $dy,),
               last SW if $type==4;
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}} ".
               "\\put(%.2f,%.2f){//}\n",
               $x, $y, $dx, $dy, $proj, $x+$proj/2,$y),
               last SW if $type==5;
       (sprintf "\\put(%.2f,%.2f){\\vector(%d,%d){%.2f}} ".
               "\\put(%.2f,%.2f){//}\n",
               $x+$proj, $y, -$dx, $dy, $proj, $x+$proj/2,$y),
               last SW if $type==6;
       }
   }
}


#
#  blanks out rectangle, normally used to erase background of text
#  $be->erase($x, $y, $width, $height [,$rem])
#
sub erase
{
   my $r_be = shift;
   my ($x, $y, $width, $height, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS)
   {
       sprintf "gs 1 setgray np %f %f moveto %f 0 rlineto 0 %f rlineto -%f 0 rlineto ".
               "closepath fill gr\n",
               $x, $y, $width, $height, $rem ? "  %%$rem" : "";
   }
   elsif ($r_be->{"type"} == $BE_PSLATEX || $r_be->{"type"} == $BE_LATEX)
   {
       sprintf "\\put(%f,%f){\\textcolor{white}{\\rule{%fpt}{%fpt}}}\n",
               $x, $y, $width, $height, $rem ? "  %%$rem" : "";
   }
}


#
#  $be->text($x, $y, $text [,$rem])
#
sub text
{
   my $r_be = shift;
   my ($x, $y, $text, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS)
   {
       sprintf "%.2f %.2f moveto (%s) show%s\n",
               $x, $y, $text, $rem ? "  %%$rem" : "";
   }
   elsif ($r_be->{"type"} == $BE_PSLATEX || $r_be->{"type"} == $BE_LATEX)
   {
       sprintf "\\put(%f,%f){%s}%s\n",
               $x, $y, $text, $rem ? "  %%$rem" : "";
   }
}


#
#  draw a circle
#  $be->arc($mx, $my, $phi0, $phiend, $radius [,$rem])
#
sub arc
{
   my $r_be = shift;
   my ($x, $y, $phi0, $phiend, $radius, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "np %.2f %.2f %4f %4f %.2f arc closepath s%s\n",
               $x, $y, $radius, $phi0, $phiend,
               $rem ? "  %$rem" : "";
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       sprintf "\\put(%.2f,%.2f){\\circle{%.2f}}%s\n",
               $x, $y, $radius, $rem ? "  %$rem" : "";
   }
}


#
#  draws a spline starting at p1, control points p2/p3 with an arrow tip
#  at the end point p4
#  $be->spline($p1.x, $p1.y, ..., $p4.y)
#
sub spline
{
   my $r_be = shift;
   my ($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $angle) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "np %.2f %.2f moveto %.2f %.2f %.2f %.2f %.2f %.2f curveto s".
               "  %d %.2f %.2f atip\n",
               $x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $angle, $x4, $y4;
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       print "warning: not drawing emove spline!\n";
       sprintf "\n";
   }
}


#
#  $be->orbital($x, $y, $iAngle, $rWeight)
#
sub orbital
{
   my $r_be = shift;
   my ($x, $y, $iAngle, $rWeight) = @_;

   my $XY1 = loc->new($x, $y);
   my $XY2 = loc->new($x, $y);
   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {

       sprintf "gsave %.2f %.2f translate %d rotate %.2f dup scale ".
               ".9 setgray np 0 0 moveto  1 .5 1 -.5 0 0 rcurveto fill ".
               ".7 setgray np 0 0 moveto -1 .5 -1 -.5 0 0 rcurveto fill grestore\n",
               $x, $y, $iAngle, $rWeight;
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       print "warning: not drawing orbital!\n";
       sprintf "\n";
   }
}


#
#  sets graphical parameters
#  $be->parameter($name, $wert)
#
sub parameter
{
   my $r_be = shift;
   my ($name, $value, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX)
   {
       SW: {
           (sprintf "%f setlinewidth /lw %f def \n", $value, $value),
                                                       last SW if $name eq "lw";
           (sprintf "%f setgray\n", $value), last SW if $name eq "gray";
           sprintf "/%s %f def\n", $name, $value;
       }
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       SW1: {
           (sprintf "\\allinethickness{%.2fpt}\n", $value), last SW1 if $name eq "lw";
       }
   }
}


# $be->comment($rem)
sub comment
{
   my $r_be = shift;
   my ($rem) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_PSLATEX ||
                                               $r_be->{"type"} == $BE_LATEX)
   {
       sprintf "%%%s\n", $rem;
   }
}


#
#  called when picture is to be opened
#  $be->open($font, $x, $y, [,$rem])
#
sub open
{
   my $r_be = shift;
   my ($font, $x, $y, $rem) = @_;

   if ($r_be->{"type"} == $BE_PS)
   {
       sprintf "%sBoundingBox: 0 0 %7.2f %7.2f%s\n", "%%%%",
               $x, $y, $rem ? "\n%% $rem" : "";

   }
   elsif ($r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "{\\unitlength1pt\\begin{picture}(%7.2f,%7.2f)\n".
       "{\\%sname\n".
       "\\special{\\string\"\n", $x, $y, $font;
   }
   elsif ($r_be->{"type"} == $BE_LATEX)
   {
       sprintf "{\\unitlength1pt\\begin{picture}(%7.2f,%7.2f)\n".
       "{\\%s\n", $x, $y, $font;
   }
}


#
#  called at closure of picture
#  $be->close([$rem])
#
sub close
{
   my $r_be = shift;
   my ($rem) = @_;

   if ($r_be->{"type"} == $BE_PS)
   {
       sprintf "%% end of chem pic%s\n", $rem ? "  ($rem)" : "";
   }
   if ($r_be->{"type"} == $BE_PSLATEX || $r_be->{"type"} == $BE_LATEX)
   {
       sprintf "}\\end{picture}}\%%s\n", $rem ? "  %%$rem" : "";
   }
}


#
#  called after drawing data was written, but before text is wrote
#  $be->inter([$rem])
#
sub inter
{
   my $r_be = shift;
   my ($rem) = @_;

   if ($r_be->{"type"} == $BE_PS || $r_be->{"type"} == $BE_LATEX)
   {
       sprintf "\n";
   }
   elsif ($r_be->{"type"} == $BE_PSLATEX)
   {
       sprintf "} %% end of special%s\n", $rem ? "  ($rem)" : "";
   }
}

1;