/**********************************************************************
 * File:        rect.c  (Formerly box.c)
 * Description: Bounding box class definition.
 * Author:					Phil Cheatle
 * Created:					Wed Oct 16 15:18:45 BST 1991
 *
 * (C) Copyright 1991, Hewlett-Packard Ltd.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 *
 **********************************************************************/

#include          "mfcpch.h"     //precompiled headers
#include          "rect.h"

/**********************************************************************
 * BOX::BOX()  Constructor from 2 ICOORDS
 *
 **********************************************************************/

BOX::BOX(                   //construtor
         const ICOORD pt1,  //one corner
         const ICOORD pt2   //the other corner
        ) {
  if (pt1.x () <= pt2.x ()) {
    if (pt1.y () <= pt2.y ()) {
      bot_left = pt1;
      top_right = pt2;
    }
    else {
      bot_left = ICOORD (pt1.x (), pt2.y ());
      top_right = ICOORD (pt2.x (), pt1.y ());
    }
  }
  else {
    if (pt1.y () <= pt2.y ()) {
      bot_left = ICOORD (pt2.x (), pt1.y ());
      top_right = ICOORD (pt1.x (), pt2.y ());
    }
    else {
      bot_left = pt2;
      top_right = pt1;
    }
  }
}


/**********************************************************************
 * BOX::intersection()  Build the largest box contained in both boxes
 *
 **********************************************************************/

BOX BOX::intersection(  //shared area box
                      const BOX &box) const {
  ICOORD bl;                     //bottom left
  ICOORD tr;                     //top right

  if (overlap (box)) {
    if (box.bot_left.x () > bot_left.x ())
      bl.set_x (box.bot_left.x ());
    else
      bl.set_x (bot_left.x ());

    if (box.top_right.x () < top_right.x ())
      tr.set_x (box.top_right.x ());
    else
      tr.set_x (top_right.x ());

    if (box.bot_left.y () > bot_left.y ())
      bl.set_y (box.bot_left.y ());
    else
      bl.set_y (bot_left.y ());

    if (box.top_right.y () < top_right.y ())
      tr.set_y (box.top_right.y ());
    else
      tr.set_y (top_right.y ());
  }
  else {
    bl.set_x (MAX_INT16);
    bl.set_y (MAX_INT16);
    tr.set_x (-MAX_INT16);
    tr.set_y (-MAX_INT16);
  }
  return BOX (bl, tr);
}


/**********************************************************************
 * BOX::bounding_union()  Build the smallest box containing both boxes
 *
 **********************************************************************/

BOX BOX::bounding_union(  //box enclosing both
                        const BOX &box) const {
  ICOORD bl;                     //bottom left
  ICOORD tr;                     //top right

  if (box.bot_left.x () < bot_left.x ())
    bl.set_x (box.bot_left.x ());
  else
    bl.set_x (bot_left.x ());

  if (box.top_right.x () > top_right.x ())
    tr.set_x (box.top_right.x ());
  else
    tr.set_x (top_right.x ());

  if (box.bot_left.y () < bot_left.y ())
    bl.set_y (box.bot_left.y ());
  else
    bl.set_y (bot_left.y ());

  if (box.top_right.y () > top_right.y ())
    tr.set_y (box.top_right.y ());
  else
    tr.set_y (top_right.y ());
  return BOX (bl, tr);
}


/**********************************************************************
 * BOX::plot()  Paint a box using specified settings
 *
 **********************************************************************/

#ifndef GRAPHICS_DISABLED
void BOX::plot(                      //paint box
               WINDOW fd,            //where to paint
               INT16 style,          //display style
               INT16 edged,          //show border?
               COLOUR fill_colour,   //colour for inside
               COLOUR border_colour  //colour for border
              ) const {
  interior_style(fd, style, edged); 
  fill_color_index(fd, fill_colour); 
  perimeter_color_index(fd, border_colour); 
  plot(fd); 
}
#endif


/**********************************************************************
 * operator+=
 *
 * Extend one box to include the other  (In place union)
 **********************************************************************/

DLLSYM BOX &
operator+= (                     //bounding bounding bx
BOX & op1,                       //operands
const BOX & op2) {
  if (op2.bot_left.x () < op1.bot_left.x ())
    op1.bot_left.set_x (op2.bot_left.x ());

  if (op2.top_right.x () > op1.top_right.x ())
    op1.top_right.set_x (op2.top_right.x ());

  if (op2.bot_left.y () < op1.bot_left.y ())
    op1.bot_left.set_y (op2.bot_left.y ());

  if (op2.top_right.y () > op1.top_right.y ())
    op1.top_right.set_y (op2.top_right.y ());

  return op1;
}


/**********************************************************************
 * operator-=
 *
 * Reduce one box to intersection with the other  (In place intersection)
 **********************************************************************/

DLLSYM BOX &
operator-= (                     //inplace intersection
BOX & op1,                       //operands
const BOX & op2) {
  if (op1.overlap (op2)) {
    if (op2.bot_left.x () > op1.bot_left.x ())
      op1.bot_left.set_x (op2.bot_left.x ());

    if (op2.top_right.x () < op1.top_right.x ())
      op1.top_right.set_x (op2.top_right.x ());

    if (op2.bot_left.y () > op1.bot_left.y ())
      op1.bot_left.set_y (op2.bot_left.y ());

    if (op2.top_right.y () < op1.top_right.y ())
      op1.top_right.set_y (op2.top_right.y ());
  }
  else {
    op1.bot_left.set_x (MAX_INT16);
    op1.bot_left.set_y (MAX_INT16);
    op1.top_right.set_x (-MAX_INT16);
    op1.top_right.set_y (-MAX_INT16);
  }
  return op1;
}


/**********************************************************************
 * BOX::serialise_asc()  Convert to ascii file.
 *
 **********************************************************************/

void BOX::serialise_asc(         //convert to ascii
                        FILE *f  //file to use
                       ) {
  bot_left.serialise_asc (f);
  top_right.serialise_asc (f);
}


/**********************************************************************
 * BOX::de_serialise_asc()  Convert from ascii file.
 *
 **********************************************************************/

void BOX::de_serialise_asc(         //convert from ascii
                           FILE *f  //file to use
                          ) {
  bot_left.de_serialise_asc (f);
  top_right.de_serialise_asc (f);
}
