blob: c6174744e77c77e2e7528f7fd7bd6a069fddc9e7 [file] [log] [blame]
/**********************************************************************
* File: rect.h (Formerly box.h)
* 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.
*
**********************************************************************/
#ifndef RECT_H
#define RECT_H
#include <math.h>
#include "points.h"
#include "ndminx.h"
#include "tprintf.h"
#ifndef GRAPHICS_DISABLED
#include "scrollview.h"
#endif
class DLLSYM TBOX //bounding box
{
public:
TBOX (): //empty constructor
bot_left (MAX_INT16, MAX_INT16), top_right (-MAX_INT16, -MAX_INT16) {
} //null box
TBOX( //constructor
const ICOORD pt1, //one corner
const ICOORD pt2); //the other corner
TBOX( //box around FCOORD
const FCOORD pt);
BOOL8 null_box() const { //Is box null
return ((left () > right ()) || (top () < bottom ()));
}
inT16 top() const { // coord of top
return top_right.y ();
}
inT16 bottom() const { // coord of bottom
return bot_left.y ();
}
inT16 left() const { // coord of left
return bot_left.x ();
}
inT16 right() const { // coord of right
return top_right.x ();
}
//access function
const ICOORD &botleft() const {
return bot_left;
}
ICOORD botright() const { // ~ access function
return ICOORD (top_right.x (), bot_left.y ());
}
ICOORD topleft() const { // ~ access function
return ICOORD (bot_left.x (), top_right.y ());
}
//access function
const ICOORD &topright() const {
return top_right;
}
inT16 height() const { //how high is it?
if (!null_box ())
return top_right.y () - bot_left.y ();
else
return 0;
}
inT16 width() const { //how high is it?
if (!null_box ())
return top_right.x () - bot_left.x ();
else
return 0;
}
inT32 area() const { //what is the area?
if (!null_box ())
return width () * height ();
else
return 0;
}
void move_bottom_edge( // move one edge
const inT16 y) { // by +/- y
bot_left += ICOORD (0, y);
}
void move_left_edge( // move one edge
const inT16 x) { // by +/- x
bot_left += ICOORD (x, 0);
}
void move_right_edge( // move one edge
const inT16 x) { // by +/- x
top_right += ICOORD (x, 0);
}
void move_top_edge( // move one edge
const inT16 y) { // by +/- y
top_right += ICOORD (0, y);
}
void move( // move box
const ICOORD vec) { // by vector
bot_left += vec;
top_right += vec;
}
void move( // move box
const FCOORD vec) { // by float vector
bot_left.set_x ((inT16) floor (bot_left.x () + vec.x ()));
//round left
bot_left.set_y ((inT16) floor (bot_left.y () + vec.y ()));
//round down
top_right.set_x ((inT16) ceil (top_right.x () + vec.x ()));
//round right
top_right.set_y ((inT16) ceil (top_right.y () + vec.y ()));
//round up
}
void scale( // scale box
const float f) { // by multiplier
//round left
bot_left.set_x ((inT16) floor (bot_left.x () * f));
//round down
bot_left.set_y ((inT16) floor (bot_left.y () * f));
top_right.set_x ((inT16) ceil (top_right.x () * f));
//round right
top_right.set_y ((inT16) ceil (top_right.y () * f));
//round up
}
void scale( // scale box
const FCOORD vec) { // by float vector
bot_left.set_x ((inT16) floor (bot_left.x () * vec.x ()));
bot_left.set_y ((inT16) floor (bot_left.y () * vec.y ()));
top_right.set_x ((inT16) ceil (top_right.x () * vec.x ()));
top_right.set_y ((inT16) ceil (top_right.y () * vec.y ()));
}
void rotate( //rotate coords
const FCOORD vec) { //by vector
bot_left.rotate (vec);
top_right.rotate (vec);
*this = TBOX (bot_left, top_right);
}
BOOL8 contains( //is pt inside box
const FCOORD pt) const;
BOOL8 contains( //is box inside box
const TBOX &box) const;
// Do boxes overlap on x axis.
BOOL8 x_overlap(const TBOX &box) const;
// Do boxes overlap on x axis by more than
// half of the width of the narrower box.
BOOL8 major_x_overlap(const TBOX &box) const;
BOOL8 overlap( //do boxes overlap
const TBOX &box) const;
BOOL8 major_overlap( // do boxes overlap more than half
const TBOX &box) const;
TBOX intersection( //shared area box
const TBOX &box) const;
TBOX bounding_union( //box enclosing both
const TBOX &box) const;
void print() { //print
tprintf ("Bounding box=(%d,%d)->(%d,%d)\n",
left (), bottom (), right (), top ());
}
#ifndef GRAPHICS_DISABLED
void plot( //use current settings
ScrollView* fd) const { //where to paint
fd->Rectangle(bot_left.x (), bot_left.y (), top_right.x (),
top_right.y ());
}
void plot( //paint box
ScrollView* fd, //where to paint
ScrollView::Color fill_colour, //colour for inside
ScrollView::Color border_colour) const; //colour for border
#endif
friend DLLSYM TBOX & operator+= (TBOX &, const TBOX &);
//in place union
friend DLLSYM TBOX & operator-= (TBOX &, const TBOX &);
//in place intrsection
void serialise_asc( //convert to ascii
FILE *f);
void de_serialise_asc( //convert from ascii
FILE *f);
private:
ICOORD bot_left; //bottom left corner
ICOORD top_right; //top right corner
};
/**********************************************************************
* TBOX::TBOX() Constructor from 1 FCOORD
*
**********************************************************************/
inline TBOX::TBOX( //construtor
const FCOORD pt //floating centre
) {
bot_left = ICOORD ((inT16) floor (pt.x ()), (inT16) floor (pt.y ()));
top_right = ICOORD ((inT16) ceil (pt.x ()), (inT16) ceil (pt.y ()));
}
/**********************************************************************
* TBOX::contains() Is point within box
*
**********************************************************************/
inline BOOL8 TBOX::contains(const FCOORD pt) const {
return ((pt.x () >= bot_left.x ()) &&
(pt.x () <= top_right.x ()) &&
(pt.y () >= bot_left.y ()) && (pt.y () <= top_right.y ()));
}
/**********************************************************************
* TBOX::contains() Is box within box
*
**********************************************************************/
inline BOOL8 TBOX::contains(const TBOX &box) const {
return (contains (box.bot_left) && contains (box.top_right));
}
/**********************************************************************
* TBOX::overlap() Do two boxes overlap?
*
**********************************************************************/
inline BOOL8 TBOX::overlap( //do boxes overlap
const TBOX &box) const {
return ((box.bot_left.x () <= top_right.x ()) &&
(box.top_right.x () >= bot_left.x ()) &&
(box.bot_left.y () <= top_right.y ()) &&
(box.top_right.y () >= bot_left.y ()));
}
/**********************************************************************
* TBOX::major_overlap() Do two boxes overlap by at least half of the smallest?
*
**********************************************************************/
inline BOOL8 TBOX::major_overlap( // Do boxes overlap more that half.
const TBOX &box) const {
int overlap = MIN(box.top_right.x(), top_right.x());
overlap -= MAX(box.bot_left.x(), bot_left.x());
overlap += overlap;
if (overlap < MIN(box.width(), width()))
return false;
overlap = MIN(box.top_right.y(), top_right.y());
overlap -= MAX(box.bot_left.y(), bot_left.y());
overlap += overlap;
if (overlap < MIN(box.height(), height()))
return false;
return true;
}
inline BOOL8 TBOX::x_overlap(const TBOX &box) const {
return ((box.bot_left.x() <= top_right.x()) &&
(box.top_right.x() >= bot_left.x()));
}
inline BOOL8 TBOX::major_x_overlap(const TBOX &box) const {
inT16 overlap = box.width();
if (this->left() > box.left()) {
overlap -= this->left() - box.left();
}
if (this->right() < box.right()) {
overlap -= box.right() - this->right();
}
return (overlap >= box.width() / 2 || overlap >= this->width() / 2);
}
#endif