/* GNU Ocrad - Optical Character Recognition program Copyright (C) 2003, 2004, 2005, 2006, 2007 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "common.h" #include "rectangle.h" namespace { void error( const char * s ) throw() __attribute__ ((noreturn)); void error( const char * s ) throw() { Ocrad::internal_error( s ); } int hypoti( const int c1, const int c2 ) { long long temp = c1; temp *= temp; long long target = c2; target *= target; target += temp; int lower = std::max( std::abs(c1), std::abs(c2) ); int upper = std::abs(c1) + std::abs(c2); while( upper - lower > 1 ) { int m = ( lower + upper ) / 2; temp = m; temp *= temp; if( temp < target ) lower = m; else upper = m; } temp = lower; temp *= temp; target *= 2; target -= temp; temp = upper; temp *= temp; if( target < temp ) return lower; else return upper; } } // end namespace Rectangle::Rectangle( const int l, const int t, const int r, const int b ) throw() { if( r < l || b < t ) { std::fprintf( stderr, "l = %d, t = %d, r = %d, b = %d\n", l, t, r, b ); error( "bad parameter building a Rectangle" ); } _left = l; _top = t; _right = r; _bottom = b; } void Rectangle::left( const int l ) throw() { if( l > _right ) error( "left, bad parameter resizing a Rectangle" ); _left = l; } void Rectangle::top( const int t ) throw() { if( t > _bottom ) error( "top, bad parameter resizing a Rectangle" ); _top = t; } void Rectangle::right( const int r ) throw() { if( r < _left ) error( "right, bad parameter resizing a Rectangle" ); _right = r; } void Rectangle::bottom( const int b ) throw() { if( b < _top ) error( "bottom, bad parameter resizing a Rectangle" ); _bottom = b; } void Rectangle::height( const int h ) throw() { if( h <= 0 ) error( "height, bad parameter resizing a Rectangle" ); _bottom = _top + h - 1; } void Rectangle::width( const int w ) throw() { if( w <= 0 ) error( "width, bad parameter resizing a Rectangle" ); _right = _left + w - 1; } void Rectangle::add_point( const int row, const int col ) throw() { if( row > _bottom ) _bottom = row; else if( row < _top ) _top = row; if( col > _right ) _right = col; else if( col < _left ) _left = col; } void Rectangle::add_rectangle( const Rectangle & re ) throw() { if( re._left < _left ) _left = re._left; if( re._top < _top ) _top = re._top; if( re._right > _right ) _right = re._right; if( re._bottom > _bottom ) _bottom = re._bottom; } void Rectangle::enlarge( const int scale ) throw() { if( scale > 0 ) { _left *= scale; _top *= scale; _right *= scale; _bottom *= scale; } } void Rectangle::move( const int row, const int col ) throw() { int d = row - _top; if( d ) { _top += d; _bottom += d; } d = col - _left; if( d ) { _left += d; _right += d; } } bool Rectangle::includes( const Rectangle & re ) const throw() { return ( _left <= re._left && _top <= re._top && _right >= re._right && _bottom >= re._bottom ); } bool Rectangle::includes( const int row, const int col ) const throw() { return ( _left <= col && _right >= col && _top <= row && _bottom >= row ); } bool Rectangle::strictly_includes( const Rectangle & re ) const throw() { return ( _left < re._left && _top < re._top && _right > re._right && _bottom > re._bottom ); } bool Rectangle::strictly_includes( const int row, const int col ) const throw() { return ( _left < col && _right > col && _top < row && _bottom > row ); } bool Rectangle::includes_hcenter( const Rectangle & re ) const throw() { return ( _left <= re.hcenter() && _right >= re.hcenter() ); } bool Rectangle::includes_vcenter( const Rectangle & re ) const throw() { return ( _top <= re.vcenter() && _bottom >= re.vcenter() ); } bool Rectangle::h_includes( const Rectangle & re ) const throw() { return ( _left <= re._left && _right >= re._right ); } bool Rectangle::v_includes( const Rectangle & re ) const throw() { return ( _top <= re._top && _bottom >= re._bottom ); } bool Rectangle::h_includes( const int col ) const throw() { return ( _left <= col && _right >= col ); } bool Rectangle::v_includes( const int row ) const throw() { return ( _top <= row && _bottom >= row ); } bool Rectangle::h_overlaps( const Rectangle & re ) const throw() { return ( _left <= re._right && _right >= re._left ); } bool Rectangle::v_overlaps( const Rectangle & re ) const throw() { return ( _top <= re._bottom && _bottom >= re._top ); } bool Rectangle::is_hcentred_in( const Rectangle & re ) const throw() { if( this->h_includes( re.hcenter() ) ) return true; int w = std::min( re.height(), re.width() ) / 2; if( width() < w ) { int d = ( w + 1 ) / 2; if( hcenter() - d <= re.hcenter() && hcenter() + d >= re.hcenter() ) return true; } return false; } bool Rectangle::is_vcentred_in( const Rectangle & re ) const throw() { if( this->v_includes( re.vcenter() ) ) return true; int h = std::min( re.height(), re.width() ) / 2; if( height() < h ) { int d = ( h + 1 ) / 2; if( vcenter() - d <= re.vcenter() && vcenter() + d >= re.vcenter() ) return true; } return false; } bool Rectangle::h_precedes( const Rectangle & re ) const throw() { return ( hcenter() < re.hcenter() ); } bool Rectangle::v_precedes( const Rectangle & re ) const throw() { if( _bottom < re.vcenter() || vcenter() < re._top ) return true; if( this->includes_vcenter( re ) && re.includes_vcenter( *this ) ) return this->h_precedes( re ); return false; } int Rectangle::distance( const Rectangle & re ) const throw() { return hypoti( h_distance( re ), v_distance( re ) ); } int Rectangle::distance( const int row, const int col ) const throw() { return hypoti( h_distance( col ), v_distance( row ) ); } int Rectangle::h_distance( const Rectangle & re ) const throw() { if( re._right <= _left ) return _left - re._right; if( re._left >= _right ) return re._left - _right; return 0; } int Rectangle::h_distance( const int col ) const throw() { if( col <= _left ) return _left - col; if( col >= _right ) return col - _right; return 0; } int Rectangle::v_distance( const Rectangle & re ) const throw() { if( re._bottom <= _top ) return _top - re._bottom; if( re._top >= _bottom ) return re._top - _bottom; return 0; } int Rectangle::v_distance( const int row ) const throw() { if( row <= _top ) return _top - row; if( row >= _bottom ) return row - _bottom; return 0; }