/********************************************************************** * 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 #include "points.h" #include "ndminx.h" #include "tprintf.h" #include "scrollview.h" 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 (); } void set_top(int y) { top_right.set_y(y); } inT16 bottom() const { // coord of bottom return bot_left.y (); } void set_bottom(int y) { bot_left.set_y(y); } inT16 left() const { // coord of left return bot_left.x (); } void set_left(int x) { bot_left.set_x(x); } inT16 right() const { // coord of right return top_right.x (); } void set_right(int x) { top_right.set_x(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