package bbox;

# 14.4.2001 IK  bugfix

# some constant values (modify in streambuf::GetPos too!)
($SB_C, $SB_R, $SB_T, $SB_TL, $SB_TR, $SB_L, $SB_B, $SB_BR, $SB_BL) =
  (0, 1, 2, 3, 4, 5, 6, 7, 8);

#
#  create new box object.
#  $box1 = box->new()            create with default (0,0,0,0)
#  $box2 = box->new(xu,yu,xo,yo) create with (xu,yu,xo,yo)
#  $box3 = box->new($loc)        create with (x,y,x,y)
#  $box4 = $box1->new()          clone $loc1
#
sub new
{
    my $r_bbox;
    my $pck = shift;    # first parameter is class name
    if (ref($pck))
    # called as instance method $locobject->new()
    {
	$r_bbox = { "xu" => $pck->{"xu"},
		    "yu" => $pck->{"yu"},
		    "xo" => $pck->{"xo"},
		    "yo" => $pck->{"yo"}
		 };
    }
    else
    # called as class method loc->new()
    {
	if (@_)
	{
	    if (ref($p1 = $_[0]) eq "loc")
	    {
		$xu = $xo = $p1->{"x"};
		$yu = $yo = $p1->{"y"};
	    }
	    else
	    {
		if (scalar(@_)==2)
		{
		    $xu = $xo = $_[0];
		    $yu = $yo = $_[1];
		}
		else
		{
		    $xu = $_[0];
		    $yu = $_[1];
		    $xo = $_[2];
		    $yo = $_[3];
		}
	    }
	}
	else
	{
	    $xu = $yu = $xo = $yo = 0;
	}
	$r_bbox = { "xu" => $xu,
		    "yu" => $yu,
		    "xo" => $xo,
		    "yo" => $yo
		 };
    }
    bless $r_bbox, 'bbox';
    return $r_bbox;
}


#
# initialize existing box
# $box->init()
# $box->init(x,y)
# $box->init($loc)
#
sub init
{
    my $r_bbox = shift;
    my ($xu, $yu, $xo, $yo);
    if (@_)
    # called with arguments
    {
	if (ref($p1 = $_[0]) eq "loc")
	# called with location object
	{
	    $xu = $xo = $p1->{"x"};
	    $yu = $yo = $p1->{"y"};
	}
	else
	# called with numbers
	{
	    $xu = $xo = $_[0];
	    $yu = $yo = $_[1];
	}
    }
    else
    # no arguments
    {
	$xu = $yu = $xo = $yo = 0;
    }
    $r_bbox->{"xu"} = $xu;
    $r_bbox->{"yu"} = $yu;
    $r_bbox->{"xo"} = $xo;
    $r_bbox->{"yo"} = $yo;
}

#
# copy box dimensions
# $box->eq($box1)
#
sub eq
{
    my $r_bbox = shift;
    my ($r_box1) = @_;
    $r_bbox->{"xu"} = $r_box1->{"xu"};
    $r_bbox->{"yu"} = $r_box1->{"yu"};
    $r_bbox->{"xo"} = $r_box1->{"xo"};
    $r_bbox->{"yo"} = $r_box1->{"yo"};
}


#
#  returns width and height of box
#
sub width
{
    my $r_bbox = shift;
    return ($r_bbox->{"xo"} - $r_bbox->{"xu"});
}

sub height
{
    my $r_bbox = shift;
    return ($r_bbox->{"yo"} - $r_bbox->{"yu"});
}


#
#  $box1->minmax(x,y)
#  $box1->minmax($loc)
#  $box1->minmax($box)
#
sub MinMax
{
    my $r_bbox = shift;
    my $p1 = shift;
    if (ref($p1) eq "bbox")
    # box extends box
    {
	$r_bbox->{"xu"} = $p1->{"xu"} if $p1->{"xu"} < $r_bbox->{"xu"};
	$r_bbox->{"yu"} = $p1->{"yu"} if $p1->{"yu"} < $r_bbox->{"yu"};
	$r_bbox->{"xo"} = $p1->{"xo"} if $p1->{"xo"} > $r_bbox->{"xo"};
	$r_bbox->{"yo"} = $p1->{"yo"} if $p1->{"yo"} > $r_bbox->{"yo"};
    }                                     
    else
    {
	if (ref($p1) eq "loc")
	# location object extends box
	{
	    $r_bbox->{"xu"} = $p1->{"x"} if $p1->{"x"} < $r_bbox->{"xu"};
	    $r_bbox->{"yu"} = $p1->{"y"} if $p1->{"y"} < $r_bbox->{"yu"};
	    $r_bbox->{"xo"} = $p1->{"x"} if $p1->{"x"} > $r_bbox->{"xo"};
	    $r_bbox->{"yo"} = $p1->{"y"} if $p1->{"y"} > $r_bbox->{"yo"};
	}
	else
	# point given
	{
	    my $p2 = shift;
	    $r_bbox->{"xu"} = $p1 if $p1 < $r_bbox->{"xu"};
	    $r_bbox->{"yu"} = $p2 if $p2 < $r_bbox->{"yu"};
	    $r_bbox->{"xo"} = $p1 if $p1 > $r_bbox->{"xo"};
	    $r_bbox->{"yo"} = $p2 if $p2 > $r_bbox->{"yo"};
	}
    }
}


#
#  determines $loc so that $loc is in relation $iPos to $box
#  $box->ToConPoint($iPos, $loc)
#
sub ToConPoint
{
    my ($r_bbox, $iPos, $r_loc) = @_;
    $r_loc->{"x"} = $r_bbox->{"xo"} if grep($iPos==$_, ($SB_R, $SB_TR, $SB_BR));
    $r_loc->{"x"} = $r_bbox->{"xu"} if grep($iPos==$_, ($SB_L, $SB_TL, $SB_BL));
    $r_loc->{"x"} = ($r_bbox->{"xu"} + $r_bbox->{"xo"})/2
				 if grep($iPos==$_, ($SB_T, $SB_C, $SB_B));
    $r_loc->{"y"} = $r_bbox->{"yo"} if grep($iPos==$_, ($SB_TR, $SB_T, $SB_TL));
    $r_loc->{"y"} = $r_bbox->{"yu"} if grep($iPos==$_, ($SB_BR, $SB_B, $SB_BL));
    $r_loc->{"y"} = ($r_bbox->{"yu"} + $r_bbox->{"yo"})/2
				 if grep($iPos==$_, ($SB_L, $SB_C, $SB_R));
}


#
#  determines $loc so that $box is in relation $iPos to $locg
#  $box->OrigConPoint($iPos, $loc, $locg)
#
sub OrigConPoint
{
    my ($r_bbox, $iPos, $r_loc, $r_locg) = @_;
    $r_loc->{"x"} = $r_locg->{"x"} - $r_bbox->{"xo"} 
				if grep($iPos==$_, ($SB_R, $SB_TR, $SB_BR));
    $r_loc->{"x"} = $r_locg->{"x"} - $r_bbox->{"xu"} 
				if grep($iPos==$_, ($SB_L, $SB_TL, $SB_BL));
    $r_loc->{"x"} = $r_locg->{"x"} - ($r_bbox->{"xu"} + $r_bbox->{"xo"})/2
				if grep($iPos==$_, ($SB_T, $SB_C, $SB_B));

    $r_loc->{"y"} = $r_locg->{"y"} - $r_bbox->{"yo"} 
				if grep($iPos==$_, ($SB_TR, $SB_T, $SB_TL));
    $r_loc->{"y"} = $r_locg->{"y"} - $r_bbox->{"yu"} 
				if grep($iPos==$_, ($SB_BR, $SB_B, $SB_BL));
    $r_loc->{"y"} = $r_locg->{"y"} - ($r_bbox->{"yu"} + $r_bbox->{"yo"})/2
				if grep($iPos==$_, ($SB_L, $SB_C, $SB_R));
}


#
#  adds offset $loc2 or vec(x,y) to $bbox
#  $box->translate(x,y)
#  $box->translate($loc2)
#
sub translate
{
    my $r_box = shift;
    my $p1 = shift;
    if (ref($p1) eq "loc")
    {
	$r_box->{"xu"} += $p1->{"x"};
	$r_box->{"yu"} += $p1->{"y"};
	$r_box->{"xo"} += $p1->{"x"};
	$r_box->{"yo"} += $p1->{"y"};
    }
    else
    {
	my $p2 = shift;
	$r_box->{"xu"} += $p1;
	$r_box->{"yu"} += $p2;
	$r_box->{"xo"} += $p1;
	$r_box->{"yo"} += $p2;
    }
}


#
# show values
# $loc->dump( [name])
#
sub dump
{
    my $r_bbox = shift;
    my $name = shift;
    printf "%s (BBOX): xu = %f, yu = %f xo = %f yo = %f\n", $name,
	$r_bbox->{"xu"}, $r_bbox->{"yu"}, $r_bbox->{"xo"}, $r_bbox->{"yo"};
}

1;