1 /*  GNU Ocrad - Optical Character Recognition program
2     Copyright (C) 2003-2019 Antonio Diaz Diaz.
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include <algorithm>
19 #include <cstddef>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <vector>
23 
24 #include "common.h"
25 #include "rectangle.h"
26 
27 
28 namespace {
29 
error(const char * const msg)30 void error( const char * const msg )
31   { Ocrad::internal_error( msg ); }
32 
33 } // end namespace
34 
35 
Rectangle(const int l,const int t,const int r,const int b)36 Rectangle::Rectangle( const int l, const int t, const int r, const int b )
37   {
38   if( r < l || b < t )
39     {
40     if( verbosity >= 0 )
41       std::fprintf( stderr, "l = %d, t = %d, r = %d, b = %d\n", l, t, r, b );
42     error( "bad parameter building a Rectangle." );
43     }
44   left_ = l; top_ = t; right_ = r; bottom_ = b;
45   }
46 
47 
left(const int l)48 void Rectangle::left( const int l )
49   {
50   if( l > right_ ) error( "left, bad parameter resizing a Rectangle." );
51   left_ = l;
52   }
53 
54 
top(const int t)55 void Rectangle::top( const int t )
56   {
57   if( t > bottom_ ) error( "top, bad parameter resizing a Rectangle." );
58   top_ = t;
59   }
60 
61 
right(const int r)62 void Rectangle::right( const int r )
63   {
64   if( r < left_ ) error( "right, bad parameter resizing a Rectangle." );
65   right_ = r;
66   }
67 
68 
bottom(const int b)69 void Rectangle::bottom( const int b )
70   {
71   if( b < top_ ) error( "bottom, bad parameter resizing a Rectangle." );
72   bottom_ = b;
73   }
74 
75 
height(const int h)76 void Rectangle::height( const int h )
77   {
78   if( h <= 0 ) error( "height, bad parameter resizing a Rectangle." );
79   bottom_ = top_ + h - 1;
80   }
81 
82 
width(const int w)83 void Rectangle::width( const int w )
84   {
85   if( w <= 0 ) error( "width, bad parameter resizing a Rectangle." );
86   right_ = left_ + w - 1;
87   }
88 
89 
add_point(const int row,const int col)90 void Rectangle::add_point( const int row, const int col )
91   {
92   if( row > bottom_ ) bottom_ = row; else if( row < top_ ) top_ = row;
93   if( col > right_ ) right_ = col;   else if( col < left_ ) left_ = col;
94   }
95 
96 
add_rectangle(const Rectangle & re)97 void Rectangle::add_rectangle( const Rectangle & re )
98   {
99   if( re.left_ < left_ )     left_ = re.left_;
100   if( re.top_ < top_ )       top_ = re.top_;
101   if( re.right_ > right_ )   right_ = re.right_;
102   if( re.bottom_ > bottom_ ) bottom_ = re.bottom_;
103   }
104 
105 
enlarge(const int scale)106 void Rectangle::enlarge( const int scale )
107   {
108   if( scale > 1 )
109     { left_ *= scale; top_ *= scale; right_ *= scale; bottom_ *= scale; }
110   }
111 
112 
move(const int row,const int col)113 void Rectangle::move( const int row, const int col )
114   {
115   int d = row - top_; if( d ) { top_ += d; bottom_ += d; }
116   d = col - left_; if( d ) { left_ += d; right_ += d; }
117   }
118 
119 
includes(const Rectangle & re) const120 bool Rectangle::includes( const Rectangle & re ) const
121   {
122   return ( left_  <= re.left_  && top_    <= re.top_ &&
123            right_ >= re.right_ && bottom_ >= re.bottom_ );
124   }
125 
126 
includes(const int row,const int col) const127 bool Rectangle::includes( const int row, const int col ) const
128   {
129   return ( left_ <= col && right_ >= col && top_ <= row && bottom_ >= row );
130   }
131 
132 
strictly_includes(const Rectangle & re) const133 bool Rectangle::strictly_includes( const Rectangle & re ) const
134   {
135   return ( left_  < re.left_  && top_    < re.top_ &&
136            right_ > re.right_ && bottom_ > re.bottom_ );
137   }
138 
139 
strictly_includes(const int row,const int col) const140 bool Rectangle::strictly_includes( const int row, const int col ) const
141   {
142   return ( left_ < col && right_ > col && top_ < row && bottom_ > row );
143   }
144 
145 
includes_hcenter(const Rectangle & re) const146 bool Rectangle::includes_hcenter( const Rectangle & re ) const
147   { return ( left_ <= re.hcenter() && right_ >= re.hcenter() ); }
148 
149 
includes_vcenter(const Rectangle & re) const150 bool Rectangle::includes_vcenter( const Rectangle & re ) const
151   { return ( top_ <= re.vcenter() && bottom_ >= re.vcenter() ); }
152 
153 
h_includes(const Rectangle & re) const154 bool Rectangle::h_includes( const Rectangle & re ) const
155   { return ( left_ <= re.left_ && right_ >= re.right_ ); }
156 
157 
v_includes(const Rectangle & re) const158 bool Rectangle::v_includes( const Rectangle & re ) const
159   { return ( top_ <= re.top_ && bottom_ >= re.bottom_ ); }
160 
161 
h_includes(const int col) const162 bool Rectangle::h_includes( const int col ) const
163   { return ( left_ <= col && right_ >= col ); }
164 
165 
v_includes(const int row) const166 bool Rectangle::v_includes( const int row ) const
167   { return ( top_ <= row && bottom_ >= row ); }
168 
169 
h_overlaps(const Rectangle & re) const170 bool Rectangle::h_overlaps( const Rectangle & re ) const
171   { return ( left_ <= re.right_ && right_ >= re.left_ ); }
172 
173 
v_overlaps(const Rectangle & re) const174 bool Rectangle::v_overlaps( const Rectangle & re ) const
175   { return ( top_ <= re.bottom_ && bottom_ >= re.top_ ); }
176 
177 
v_overlap_percent(const Rectangle & re) const178 int Rectangle::v_overlap_percent( const Rectangle & re ) const
179   {
180   int ov = std::min( bottom_, re.bottom_ ) - std::max( top_, re.top_ ) + 1;
181   if( ov > 0 )
182     ov = std::max( 1, ( ov * 100 ) / std::min( height(), re.height() ) );
183   else ov = 0;
184   return ov;
185   }
186 
187 
is_hcentred_in(const Rectangle & re) const188 bool Rectangle::is_hcentred_in( const Rectangle & re ) const
189   {
190   if( this->h_includes( re.hcenter() ) ) return true;
191   int w = std::min( re.height(), re.width() ) / 2;
192   if( width() < w )
193     {
194     int d = ( w + 1 ) / 2;
195     if( hcenter() - d <= re.hcenter() && hcenter() + d >= re.hcenter() )
196       return true;
197     }
198   return false;
199   }
200 
201 
is_vcentred_in(const Rectangle & re) const202 bool Rectangle::is_vcentred_in( const Rectangle & re ) const
203   {
204   if( this->v_includes( re.vcenter() ) ) return true;
205   int h = std::min( re.height(), re.width() ) / 2;
206   if( height() < h )
207     {
208     int d = ( h + 1 ) / 2;
209     if( vcenter() - d <= re.vcenter() && vcenter() + d >= re.vcenter() )
210       return true;
211     }
212   return false;
213   }
214 
215 
precedes(const Rectangle & re) const216 bool Rectangle::precedes( const Rectangle & re ) const
217   {
218   if( right_ < re.left_ ) return true;
219   if( this->h_overlaps( re ) &&
220       ( ( top_ < re.top_ ) || ( top_ == re.top_ && left_ < re.left_ ) ) )
221     return true;
222   return false;
223   }
224 
225 
h_precedes(const Rectangle & re) const226 bool Rectangle::h_precedes( const Rectangle & re ) const
227   { return ( hcenter() < re.hcenter() ); }
228 
229 
v_precedes(const Rectangle & re) const230 bool Rectangle::v_precedes( const Rectangle & re ) const
231   {
232   if( bottom_ < re.vcenter() || vcenter() < re.top_ ) return true;
233   if( this->includes_vcenter( re ) && re.includes_vcenter( *this ) )
234     return this->h_precedes( re );
235   return false;
236   }
237 
238 
distance(const Rectangle & re) const239 int Rectangle::distance( const Rectangle & re ) const
240   { return hypoti( h_distance( re ), v_distance( re ) ); }
241 
242 
distance(const int row,const int col) const243 int Rectangle::distance( const int row, const int col ) const
244   { return hypoti( h_distance( col ), v_distance( row ) ); }
245 
246 
h_distance(const Rectangle & re) const247 int Rectangle::h_distance( const Rectangle & re ) const
248   {
249   if( re.right_ <= left_ ) return left_ - re.right_;
250   if( re.left_ >= right_ ) return re.left_ - right_;
251   return 0;
252   }
253 
h_distance(const int col) const254 int Rectangle::h_distance( const int col ) const
255   {
256   if( col <= left_ ) return left_ - col;
257   if( col >= right_ ) return col - right_;
258   return 0;
259   }
260 
v_distance(const Rectangle & re) const261 int Rectangle::v_distance( const Rectangle & re ) const
262   {
263   if( re.bottom_ <= top_ ) return top_ - re.bottom_;
264   if( re.top_ >= bottom_ ) return re.top_ - bottom_;
265   return 0;
266   }
267 
v_distance(const int row) const268 int Rectangle::v_distance( const int row ) const
269   {
270   if( row <= top_ ) return top_ - row;
271   if( row >= bottom_ ) return row - bottom_;
272   return 0;
273   }
274 
275 
hypoti(const int c1,const int c2)276 int Rectangle::hypoti( const int c1, const int c2 )
277   {
278   long long temp = c1; temp *= temp;
279   long long target = c2; target *= target; target += temp;
280   int lower = std::max( std::abs( c1 ), std::abs( c2 ) );
281   int upper = std::abs( c1 ) + std::abs( c2 );
282   while( upper - lower > 1 )
283     {
284     int m = ( lower + upper ) / 2;
285     temp = m; temp *= temp;
286     if( temp < target ) lower = m; else upper = m;
287     }
288   temp = lower; temp *= temp; target *= 2; target -= temp;
289   temp = upper; temp *= temp;
290   if( target < temp ) return lower;
291   else return upper;
292   }
293