/* GNU Ocrad - Optical Character Recognition program
Copyright (C) 2003-2019 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 2 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
#include "common.h"
#include "rectangle.h"
namespace {
void error( const char * const msg )
{ Ocrad::internal_error( msg ); }
} // end namespace
Rectangle::Rectangle( const int l, const int t, const int r, const int b )
{
if( r < l || b < t )
{
if( verbosity >= 0 )
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 )
{
if( l > right_ ) error( "left, bad parameter resizing a Rectangle." );
left_ = l;
}
void Rectangle::top( const int t )
{
if( t > bottom_ ) error( "top, bad parameter resizing a Rectangle." );
top_ = t;
}
void Rectangle::right( const int r )
{
if( r < left_ ) error( "right, bad parameter resizing a Rectangle." );
right_ = r;
}
void Rectangle::bottom( const int b )
{
if( b < top_ ) error( "bottom, bad parameter resizing a Rectangle." );
bottom_ = b;
}
void Rectangle::height( const int h )
{
if( h <= 0 ) error( "height, bad parameter resizing a Rectangle." );
bottom_ = top_ + h - 1;
}
void Rectangle::width( const int w )
{
if( w <= 0 ) error( "width, bad parameter resizing a Rectangle." );
right_ = left_ + w - 1;
}
void Rectangle::add_point( const int row, const int col )
{
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 )
{
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 )
{
if( scale > 1 )
{ left_ *= scale; top_ *= scale; right_ *= scale; bottom_ *= scale; }
}
void Rectangle::move( const int row, const int col )
{
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
{
return ( left_ <= re.left_ && top_ <= re.top_ &&
right_ >= re.right_ && bottom_ >= re.bottom_ );
}
bool Rectangle::includes( const int row, const int col ) const
{
return ( left_ <= col && right_ >= col && top_ <= row && bottom_ >= row );
}
bool Rectangle::strictly_includes( const Rectangle & re ) const
{
return ( left_ < re.left_ && top_ < re.top_ &&
right_ > re.right_ && bottom_ > re.bottom_ );
}
bool Rectangle::strictly_includes( const int row, const int col ) const
{
return ( left_ < col && right_ > col && top_ < row && bottom_ > row );
}
bool Rectangle::includes_hcenter( const Rectangle & re ) const
{ return ( left_ <= re.hcenter() && right_ >= re.hcenter() ); }
bool Rectangle::includes_vcenter( const Rectangle & re ) const
{ return ( top_ <= re.vcenter() && bottom_ >= re.vcenter() ); }
bool Rectangle::h_includes( const Rectangle & re ) const
{ return ( left_ <= re.left_ && right_ >= re.right_ ); }
bool Rectangle::v_includes( const Rectangle & re ) const
{ return ( top_ <= re.top_ && bottom_ >= re.bottom_ ); }
bool Rectangle::h_includes( const int col ) const
{ return ( left_ <= col && right_ >= col ); }
bool Rectangle::v_includes( const int row ) const
{ return ( top_ <= row && bottom_ >= row ); }
bool Rectangle::h_overlaps( const Rectangle & re ) const
{ return ( left_ <= re.right_ && right_ >= re.left_ ); }
bool Rectangle::v_overlaps( const Rectangle & re ) const
{ return ( top_ <= re.bottom_ && bottom_ >= re.top_ ); }
int Rectangle::v_overlap_percent( const Rectangle & re ) const
{
int ov = std::min( bottom_, re.bottom_ ) - std::max( top_, re.top_ ) + 1;
if( ov > 0 )
ov = std::max( 1, ( ov * 100 ) / std::min( height(), re.height() ) );
else ov = 0;
return ov;
}
bool Rectangle::is_hcentred_in( const Rectangle & re ) const
{
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
{
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::precedes( const Rectangle & re ) const
{
if( right_ < re.left_ ) return true;
if( this->h_overlaps( re ) &&
( ( top_ < re.top_ ) || ( top_ == re.top_ && left_ < re.left_ ) ) )
return true;
return false;
}
bool Rectangle::h_precedes( const Rectangle & re ) const
{ return ( hcenter() < re.hcenter() ); }
bool Rectangle::v_precedes( const Rectangle & re ) const
{
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
{ return hypoti( h_distance( re ), v_distance( re ) ); }
int Rectangle::distance( const int row, const int col ) const
{ return hypoti( h_distance( col ), v_distance( row ) ); }
int Rectangle::h_distance( const Rectangle & re ) const
{
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
{
if( col <= left_ ) return left_ - col;
if( col >= right_ ) return col - right_;
return 0;
}
int Rectangle::v_distance( const Rectangle & re ) const
{
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
{
if( row <= top_ ) return top_ - row;
if( row >= bottom_ ) return row - bottom_;
return 0;
}
int Rectangle::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;
}