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