Leptonica  1.83.1
Image processing and image analysis suite
boxfunc1.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
82 #ifdef HAVE_CONFIG_H
83 #include <config_auto.h>
84 #endif /* HAVE_CONFIG_H */
85 
86 #include "allheaders.h"
87 #include "pix_internal.h"
88 
89 static l_int32 boxHasOverlapInXorY(l_int32 c1, l_int32 s1, l_int32 c2,
90  l_int32 s2);
91 static l_int32 boxGetDistanceInXorY(l_int32 c1, l_int32 s1, l_int32 c2,
92  l_int32 s2);
93 
94 
95 /*---------------------------------------------------------------------*
96  * Box geometry *
97  *---------------------------------------------------------------------*/
106 l_ok
108  BOX *box2,
109  l_int32 *presult)
110 {
111 l_int32 x1, y1, w1, h1, x2, y2, w2, h2, valid1, valid2;
112 
113  if (!presult)
114  return ERROR_INT("&result not defined", __func__, 1);
115  *presult = 0;
116  if (!box1 || !box2)
117  return ERROR_INT("boxes not both defined", __func__, 1);
118  boxIsValid(box1, &valid1);
119  boxIsValid(box2, &valid2);
120  if (!valid1 || !valid2)
121  return ERROR_INT("boxes not both valid", __func__, 1);
122 
123  boxGetGeometry(box1, &x1, &y1, &w1, &h1);
124  boxGetGeometry(box2, &x2, &y2, &w2, &h2);
125  if (x1 <= x2 && y1 <= y2 && (x1 + w1 >= x2 + w2) && (y1 + h1 >= y2 + h2))
126  *presult = 1;
127  return 0;
128 }
129 
130 
139 l_ok
141  BOX *box2,
142  l_int32 *presult)
143 {
144 l_int32 l1, l2, r1, r2, t1, t2, b1, b2, w1, h1, w2, h2, valid1, valid2;
145 
146  if (!presult)
147  return ERROR_INT("&result not defined", __func__, 1);
148  *presult = 0;
149  if (!box1 || !box2)
150  return ERROR_INT("boxes not both defined", __func__, 1);
151  boxIsValid(box1, &valid1);
152  boxIsValid(box2, &valid2);
153  if (!valid1 || !valid2)
154  return ERROR_INT("boxes not both valid", __func__, 1);
155 
156  boxGetGeometry(box1, &l1, &t1, &w1, &h1);
157  boxGetGeometry(box2, &l2, &t2, &w2, &h2);
158  r1 = l1 + w1 - 1;
159  r2 = l2 + w2 - 1;
160  b1 = t1 + h1 - 1;
161  b2 = t2 + h2 - 1;
162  if (b2 < t1 || b1 < t2 || r1 < l2 || r2 < l1)
163  *presult = 0;
164  else
165  *presult = 1;
166  return 0;
167 }
168 
169 
184 BOXA *
186  BOX *box)
187 {
188 l_int32 i, n, val, valid;
189 BOX *box1;
190 BOXA *boxad;
191 
192  if (!boxas)
193  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
194  if (!box)
195  return (BOXA *)ERROR_PTR("box not defined", __func__, NULL);
196  n = boxaGetCount(boxas);
197  boxIsValid(box, &valid);
198  if (n == 0 || !valid)
199  return boxaCreate(1); /* empty */
200 
201  boxad = boxaCreate(0);
202  for (i = 0; i < n; i++) {
203  if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
204  continue;
205  boxContains(box, box1, &val);
206  if (val == 1)
207  boxaAddBox(boxad, box1, L_COPY);
208  boxDestroy(&box1); /* destroy the clone */
209  }
210 
211  return boxad;
212 }
213 
214 
228 l_ok
230  BOX *box,
231  l_int32 *pcount)
232 {
233 l_int32 i, n, val, valid;
234 BOX *box1;
235 
236  if (!pcount)
237  return ERROR_INT("&count not defined", __func__, 1);
238  *pcount = 0;
239  if (!boxa)
240  return ERROR_INT("boxa not defined", __func__, 1);
241  if (!box)
242  return ERROR_INT("box not defined", __func__, 1);
243  n = boxaGetCount(boxa);
244  boxIsValid(box, &valid);
245  if (n == 0 || !valid)
246  return 0;
247 
248  for (i = 0; i < n; i++) {
249  if ((box1 = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
250  continue;
251  boxContains(box, box1, &val);
252  if (val == 1)
253  (*pcount)++;
254  boxDestroy(&box1);
255  }
256  return 0;
257 }
258 
259 
268 l_ok
270  BOXA *boxa2,
271  l_int32 *pcontained)
272 {
273 l_int32 i, j, n1, n2, cont, result;
274 BOX *box1, *box2;
275 
276  if (!pcontained)
277  return ERROR_INT("&contained not defined", __func__, 1);
278  *pcontained = 0;
279  if (!boxa1 || !boxa2)
280  return ERROR_INT("boxa1 and boxa2 not both defined", __func__, 1);
281 
282  n1 = boxaGetCount(boxa1);
283  n2 = boxaGetCount(boxa2);
284  for (i = 0; i < n2; i++) {
285  if ((box2 = boxaGetValidBox(boxa2, i, L_CLONE)) == NULL)
286  continue;
287  cont = 0;
288  for (j = 0; j < n1; j++) {
289  if ((box1 = boxaGetValidBox(boxa1, j, L_CLONE)) == NULL)
290  continue;
291  boxContains(box1, box2, &result);
292  boxDestroy(&box1);
293  if (result) {
294  cont = 1;
295  break;
296  }
297  }
298  boxDestroy(&box2);
299  if (!cont) return 0;
300  }
301 
302  *pcontained = 1;
303  return 0;
304 }
305 
306 
321 BOXA *
323  BOX *box)
324 {
325 l_int32 i, n, val, valid;
326 BOX *box1;
327 BOXA *boxad;
328 
329  if (!boxas)
330  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
331  if (!box)
332  return (BOXA *)ERROR_PTR("box not defined", __func__, NULL);
333  n = boxaGetCount(boxas);
334  boxIsValid(box, &valid);
335  if (n == 0 || !valid)
336  return boxaCreate(1); /* empty */
337 
338  boxad = boxaCreate(0);
339  for (i = 0; i < n; i++) {
340  if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
341  continue;
342  boxIntersects(box, box1, &val);
343  if (val == 1)
344  boxaAddBox(boxad, box1, L_COPY);
345  boxDestroy(&box1); /* destroy the clone */
346  }
347 
348  return boxad;
349 }
350 
351 
360 l_ok
362  BOX *box,
363  l_int32 *pcount)
364 {
365 l_int32 i, n, val, valid;
366 BOX *box1;
367 
368  if (!pcount)
369  return ERROR_INT("&count not defined", __func__, 1);
370  *pcount = 0;
371  if (!boxa)
372  return ERROR_INT("boxa not defined", __func__, 1);
373  if (!box)
374  return ERROR_INT("box not defined", __func__, 1);
375  n = boxaGetCount(boxa);
376  boxIsValid(box, &valid);
377  if (n == 0 || !valid)
378  return 0;
379 
380  for (i = 0; i < n; i++) {
381  if ((box1 = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
382  continue;
383  boxIntersects(box, box1, &val);
384  if (val == 1)
385  (*pcount)++;
386  boxDestroy(&box1);
387  }
388  return 0;
389 }
390 
391 
405 BOXA *
407  BOX *box)
408 {
409 l_int32 i, n, valid;
410 BOX *box1, *boxo;
411 BOXA *boxad;
412 
413  if (!boxas)
414  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
415  if (!box)
416  return (BOXA *)ERROR_PTR("box not defined", __func__, NULL);
417  n = boxaGetCount(boxas);
418  boxIsValid(box, &valid);
419  if (n == 0 || !valid)
420  return boxaCreate(1); /* empty */
421 
422  boxad = boxaCreate(0);
423  for (i = 0; i < n; i++) {
424  if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
425  continue;
426  if ((boxo = boxOverlapRegion(box, box1)) != NULL)
427  boxaAddBox(boxad, boxo, L_INSERT);
428  boxDestroy(&box1);
429  }
430 
431  return boxad;
432 }
433 
434 
462 BOXA *
464  PIXA *pixadb)
465 {
466 l_int32 i, j, w, h, n1, n2, overlap, niters;
467 BOX *box1, *box2, *box3;
468 BOXA *boxa1, *boxa2;
469 PIX *pix1;
470 
471  if (!boxas)
472  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
473 
474  if (pixadb) boxaGetExtent(boxas, &w, &h, NULL);
475 
476  boxa1 = boxaCopy(boxas, L_COPY);
477  n1 = boxaGetCount(boxa1);
478  niters = 0;
479  while (1) { /* loop until no change from previous iteration */
480  niters++;
481  if (pixadb) {
482  pix1 = pixCreate(w + 5, h + 5, 32);
483  pixSetAll(pix1);
484  pixRenderBoxaArb(pix1, boxa1, 2, 255, 0, 0);
485  pixaAddPix(pixadb, pix1, L_COPY);
486  }
487 
488  /* Combine overlaps for this iteration */
489  for (i = 0; i < n1; i++) {
490  if ((box1 = boxaGetValidBox(boxa1, i, L_COPY)) == NULL)
491  continue;
492  for (j = i + 1; j < n1; j++) {
493  if ((box2 = boxaGetValidBox(boxa1, j, L_COPY)) == NULL)
494  continue;
495  boxIntersects(box1, box2, &overlap);
496  if (overlap) {
497  box3 = boxBoundingRegion(box1, box2);
498  boxaReplaceBox(boxa1, i, box3);
499  boxaReplaceBox(boxa1, j, boxCreate(0, 0, 0, 0));
500  boxDestroy(&box1);
501  box1 = boxCopy(box3);
502  }
503  boxDestroy(&box2);
504  }
505  boxDestroy(&box1);
506  }
507  boxa2 = boxaSaveValid(boxa1, L_COPY);
508  n2 = boxaGetCount(boxa2);
509  boxaDestroy(&boxa1);
510  boxa1 = boxa2;
511  if (n1 == n2) {
512  if (pixadb) pixDestroy(&pix1);
513  break;
514  }
515  n1 = n2;
516  if (pixadb) {
517  pixRenderBoxaArb(pix1, boxa1, 2, 0, 255, 0);
518  pixaAddPix(pixadb, pix1, L_INSERT);
519  }
520  }
521 
522  if (pixadb)
523  L_INFO("number of iterations: %d\n", __func__, niters);
524  return boxa1;
525 }
526 
527 
554 l_ok
556  BOXA *boxas2,
557  BOXA **pboxad1,
558  BOXA **pboxad2,
559  PIXA *pixadb)
560 {
561 l_int32 i, j, w, h, w2, h2, n1, n2, n1i, n2i, niters;
562 l_int32 overlap, bigger, area1, area2;
563 BOX *box1, *box2, *box3;
564 BOXA *boxa1, *boxa2, *boxac1, *boxac2;
565 PIX *pix1;
566 
567  if (pboxad1) *pboxad1 = NULL;
568  if (pboxad2) *pboxad2 = NULL;
569  if (!boxas1 || !boxas2)
570  return ERROR_INT("boxas1 and boxas2 not both defined", __func__, 1);
571  if (!pboxad1 || !pboxad2)
572  return ERROR_INT("&boxad1 and &boxad2 not both defined", __func__, 1);
573 
574  if (pixadb) {
575  boxaGetExtent(boxas1, &w, &h, NULL);
576  boxaGetExtent(boxas2, &w2, &h2, NULL);
577  w = L_MAX(w, w2);
578  h = L_MAX(h, w2);
579  }
580 
581  /* Let the boxa with the largest area have first crack at the other */
582  boxaGetArea(boxas1, &area1);
583  boxaGetArea(boxas2, &area2);
584  if (area1 >= area2) {
585  boxac1 = boxaCopy(boxas1, L_COPY);
586  boxac2 = boxaCopy(boxas2, L_COPY);
587  } else {
588  boxac1 = boxaCopy(boxas2, L_COPY);
589  boxac2 = boxaCopy(boxas1, L_COPY);
590  }
591 
592  n1i = boxaGetCount(boxac1);
593  n2i = boxaGetCount(boxac2);
594  niters = 0;
595  while (1) {
596  niters++;
597  if (pixadb) {
598  pix1 = pixCreate(w + 5, h + 5, 32);
599  pixSetAll(pix1);
600  pixRenderBoxaArb(pix1, boxac1, 2, 255, 0, 0);
601  pixRenderBoxaArb(pix1, boxac2, 2, 0, 255, 0);
602  pixaAddPix(pixadb, pix1, L_INSERT);
603  }
604 
605  /* First combine boxes in each set */
606  boxa1 = boxaCombineOverlaps(boxac1, NULL);
607  boxa2 = boxaCombineOverlaps(boxac2, NULL);
608 
609  /* Now combine boxes between sets */
610  n1 = boxaGetCount(boxa1);
611  n2 = boxaGetCount(boxa2);
612  for (i = 0; i < n1; i++) { /* 1 eats 2 */
613  if ((box1 = boxaGetValidBox(boxa1, i, L_COPY)) == NULL)
614  continue;
615  for (j = 0; j < n2; j++) {
616  if ((box2 = boxaGetValidBox(boxa2, j, L_COPY)) == NULL)
617  continue;
618  boxIntersects(box1, box2, &overlap);
619  boxCompareSize(box1, box2, L_SORT_BY_AREA, &bigger);
620  if (overlap && (bigger == 1)) {
621  box3 = boxBoundingRegion(box1, box2);
622  boxaReplaceBox(boxa1, i, box3);
623  boxaReplaceBox(boxa2, j, boxCreate(0, 0, 0, 0));
624  boxDestroy(&box1);
625  box1 = boxCopy(box3);
626  }
627  boxDestroy(&box2);
628  }
629  boxDestroy(&box1);
630  }
631  for (i = 0; i < n2; i++) { /* 2 eats 1 */
632  if ((box2 = boxaGetValidBox(boxa2, i, L_COPY)) == NULL)
633  continue;
634  for (j = 0; j < n1; j++) {
635  if ((box1 = boxaGetValidBox(boxa1, j, L_COPY)) == NULL)
636  continue;
637  boxIntersects(box1, box2, &overlap);
638  boxCompareSize(box2, box1, L_SORT_BY_AREA, &bigger);
639  if (overlap && (bigger == 1)) {
640  box3 = boxBoundingRegion(box1, box2);
641  boxaReplaceBox(boxa2, i, box3);
642  boxaReplaceBox(boxa1, j, boxCreate(0, 0, 0, 0));
643  boxDestroy(&box2);
644  box2 = boxCopy(box3);
645  }
646  boxDestroy(&box1);
647  }
648  boxDestroy(&box2);
649  }
650  boxaDestroy(&boxac1);
651  boxaDestroy(&boxac2);
652  boxac1 = boxaSaveValid(boxa1, L_COPY); /* remove invalid boxes */
653  boxac2 = boxaSaveValid(boxa2, L_COPY);
654  boxaDestroy(&boxa1);
655  boxaDestroy(&boxa2);
656  n1 = boxaGetCount(boxac1);
657  n2 = boxaGetCount(boxac2);
658  if (n1 == n1i && n2 == n2i) break;
659  n1i = n1;
660  n2i = n2;
661  if (pixadb) {
662  pix1 = pixCreate(w + 5, h + 5, 32);
663  pixSetAll(pix1);
664  pixRenderBoxaArb(pix1, boxac1, 2, 255, 0, 0);
665  pixRenderBoxaArb(pix1, boxac2, 2, 0, 255, 0);
666  pixaAddPix(pixadb, pix1, L_INSERT);
667  }
668  }
669 
670  if (pixadb)
671  L_INFO("number of iterations: %d\n", __func__, niters);
672  *pboxad1 = boxac1;
673  *pboxad2 = boxac2;
674  return 0;
675 }
676 
677 
690 BOX *
692  BOX *box2)
693 {
694 l_int32 l1, l2, r1, r2, t1, t2, b1, b2, w1, h1, w2, h2, ld, td, rd, bd;
695 l_int32 valid1, valid2;
696 
697  if (!box1 || !box2)
698  return (BOX *)ERROR_PTR("boxes not both defined", __func__, NULL);
699  boxIsValid(box1, &valid1);
700  boxIsValid(box2, &valid2);
701  if (!valid1 || !valid2) {
702  L_WARNING("at least one box is invalid\n", __func__);
703  return NULL;
704  }
705 
706  boxGetGeometry(box1, &l1, &t1, &w1, &h1);
707  boxGetGeometry(box2, &l2, &t2, &w2, &h2);
708  r1 = l1 + w1 - 1;
709  r2 = l2 + w2 - 1;
710  b1 = t1 + h1 - 1;
711  b2 = t2 + h2 - 1;
712  if (b2 < t1 || b1 < t2 || r1 < l2 || r2 < l1)
713  return NULL;
714 
715  ld = L_MAX(l1, l2);
716  td = L_MAX(t1, t2);
717  rd = L_MIN(r1, r2);
718  bd = L_MIN(b1, b2);
719  return boxCreate(ld, td, rd - ld + 1, bd - td + 1);
720 }
721 
722 
738 BOX *
740  BOX *box2)
741 {
742 l_int32 l1, l2, r1, r2, t1, t2, b1, b2, w1, h1, w2, h2, ld, td, rd, bd;
743 l_int32 valid1, valid2;
744 
745  if (!box1 || !box2)
746  return (BOX *)ERROR_PTR("boxes not both defined", __func__, NULL);
747  boxIsValid(box1, &valid1);
748  boxIsValid(box2, &valid2);
749  if (!valid1 && !valid2) {
750  L_WARNING("both boxes are invalid\n", __func__);
751  return boxCreate(0, 0, 0, 0);
752  }
753  if (valid1 && !valid2)
754  return boxCopy(box1);
755  if (!valid1 && valid2)
756  return boxCopy(box2);
757 
758  boxGetGeometry(box1, &l1, &t1, &w1, &h1);
759  boxGetGeometry(box2, &l2, &t2, &w2, &h2);
760  r1 = l1 + w1 - 1;
761  r2 = l2 + w2 - 1;
762  b1 = t1 + h1 - 1;
763  b2 = t2 + h2 - 1;
764  ld = L_MIN(l1, l2);
765  td = L_MIN(t1, t2);
766  rd = L_MAX(r1, r2);
767  bd = L_MAX(b1, b2);
768  return boxCreate(ld, td, rd - ld + 1, bd - td + 1);
769 }
770 
771 
786 l_ok
788  BOX *box2,
789  l_float32 *pfract)
790 {
791 l_int32 w2, h2, w, h, valid1, valid2;
792 BOX *boxo;
793 
794  if (!pfract)
795  return ERROR_INT("&fract not defined", __func__, 1);
796  *pfract = 0.0;
797  if (!box1 || !box2)
798  return ERROR_INT("boxes not both defined", __func__, 1);
799  boxIsValid(box1, &valid1);
800  boxIsValid(box2, &valid2);
801  if (!valid1 || !valid2) {
802  L_WARNING("boxes not both valid\n", __func__);
803  return 0;
804  }
805 
806  if ((boxo = boxOverlapRegion(box1, box2)) == NULL) /* no overlap */
807  return 0;
808 
809  boxGetGeometry(box2, NULL, NULL, &w2, &h2);
810  boxGetGeometry(boxo, NULL, NULL, &w, &h);
811  *pfract = (l_float32)(w * h) / (l_float32)(w2 * h2);
812  boxDestroy(&boxo);
813  return 0;
814 }
815 
816 
824 l_ok
826  BOX *box2,
827  l_int32 *parea)
828 {
829 l_int32 w, h, valid1, valid2;
830 BOX *box;
831 
832  if (!parea)
833  return ERROR_INT("&area not defined", __func__, 1);
834  *parea = 0;
835  if (!box1 || !box2)
836  return ERROR_INT("boxes not both defined", __func__, 1);
837  boxIsValid(box1, &valid1);
838  boxIsValid(box2, &valid2);
839  if (!valid1 || !valid2)
840  return ERROR_INT("boxes not both valid", __func__, 1);
841 
842  if ((box = boxOverlapRegion(box1, box2)) == NULL) /* no overlap */
843  return 0;
844 
845  boxGetGeometry(box, NULL, NULL, &w, &h);
846  *parea = w * h;
847  boxDestroy(&box);
848  return 0;
849 }
850 
851 
886 BOXA *
888  l_int32 op,
889  l_int32 range,
890  l_float32 min_overlap,
891  l_float32 max_ratio,
892  NUMA **pnamap)
893 {
894 l_int32 i, j, n, w, h, area1, area2, val;
895 l_int32 overlap_area;
896 l_float32 overlap_ratio, area_ratio;
897 BOX *box1, *box2, *box3;
898 BOXA *boxat, *boxad;
899 NUMA *namap;
900 
901  if (pnamap) *pnamap = NULL;
902  if (!boxas)
903  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
904  if (op != L_COMBINE && op != L_REMOVE_SMALL)
905  return (BOXA *)ERROR_PTR("invalid op", __func__, NULL);
906 
907  n = boxaGetCount(boxas);
908  if (n == 0)
909  return boxaCreate(1); /* empty */
910  if (range == 0) {
911  L_WARNING("range is 0\n", __func__);
912  return boxaCopy(boxas, L_COPY);
913  }
914 
915  /* Identify smaller boxes in overlap pairs, and mark to eliminate. */
916  namap = numaMakeConstant(-1, n);
917  for (i = 0; i < n; i++) {
918  if ((box1 = boxaGetValidBox(boxas, i, L_CLONE)) == NULL)
919  continue;
920  boxGetGeometry(box1, NULL, NULL, &w, &h);
921  area1 = w * h;
922  if (area1 == 0) {
923  boxDestroy(&box1);
924  continue;
925  }
926  for (j = i + 1; j < i + 1 + range && j < n; j++) {
927  if ((box2 = boxaGetValidBox(boxas, j, L_CLONE)) == NULL)
928  continue;
929  boxOverlapArea(box1, box2, &overlap_area);
930  if (overlap_area > 0) {
931  boxGetGeometry(box2, NULL, NULL, &w, &h);
932  area2 = w * h;
933  if (area2 == 0) {
934  /* do nothing */
935  } else if (area1 >= area2) {
936  overlap_ratio = (l_float32)overlap_area / (l_float32)area2;
937  area_ratio = (l_float32)area2 / (l_float32)area1;
938  if (overlap_ratio >= min_overlap &&
939  area_ratio <= max_ratio) {
940  numaSetValue(namap, j, i);
941  }
942  } else {
943  overlap_ratio = (l_float32)overlap_area / (l_float32)area1;
944  area_ratio = (l_float32)area1 / (l_float32)area2;
945  if (overlap_ratio >= min_overlap &&
946  area_ratio <= max_ratio) {
947  numaSetValue(namap, i, j);
948  }
949  }
950  }
951  boxDestroy(&box2);
952  }
953  boxDestroy(&box1);
954  }
955 
956  boxat = boxaCopy(boxas, L_COPY);
957  if (op == L_COMBINE) {
958  /* Resize the larger of the pair to the bounding region */
959  for (i = 0; i < n; i++) {
960  numaGetIValue(namap, i, &val);
961  if (val >= 0) {
962  box1 = boxaGetBox(boxas, i, L_CLONE); /* smaller */
963  box2 = boxaGetBox(boxas, val, L_CLONE); /* larger */
964  box3 = boxBoundingRegion(box1, box2);
965  boxaReplaceBox(boxat, val, box3);
966  boxDestroy(&box1);
967  boxDestroy(&box2);
968  }
969  }
970  }
971 
972  /* Remove the smaller of the pairs */
973  boxad = boxaCreate(n);
974  for (i = 0; i < n; i++) {
975  numaGetIValue(namap, i, &val);
976  if (val == -1) {
977  box1 = boxaGetBox(boxat, i, L_COPY);
978  boxaAddBox(boxad, box1, L_INSERT);
979  }
980  }
981  boxaDestroy(&boxat);
982  if (pnamap)
983  *pnamap = namap;
984  else
985  numaDestroy(&namap);
986  return boxad;
987 }
988 
989 
1014 l_ok
1016  BOX *box2,
1017  l_int32 *ph_ovl,
1018  l_int32 *pv_ovl)
1019 {
1020 l_int32 l1, t1, w1, h1, r1, b1, l2, t2, w2, h2, r2, b2, valid1, valid2;
1021 
1022  if (!ph_ovl && !pv_ovl)
1023  return ERROR_INT("nothing to do", __func__, 1);
1024  if (ph_ovl) *ph_ovl = 0;
1025  if (pv_ovl) *pv_ovl = 0;
1026  if (!box1 || !box2)
1027  return ERROR_INT("boxes not both defined", __func__, 1);
1028  boxIsValid(box1, &valid1);
1029  boxIsValid(box2, &valid2);
1030  if (!valid1 || !valid2)
1031  return ERROR_INT("boxes not both valid", __func__, 1);
1032 
1033  if (ph_ovl) {
1034  boxGetGeometry(box1, &l1, NULL, &w1, NULL);
1035  boxGetGeometry(box2, &l2, NULL, &w2, NULL);
1036  r1 = l1 + w1; /* 1 pixel to the right of box 1 */
1037  r2 = l2 + w2;
1038  if (l2 >= l1)
1039  *ph_ovl = r1 - l2;
1040  else
1041  *ph_ovl = r2 - l1;
1042  }
1043  if (pv_ovl) {
1044  boxGetGeometry(box1, NULL, &t1, NULL, &h1);
1045  boxGetGeometry(box2, NULL, &t2, NULL, &h2);
1046  b1 = t1 + h1; /* 1 pixel below box 1 */
1047  b2 = t2 + h2;
1048  if (t2 >= t1)
1049  *pv_ovl = b1 - t2;
1050  else
1051  *pv_ovl = b2 - t1;
1052  }
1053  return 0;
1054 }
1055 
1056 
1085 l_ok
1087  BOX *box2,
1088  l_int32 *ph_sep,
1089  l_int32 *pv_sep)
1090 {
1091 l_int32 h_ovl, v_ovl, valid1, valid2;
1092 
1093  if (ph_sep) *ph_sep = 0;
1094  if (pv_sep) *pv_sep = 0;
1095  if (!ph_sep || !pv_sep)
1096  return ERROR_INT("&h_sep and &v_sep not both defined", __func__, 1);
1097  if (!box1 || !box2)
1098  return ERROR_INT("boxes not both defined", __func__, 1);
1099  boxIsValid(box1, &valid1);
1100  boxIsValid(box2, &valid2);
1101  if (!valid1 || !valid2)
1102  return ERROR_INT("boxes not both valid", __func__, 1);
1103 
1104  boxOverlapDistance(box1, box2, &h_ovl, &v_ovl);
1105  if (h_ovl <= 0)
1106  *ph_sep = -h_ovl + 1;
1107  if (v_ovl <= 0)
1108  *pv_sep = -v_ovl + 1;
1109  return 0;
1110 }
1111 
1112 
1128 l_ok
1130  BOX *box2,
1131  l_int32 type,
1132  l_int32 *prel)
1133 {
1134 l_int32 w1, h1, w2, h2, size1, size2, valid1, valid2;
1135 
1136  if (!prel)
1137  return ERROR_INT("&rel not defined", __func__, 1);
1138  *prel = 0;
1139  if (!box1 || !box2)
1140  return ERROR_INT("boxes not both defined", __func__, 1);
1141  boxIsValid(box1, &valid1);
1142  boxIsValid(box2, &valid2);
1143  if (!valid1 || !valid2)
1144  return ERROR_INT("boxes not both valid", __func__, 1);
1145  if (type != L_SORT_BY_WIDTH && type != L_SORT_BY_HEIGHT &&
1146  type != L_SORT_BY_MAX_DIMENSION && type != L_SORT_BY_PERIMETER &&
1147  type != L_SORT_BY_AREA)
1148  return ERROR_INT("invalid compare type", __func__, 1);
1149 
1150  boxGetGeometry(box1, NULL, NULL, &w1, &h1);
1151  boxGetGeometry(box2, NULL, NULL, &w2, &h2);
1152  if (type == L_SORT_BY_WIDTH) {
1153  *prel = (w1 > w2) ? 1 : ((w1 == w2) ? 0 : -1);
1154  } else if (type == L_SORT_BY_HEIGHT) {
1155  *prel = (h1 > h2) ? 1 : ((h1 == h2) ? 0 : -1);
1156  } else if (type == L_SORT_BY_MAX_DIMENSION) {
1157  size1 = L_MAX(w1, h1);
1158  size2 = L_MAX(w2, h2);
1159  *prel = (size1 > size2) ? 1 : ((size1 == size2) ? 0 : -1);
1160  } else if (type == L_SORT_BY_PERIMETER) {
1161  size1 = w1 + h1;
1162  size2 = w2 + h2;
1163  *prel = (size1 > size2) ? 1 : ((size1 == size2) ? 0 : -1);
1164  } else if (type == L_SORT_BY_AREA) {
1165  size1 = w1 * h1;
1166  size2 = w2 * h2;
1167  *prel = (size1 > size2) ? 1 : ((size1 == size2) ? 0 : -1);
1168  }
1169  return 0;
1170 }
1171 
1172 
1181 l_ok
1183  l_float32 x,
1184  l_float32 y,
1185  l_int32 *pcontains)
1186 {
1187 l_int32 bx, by, bw, bh;
1188 
1189  if (!pcontains)
1190  return ERROR_INT("&contains not defined", __func__, 1);
1191  *pcontains = 0;
1192  if (!box)
1193  return ERROR_INT("&box not defined", __func__, 1);
1194  boxGetGeometry(box, &bx, &by, &bw, &bh);
1195  if (x >= bx && x < bx + bw && y >= by && y < by + bh)
1196  *pcontains = 1;
1197  return 0;
1198 }
1199 
1200 
1214 BOX *
1216  l_int32 x,
1217  l_int32 y)
1218 {
1219 l_int32 i, n, minindex;
1220 l_float32 delx, dely, dist, mindist, cx, cy;
1221 BOX *box;
1222 
1223  if (!boxa)
1224  return (BOX *)ERROR_PTR("boxa not defined", __func__, NULL);
1225  if ((n = boxaGetCount(boxa)) == 0)
1226  return (BOX *)ERROR_PTR("n = 0", __func__, NULL);
1227 
1228  mindist = 1000000000.;
1229  minindex = 0;
1230  for (i = 0; i < n; i++) {
1231  if ((box = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
1232  continue;
1233  boxGetCenter(box, &cx, &cy);
1234  delx = (l_float32)(cx - x);
1235  dely = (l_float32)(cy - y);
1236  dist = delx * delx + dely * dely;
1237  if (dist < mindist) {
1238  minindex = i;
1239  mindist = dist;
1240  }
1241  boxDestroy(&box);
1242  }
1243 
1244  return boxaGetBox(boxa, minindex, L_COPY);
1245 }
1246 
1247 
1265 BOX *
1267  l_int32 x,
1268  l_int32 y)
1269 {
1270 l_int32 i, n, minindex;
1271 l_float32 dist, mindist, cx, cy;
1272 BOX *box;
1273 
1274  if (!boxa)
1275  return (BOX *)ERROR_PTR("boxa not defined", __func__, NULL);
1276  if ((n = boxaGetCount(boxa)) == 0)
1277  return (BOX *)ERROR_PTR("n = 0", __func__, NULL);
1278  if (y >= 0 && x >= 0)
1279  return (BOX *)ERROR_PTR("either x or y must be < 0", __func__, NULL);
1280  if (y < 0 && x < 0)
1281  return (BOX *)ERROR_PTR("either x or y must be >= 0", __func__, NULL);
1282 
1283  mindist = 1000000000.;
1284  minindex = 0;
1285  for (i = 0; i < n; i++) {
1286  if ((box = boxaGetValidBox(boxa, i, L_CLONE)) == NULL)
1287  continue;
1288  boxGetCenter(box, &cx, &cy);
1289  if (x >= 0)
1290  dist = L_ABS(cx - (l_float32)x);
1291  else /* y >= 0 */
1292  dist = L_ABS(cy - (l_float32)y);
1293  if (dist < mindist) {
1294  minindex = i;
1295  mindist = dist;
1296  }
1297  boxDestroy(&box);
1298  }
1299 
1300  return boxaGetBox(boxa, minindex, L_COPY);
1301 }
1302 
1303 
1321 l_ok
1323  l_int32 dist_select,
1324  l_int32 range,
1325  NUMAA **pnaaindex,
1326  NUMAA **pnaadist)
1327 {
1328 l_int32 i, n, index, dist;
1329 NUMA *nai, *nad;
1330 NUMAA *naai, *naad;
1331 
1332  if (pnaaindex) *pnaaindex = NULL;
1333  if (pnaadist) *pnaadist = NULL;
1334  if (!pnaaindex)
1335  return ERROR_INT("&naaindex not defined", __func__, 1);
1336  if (!pnaadist)
1337  return ERROR_INT("&naadist not defined", __func__, 1);
1338  if (!boxa)
1339  return ERROR_INT("boxa not defined", __func__, 1);
1340 
1341  n = boxaGetCount(boxa);
1342  naai = numaaCreate(n);
1343  naad = numaaCreate(n);
1344  *pnaaindex = naai;
1345  *pnaadist = naad;
1346  for (i = 0; i < n; i++) {
1347  nai = numaCreate(4);
1348  nad = numaCreate(4);
1349  boxaGetNearestByDirection(boxa, i, L_FROM_LEFT, dist_select,
1350  range, &index, &dist);
1351  numaAddNumber(nai, index);
1352  numaAddNumber(nad, dist);
1353  boxaGetNearestByDirection(boxa, i, L_FROM_RIGHT, dist_select,
1354  range, &index, &dist);
1355  numaAddNumber(nai, index);
1356  numaAddNumber(nad, dist);
1357  boxaGetNearestByDirection(boxa, i, L_FROM_TOP, dist_select,
1358  range, &index, &dist);
1359  numaAddNumber(nai, index);
1360  numaAddNumber(nad, dist);
1361  boxaGetNearestByDirection(boxa, i, L_FROM_BOT, dist_select,
1362  range, &index, &dist);
1363  numaAddNumber(nai, index);
1364  numaAddNumber(nad, dist);
1365  numaaAddNuma(naai, nai, L_INSERT);
1366  numaaAddNuma(naad, nad, L_INSERT);
1367  }
1368  return 0;
1369 }
1370 
1371 
1400 l_ok
1402  l_int32 i,
1403  l_int32 dir,
1404  l_int32 dist_select,
1405  l_int32 range,
1406  l_int32 *pindex,
1407  l_int32 *pdist)
1408 {
1409 l_int32 j, jmin, jmax, n, mindist, dist, index;
1410 l_int32 x, y, w, h, bx, by, bw, bh;
1411 
1412  if (pindex) *pindex = -1;
1413  if (pdist) *pdist = 100000;
1414  if (!pindex)
1415  return ERROR_INT("&index not defined", __func__, 1);
1416  if (!pdist)
1417  return ERROR_INT("&dist not defined", __func__, 1);
1418  if (!boxa)
1419  return ERROR_INT("boxa not defined", __func__, 1);
1420  if (dir != L_FROM_LEFT && dir != L_FROM_RIGHT &&
1421  dir != L_FROM_TOP && dir != L_FROM_BOT)
1422  return ERROR_INT("invalid dir", __func__, 1);
1423  if (dist_select != L_NON_NEGATIVE && dist_select != L_ALL)
1424  return ERROR_INT("invalid dist_select", __func__, 1);
1425  n = boxaGetCount(boxa);
1426  if (i < 0 || i >= n)
1427  return ERROR_INT("invalid box index", __func__, 1);
1428 
1429  jmin = (range <= 0) ? 0 : L_MAX(0, i - range);
1430  jmax = (range <= 0) ? n - 1 : L_MIN(n -1, i + range);
1431  boxaGetBoxGeometry(boxa, i, &x, &y, &w, &h);
1432  mindist = 100000;
1433  index = -1;
1434  if (dir == L_FROM_LEFT || dir == L_FROM_RIGHT) {
1435  for (j = jmin; j <= jmax; j++) {
1436  if (j == i) continue;
1437  boxaGetBoxGeometry(boxa, j, &bx, &by, &bw, &bh);
1438  if ((bx >= x && dir == L_FROM_LEFT) || /* not to the left */
1439  (x >= bx && dir == L_FROM_RIGHT)) /* not to the right */
1440  continue;
1441  if (boxHasOverlapInXorY(y, h, by, bh) == 1) {
1442  dist = boxGetDistanceInXorY(x, w, bx, bw);
1443  if (dist_select == L_NON_NEGATIVE && dist < 0) continue;
1444  if (dist < mindist) {
1445  mindist = dist;
1446  index = j;
1447  }
1448  }
1449  }
1450  } else if (dir == L_FROM_TOP || dir == L_FROM_BOT) {
1451  for (j = jmin; j <= jmax; j++) {
1452  if (j == i) continue;
1453  boxaGetBoxGeometry(boxa, j, &bx, &by, &bw, &bh);
1454  if ((by >= y && dir == L_FROM_TOP) || /* not above */
1455  (y >= by && dir == L_FROM_BOT)) /* not below */
1456  continue;
1457  if (boxHasOverlapInXorY(x, w, bx, bw) == 1) {
1458  dist = boxGetDistanceInXorY(y, h, by, bh);
1459  if (dist_select == L_NON_NEGATIVE && dist < 0) continue;
1460  if (dist < mindist) {
1461  mindist = dist;
1462  index = j;
1463  }
1464  }
1465  }
1466  }
1467  *pindex = index;
1468  *pdist = mindist;
1469  return 0;
1470 }
1471 
1472 
1488 static l_int32
1490  l_int32 s1,
1491  l_int32 c2,
1492  l_int32 s2)
1493 {
1494 l_int32 ovlp;
1495 
1496  if (c1 > c2)
1497  ovlp = c2 + s2 - 1 - c1;
1498  else
1499  ovlp = c1 + s1 - 1 - c2;
1500  return (ovlp < 0) ? 0 : 1;
1501 }
1502 
1503 
1514 static l_int32
1516  l_int32 s1,
1517  l_int32 c2,
1518  l_int32 s2)
1519 {
1520 l_int32 dist;
1521 
1522  if (c1 > c2)
1523  dist = c1 - (c2 + s2 - 1);
1524  else
1525  dist = c2 - (c1 + s1 - 1);
1526  return dist;
1527 }
1528 
1529 
1537 l_ok
1538 boxGetCenter(const BOX *box,
1539  l_float32 *pcx,
1540  l_float32 *pcy)
1541 {
1542 l_int32 x, y, w, h;
1543 
1544  if (pcx) *pcx = 0;
1545  if (pcy) *pcy = 0;
1546  if (!pcx || !pcy)
1547  return ERROR_INT("&cx, &cy not both defined", __func__, 1);
1548  if (!box)
1549  return ERROR_INT("box not defined", __func__, 1);
1550  boxGetGeometry(box, &x, &y, &w, &h);
1551  if (w == 0 || h == 0) return 1;
1552  *pcx = (l_float32)(x + 0.5 * w);
1553  *pcy = (l_float32)(y + 0.5 * h);
1554 
1555  return 0;
1556 }
1557 
1558 
1577 l_ok
1579  l_int32 x,
1580  l_int32 y,
1581  l_float32 slope,
1582  l_int32 *px1,
1583  l_int32 *py1,
1584  l_int32 *px2,
1585  l_int32 *py2,
1586  l_int32 *pn)
1587 {
1588 l_int32 bx, by, bw, bh, xp, yp, xt, yt, i, n;
1589 l_float32 invslope;
1590 PTA *pta;
1591 
1592  if (px1) *px1 = 0;
1593  if (px2) *px2 = 0;
1594  if (py1) *py1 = 0;
1595  if (py2) *py2 = 0;
1596  if (pn) *pn = 0;
1597  if (!px1 || !py1 || !px2 || !py2)
1598  return ERROR_INT("&x1, &y1, &x2, &y2 not all defined", __func__, 1);
1599  if (!pn)
1600  return ERROR_INT("&n not defined", __func__, 1);
1601  if (!box)
1602  return ERROR_INT("box not defined", __func__, 1);
1603  boxGetGeometry(box, &bx, &by, &bw, &bh);
1604  if (bw == 0 || bh == 0) return 1;
1605 
1606  if (slope == 0.0) {
1607  if (y >= by && y < by + bh) {
1608  *py1 = *py2 = y;
1609  *px1 = bx;
1610  *px2 = bx + bw - 1;
1611  }
1612  return 0;
1613  }
1614 
1615  if (slope > 1000000.0) {
1616  if (x >= bx && x < bx + bw) {
1617  *px1 = *px2 = x;
1618  *py1 = by;
1619  *py2 = by + bh - 1;
1620  }
1621  return 0;
1622  }
1623 
1624  /* Intersection with top and bottom lines of box */
1625  pta = ptaCreate(2);
1626  invslope = 1.0 / slope;
1627  xp = (l_int32)(x + invslope * (y - by));
1628  if (xp >= bx && xp < bx + bw)
1629  ptaAddPt(pta, xp, by);
1630  xp = (l_int32)(x + invslope * (y - by - bh + 1));
1631  if (xp >= bx && xp < bx + bw)
1632  ptaAddPt(pta, xp, by + bh - 1);
1633 
1634  /* Intersection with left and right lines of box */
1635  yp = (l_int32)(y + slope * (x - bx));
1636  if (yp >= by && yp < by + bh)
1637  ptaAddPt(pta, bx, yp);
1638  yp = (l_int32)(y + slope * (x - bx - bw + 1));
1639  if (yp >= by && yp < by + bh)
1640  ptaAddPt(pta, bx + bw - 1, yp);
1641 
1642  /* There is a maximum of 2 unique points; remove duplicates. */
1643  n = ptaGetCount(pta);
1644  if (n > 0) {
1645  ptaGetIPt(pta, 0, px1, py1); /* accept the first one */
1646  *pn = 1;
1647  }
1648  for (i = 1; i < n; i++) {
1649  ptaGetIPt(pta, i, &xt, &yt);
1650  if ((*px1 != xt) || (*py1 != yt)) {
1651  *px2 = xt;
1652  *py2 = yt;
1653  *pn = 2;
1654  break;
1655  }
1656  }
1657 
1658  ptaDestroy(&pta);
1659  return 0;
1660 }
1661 
1662 
1678 BOX *
1680  l_int32 wi,
1681  l_int32 hi)
1682 {
1683 BOX *boxd;
1684 
1685  if (!box)
1686  return (BOX *)ERROR_PTR("box not defined", __func__, NULL);
1687  if (box->x >= wi || box->y >= hi ||
1688  box->x + box->w <= 0 || box->y + box->h <= 0)
1689  return (BOX *)ERROR_PTR("box outside rectangle", __func__, NULL);
1690 
1691  boxd = boxCopy(box);
1692  if (boxd->x < 0) {
1693  boxd->w += boxd->x;
1694  boxd->x = 0;
1695  }
1696  if (boxd->y < 0) {
1697  boxd->h += boxd->y;
1698  boxd->y = 0;
1699  }
1700  if (boxd->x + boxd->w > wi)
1701  boxd->w = wi - boxd->x;
1702  if (boxd->y + boxd->h > hi)
1703  boxd->h = hi - boxd->y;
1704  return boxd;
1705 }
1706 
1707 
1733 l_ok
1735  l_int32 w,
1736  l_int32 h,
1737  l_int32 *pxstart,
1738  l_int32 *pystart,
1739  l_int32 *pxend,
1740  l_int32 *pyend,
1741  l_int32 *pbw,
1742  l_int32 *pbh)
1743 {
1744 l_int32 bw, bh;
1745 BOX *boxc;
1746 
1747  if (pxstart) *pxstart = 0;
1748  if (pystart) *pystart = 0;
1749  if (pxend) *pxend = w;
1750  if (pyend) *pyend = h;
1751  if (pbw) *pbw = w;
1752  if (pbh) *pbh = h;
1753  if (!pxstart || !pystart || !pxend || !pyend)
1754  return ERROR_INT("invalid ptr input", __func__, 1);
1755  if (!box) return 0;
1756 
1757  if ((boxc = boxClipToRectangle(box, w, h)) == NULL)
1758  return ERROR_INT("box outside image", __func__, 1);
1759  boxGetGeometry(boxc, pxstart, pystart, &bw, &bh);
1760  boxDestroy(&boxc);
1761 
1762  if (pbw) *pbw = bw;
1763  if (pbh) *pbh = bh;
1764  if (bw == 0 || bh == 0)
1765  return ERROR_INT("invalid clipping box", __func__, 1);
1766  *pxend = *pxstart + bw; /* 1 past the end */
1767  *pyend = *pystart + bh; /* 1 past the end */
1768  return 0;
1769 }
1770 
1771 
1793 BOX *
1795  BOX *boxs,
1796  l_int32 loc,
1797  l_int32 sideflag)
1798 {
1799 l_int32 x, y, w, h;
1800 
1801  if (!boxs)
1802  return (BOX *)ERROR_PTR("boxs not defined", __func__, NULL);
1803  if (!boxd)
1804  boxd = boxCopy(boxs);
1805 
1806  boxGetGeometry(boxs, &x, &y, &w, &h);
1807  if (w == 0 || h == 0)
1808  return boxd;
1809  if (sideflag == L_FROM_LEFT)
1810  boxSetGeometry(boxd, loc, -1, w + x - loc, -1);
1811  else if (sideflag == L_FROM_RIGHT)
1812  boxSetGeometry(boxd, -1, -1, loc - x + 1, -1);
1813  else if (sideflag == L_FROM_TOP)
1814  boxSetGeometry(boxd, -1, loc, -1, h + y - loc);
1815  else if (sideflag == L_FROM_BOT)
1816  boxSetGeometry(boxd, -1, -1, -1, loc - y + 1);
1817  return boxd;
1818 }
1819 
1820 
1837 BOXA *
1839  l_int32 delleft,
1840  l_int32 delright,
1841  l_int32 deltop,
1842  l_int32 delbot)
1843 {
1844 l_int32 n, i, x, y;
1845 BOX *box1, *box2;
1846 BOXA *boxad;
1847 
1848  if (!boxas)
1849  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
1850 
1851  n = boxaGetCount(boxas);
1852  boxad = boxaCreate(n);
1853  for (i = 0; i < n; i++) {
1854  box1 = boxaGetBox(boxas, i, L_COPY);
1855  box2 = boxAdjustSides(NULL, box1, delleft, delright, deltop, delbot);
1856  if (!box2) {
1857  boxGetGeometry(box1, &x, &y, NULL, NULL);
1858  box2 = boxCreate(x, y, 1, 1);
1859  }
1860  boxaAddBox(boxad, box2, L_INSERT);
1861  boxDestroy(&box1);
1862  }
1863 
1864  return boxad;
1865 }
1866 
1867 
1885 l_ok
1887  l_int32 index,
1888  l_int32 delleft,
1889  l_int32 delright,
1890  l_int32 deltop,
1891  l_int32 delbot)
1892 {
1893 BOX *box;
1894 
1895  if (!boxa)
1896  return ERROR_INT("boxa not defined", __func__, 1);
1897 
1898  if ((box = boxaGetBox(boxa, index, L_CLONE)) == NULL)
1899  return ERROR_INT("invalid index", __func__, 1);
1900 
1901  boxAdjustSides(box, box, delleft, delright, deltop, delbot);
1902  boxDestroy(&box); /* the clone */
1903  return 0;
1904 }
1905 
1906 
1931 BOX *
1933  BOX *boxs,
1934  l_int32 delleft,
1935  l_int32 delright,
1936  l_int32 deltop,
1937  l_int32 delbot)
1938 {
1939 l_int32 x, y, w, h, xl, xr, yt, yb, wnew, hnew;
1940 
1941  if (!boxs)
1942  return (BOX *)ERROR_PTR("boxs not defined", __func__, NULL);
1943 
1944  boxGetGeometry(boxs, &x, &y, &w, &h);
1945  xl = L_MAX(0, x + delleft);
1946  yt = L_MAX(0, y + deltop);
1947  xr = x + w + delright; /* one pixel beyond right edge */
1948  yb = y + h + delbot; /* one pixel below bottom edge */
1949  wnew = xr - xl;
1950  hnew = yb - yt;
1951 
1952  if (wnew < 1 || hnew < 1)
1953  return (BOX *)ERROR_PTR("boxd has 0 area", __func__, NULL);
1954  if (!boxd)
1955  return boxCreate(xl, yt, wnew, hnew);
1956 
1957  boxSetGeometry(boxd, xl, yt, wnew, hnew);
1958  return boxd;
1959 }
1960 
1961 
1981 BOXA *
1983  BOXA *boxas,
1984  l_int32 side,
1985  l_int32 val,
1986  l_int32 thresh)
1987 {
1988 l_int32 n, i;
1989 BOX *box;
1990 
1991  if (!boxas)
1992  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
1993  if (boxad && (boxas != boxad))
1994  return (BOXA *)ERROR_PTR("not in-place", __func__, NULL);
1995  if (side != L_SET_LEFT && side != L_SET_RIGHT &&
1996  side != L_SET_TOP && side != L_SET_BOT)
1997  return (BOXA *)ERROR_PTR("invalid side", __func__, NULL);
1998  if (val < 0)
1999  return (BOXA *)ERROR_PTR("val < 0", __func__, NULL);
2000 
2001  if (!boxad)
2002  boxad = boxaCopy(boxas, L_COPY);
2003  n = boxaGetCount(boxad);
2004  for (i = 0; i < n; i++) {
2005  box = boxaGetBox(boxad, i, L_CLONE);
2006  boxSetSide(box, side, val, thresh);
2007  boxDestroy(&box); /* the clone */
2008  }
2009 
2010  return boxad;
2011 }
2012 
2013 
2029 l_ok
2031  l_int32 side,
2032  l_int32 val,
2033  l_int32 thresh)
2034 {
2035 l_int32 x, y, w, h, diff;
2036 
2037  if (!boxs)
2038  return ERROR_INT("box not defined", __func__, 1);
2039  if (side != L_SET_LEFT && side != L_SET_RIGHT &&
2040  side != L_SET_TOP && side != L_SET_BOT)
2041  return ERROR_INT("invalid side", __func__, 1);
2042  if (val < 0)
2043  return ERROR_INT("val < 0", __func__, 1);
2044 
2045  boxGetGeometry(boxs, &x, &y, &w, &h);
2046  if (side == L_SET_LEFT) {
2047  diff = x - val;
2048  if (L_ABS(diff) >= thresh)
2049  boxSetGeometry(boxs, val, y, w + diff, h);
2050  } else if (side == L_SET_RIGHT) {
2051  diff = x + w -1 - val;
2052  if (L_ABS(diff) >= thresh)
2053  boxSetGeometry(boxs, x, y, val - x + 1, h);
2054  } else if (side == L_SET_TOP) {
2055  diff = y - val;
2056  if (L_ABS(diff) >= thresh)
2057  boxSetGeometry(boxs, x, val, w, h + diff);
2058  } else { /* side == L_SET_BOT */
2059  diff = y + h - 1 - val;
2060  if (L_ABS(diff) >= thresh)
2061  boxSetGeometry(boxs, x, y, w, val - y + 1);
2062  }
2063 
2064  return 0;
2065 }
2066 
2067 
2089 BOXA *
2091  BOXA *boxas,
2092  l_int32 sides,
2093  l_int32 target,
2094  l_int32 thresh)
2095 {
2096 l_int32 x, y, w, h, n, i, diff;
2097 BOX *box;
2098 
2099  if (!boxas)
2100  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
2101  if (boxad && (boxas != boxad))
2102  return (BOXA *)ERROR_PTR("not in-place", __func__, NULL);
2103  if (sides != L_ADJUST_LEFT && sides != L_ADJUST_RIGHT &&
2104  sides != L_ADJUST_LEFT_AND_RIGHT)
2105  return (BOXA *)ERROR_PTR("invalid sides", __func__, NULL);
2106  if (target < 1)
2107  return (BOXA *)ERROR_PTR("target < 1", __func__, NULL);
2108 
2109  if (!boxad)
2110  boxad = boxaCopy(boxas, L_COPY);
2111  n = boxaGetCount(boxad);
2112  for (i = 0; i < n; i++) {
2113  if ((box = boxaGetValidBox(boxad, i, L_CLONE)) == NULL)
2114  continue;
2115  boxGetGeometry(box, &x, &y, &w, &h);
2116  diff = w - target;
2117  if (sides == L_ADJUST_LEFT) {
2118  if (L_ABS(diff) >= thresh)
2119  boxSetGeometry(box, L_MAX(0, x + diff), y, target, h);
2120  } else if (sides == L_ADJUST_RIGHT) {
2121  if (L_ABS(diff) >= thresh)
2122  boxSetGeometry(box, x, y, target, h);
2123  } else { /* sides == L_ADJUST_LEFT_AND_RIGHT */
2124  if (L_ABS(diff) >= thresh)
2125  boxSetGeometry(box, L_MAX(0, x + diff/2), y, target, h);
2126  }
2127  boxDestroy(&box);
2128  }
2129 
2130  return boxad;
2131 }
2132 
2133 
2155 BOXA *
2157  BOXA *boxas,
2158  l_int32 sides,
2159  l_int32 target,
2160  l_int32 thresh)
2161 {
2162 l_int32 x, y, w, h, n, i, diff;
2163 BOX *box;
2164 
2165  if (!boxas)
2166  return (BOXA *)ERROR_PTR("boxas not defined", __func__, NULL);
2167  if (boxad && (boxas != boxad))
2168  return (BOXA *)ERROR_PTR("not in-place", __func__, NULL);
2169  if (sides != L_ADJUST_TOP && sides != L_ADJUST_BOT &&
2170  sides != L_ADJUST_TOP_AND_BOT)
2171  return (BOXA *)ERROR_PTR("invalid sides", __func__, NULL);
2172  if (target < 1)
2173  return (BOXA *)ERROR_PTR("target < 1", __func__, NULL);
2174 
2175  if (!boxad)
2176  boxad = boxaCopy(boxas, L_COPY);
2177  n = boxaGetCount(boxad);
2178  for (i = 0; i < n; i++) {
2179  if ((box = boxaGetValidBox(boxad, i, L_CLONE)) == NULL)
2180  continue;
2181  boxGetGeometry(box, &x, &y, &w, &h);
2182  diff = h - target;
2183  if (sides == L_ADJUST_TOP) {
2184  if (L_ABS(diff) >= thresh)
2185  boxSetGeometry(box, x, L_MAX(0, y + diff), w, target);
2186  } else if (sides == L_ADJUST_BOT) {
2187  if (L_ABS(diff) >= thresh)
2188  boxSetGeometry(box, x, y, w, target);
2189  } else { /* sides == L_ADJUST_TOP_AND_BOT */
2190  if (L_ABS(diff) >= thresh)
2191  boxSetGeometry(box, x, L_MAX(0, y + diff/2), w, target);
2192  }
2193  boxDestroy(&box);
2194  }
2195 
2196  return boxad;
2197 }
2198 
2199 
2208 l_ok
2210  BOX *box2,
2211  l_int32 *psame)
2212 {
2213  if (!psame)
2214  return ERROR_INT("&same not defined", __func__, 1);
2215  *psame = 0;
2216  if (!box1 || !box2)
2217  return ERROR_INT("boxes not both defined", __func__, 1);
2218  if (box1->x == box2->x && box1->y == box2->y &&
2219  box1->w == box2->w && box1->h == box2->h)
2220  *psame = 1;
2221  return 0;
2222 }
2223 
2224 
2253 l_ok
2255  BOXA *boxa2,
2256  l_int32 maxdist,
2257  NUMA **pnaindex,
2258  l_int32 *psame)
2259 {
2260 l_int32 i, j, n, jstart, jend, found, samebox;
2261 l_int32 *countarray;
2262 BOX *box1, *box2;
2263 NUMA *na;
2264 
2265  if (pnaindex) *pnaindex = NULL;
2266  if (!psame)
2267  return ERROR_INT("&same not defined", __func__, 1);
2268  *psame = 0;
2269  if (!boxa1 || !boxa2)
2270  return ERROR_INT("boxa1 and boxa2 not both defined", __func__, 1);
2271  n = boxaGetCount(boxa1);
2272  if (n != boxaGetCount(boxa2))
2273  return 0;
2274 
2275  if ((countarray = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32))) == NULL)
2276  return ERROR_INT("calloc fail for countarray", __func__, 1);
2277  na = numaMakeConstant(0.0, n);
2278 
2279  for (i = 0; i < n; i++) {
2280  box1 = boxaGetBox(boxa1, i, L_CLONE);
2281  jstart = L_MAX(0, i - maxdist);
2282  jend = L_MIN(n-1, i + maxdist);
2283  found = FALSE;
2284  for (j = jstart; j <= jend; j++) {
2285  box2 = boxaGetBox(boxa2, j, L_CLONE);
2286  boxEqual(box1, box2, &samebox);
2287  if (samebox && countarray[j] == 0) {
2288  countarray[j] = 1;
2289  numaReplaceNumber(na, i, j);
2290  found = TRUE;
2291  boxDestroy(&box2);
2292  break;
2293  }
2294  boxDestroy(&box2);
2295  }
2296  boxDestroy(&box1);
2297  if (!found) {
2298  numaDestroy(&na);
2299  LEPT_FREE(countarray);
2300  return 0;
2301  }
2302  }
2303 
2304  *psame = 1;
2305  if (pnaindex)
2306  *pnaindex = na;
2307  else
2308  numaDestroy(&na);
2309  LEPT_FREE(countarray);
2310  return 0;
2311 }
2312 
2313 
2330 l_ok
2332  BOX *box2,
2333  l_int32 leftdiff,
2334  l_int32 rightdiff,
2335  l_int32 topdiff,
2336  l_int32 botdiff,
2337  l_int32 *psimilar)
2338 {
2339 l_int32 l1, l2, r1, r2, t1, t2, b1, b2, valid1, valid2;
2340 
2341  if (!psimilar)
2342  return ERROR_INT("&similar not defined", __func__, 1);
2343  *psimilar = 0;
2344  if (!box1 || !box2)
2345  return ERROR_INT("boxes not both defined", __func__, 1);
2346  boxIsValid(box1, &valid1);
2347  boxIsValid(box2, &valid2);
2348  if (!valid1 || !valid2)
2349  return ERROR_INT("boxes not both valid", __func__, 1);
2350 
2351  boxGetSideLocations(box1, &l1, &r1, &t1, &b1);
2352  boxGetSideLocations(box2, &l2, &r2, &t2, &b2);
2353  if (L_ABS(l1 - l2) > leftdiff)
2354  return 0;
2355  if (L_ABS(r1 - r2) > rightdiff)
2356  return 0;
2357  if (L_ABS(t1 - t2) > topdiff)
2358  return 0;
2359  if (L_ABS(b1 - b2) > botdiff)
2360  return 0;
2361 
2362  *psimilar = 1;
2363  return 0;
2364 }
2365 
2366 
2387 l_ok
2389  BOXA *boxa2,
2390  l_int32 leftdiff,
2391  l_int32 rightdiff,
2392  l_int32 topdiff,
2393  l_int32 botdiff,
2394  l_int32 debug,
2395  l_int32 *psimilar,
2396  NUMA **pnasim)
2397 {
2398 l_int32 i, n1, n2, match, mismatch;
2399 BOX *box1, *box2;
2400 
2401  if (psimilar) *psimilar = 0;
2402  if (pnasim) *pnasim = NULL;
2403  if (!boxa1 || !boxa2)
2404  return ERROR_INT("boxa1 and boxa2 not both defined", __func__, 1);
2405  if (!psimilar)
2406  return ERROR_INT("&similar not defined", __func__, 1);
2407  n1 = boxaGetCount(boxa1);
2408  n2 = boxaGetCount(boxa2);
2409  if (n1 != n2) {
2410  L_ERROR("boxa counts differ: %d vs %d\n", __func__, n1, n2);
2411  return 1;
2412  }
2413  if (pnasim) *pnasim = numaCreate(n1);
2414 
2415  mismatch = FALSE;
2416  for (i = 0; i < n1; i++) {
2417  box1 = boxaGetBox(boxa1, i, L_CLONE);
2418  box2 = boxaGetBox(boxa2, i, L_CLONE);
2419  boxSimilar(box1, box2, leftdiff, rightdiff, topdiff, botdiff,
2420  &match);
2421  boxDestroy(&box1);
2422  boxDestroy(&box2);
2423  if (pnasim)
2424  numaAddNumber(*pnasim, match);
2425  if (!match) {
2426  mismatch = TRUE;
2427  if (!debug && pnasim == NULL)
2428  return 0;
2429  else if (debug)
2430  L_INFO("box %d not similar\n", __func__, i);
2431  }
2432  }
2433 
2434  if (!mismatch) *psimilar = 1;
2435  return 0;
2436 }
2437 
2438 
2439 /*----------------------------------------------------------------------*
2440  * Boxa combine and split *
2441  *----------------------------------------------------------------------*/
2459 l_ok
2461  BOXA *boxas,
2462  l_int32 istart,
2463  l_int32 iend)
2464 {
2465 l_int32 n, i;
2466 BOX *box;
2467 
2468  if (!boxad)
2469  return ERROR_INT("boxad not defined", __func__, 1);
2470  if (!boxas || ((n = boxaGetCount(boxas)) == 0))
2471  return 0;
2472 
2473  if (istart < 0)
2474  istart = 0;
2475  if (iend < 0 || iend >= n)
2476  iend = n - 1;
2477  if (istart > iend)
2478  return ERROR_INT("istart > iend; nothing to add", __func__, 1);
2479 
2480  for (i = istart; i <= iend; i++) {
2481  box = boxaGetBox(boxas, i, L_CLONE);
2482  boxaAddBox(boxad, box, L_INSERT);
2483  }
2484 
2485  return 0;
2486 }
2487 
2488 
2506 l_ok
2508  BOXAA *baas,
2509  l_int32 istart,
2510  l_int32 iend)
2511 {
2512 l_int32 n, i;
2513 BOXA *boxa;
2514 
2515  if (!baad)
2516  return ERROR_INT("baad not defined", __func__, 1);
2517  if (!baas)
2518  return 0;
2519 
2520  if (istart < 0)
2521  istart = 0;
2522  n = boxaaGetCount(baas);
2523  if (iend < 0 || iend >= n)
2524  iend = n - 1;
2525  if (istart > iend)
2526  return ERROR_INT("istart > iend; nothing to add", __func__, 1);
2527 
2528  for (i = istart; i <= iend; i++) {
2529  boxa = boxaaGetBoxa(baas, i, L_CLONE);
2530  boxaaAddBoxa(baad, boxa, L_INSERT);
2531  }
2532 
2533  return 0;
2534 }
2535 
2536 
2554 l_ok
2556  l_int32 fillflag,
2557  BOXA **pboxae,
2558  BOXA **pboxao)
2559 {
2560 l_int32 i, n;
2561 BOX *box, *box1;
2562 
2563  if (pboxae) *pboxae = NULL;
2564  if (pboxao) *pboxao = NULL;
2565  if (!pboxae || !pboxao)
2566  return ERROR_INT("&boxae and &boxao not both defined", __func__, 1);
2567  if (!boxa)
2568  return ERROR_INT("boxa not defined", __func__, 1);
2569 
2570  n = boxaGetCount(boxa);
2571  *pboxae = boxaCreate(n);
2572  *pboxao = boxaCreate(n);
2573  if (fillflag == 0) {
2574  /* don't fill with invalid boxes; end up with half-size boxa */
2575  for (i = 0; i < n; i++) {
2576  box = boxaGetBox(boxa, i, L_COPY);
2577  if ((i & 1) == 0)
2578  boxaAddBox(*pboxae, box, L_INSERT);
2579  else
2580  boxaAddBox(*pboxao, box, L_INSERT);
2581  }
2582  } else {
2583  for (i = 0; i < n; i++) {
2584  box = boxaGetBox(boxa, i, L_COPY);
2585  box1 = boxCreate(0, 0, 0, 0); /* empty placeholder */
2586  if ((i & 1) == 0) {
2587  boxaAddBox(*pboxae, box, L_INSERT);
2588  boxaAddBox(*pboxao, box1, L_INSERT);
2589  } else {
2590  boxaAddBox(*pboxae, box1, L_INSERT);
2591  boxaAddBox(*pboxao, box, L_INSERT);
2592  }
2593  }
2594  }
2595  return 0;
2596 }
2597 
2598 
2616 BOXA *
2618  BOXA *boxao,
2619  l_int32 fillflag)
2620 {
2621 l_int32 i, n, ne, no;
2622 BOX *box;
2623 BOXA *boxad;
2624 
2625  if (!boxae || !boxao)
2626  return (BOXA *)ERROR_PTR("boxae and boxao not defined", __func__, NULL);
2627  ne = boxaGetCount(boxae);
2628  no = boxaGetCount(boxao);
2629  if (ne < no || ne > no + 1)
2630  return (BOXA *)ERROR_PTR("boxa sizes invalid", __func__, NULL);
2631 
2632  boxad = boxaCreate(ne);
2633  if (fillflag == 0) { /* both are approx. half-sized; all valid boxes */
2634  n = ne + no;
2635  for (i = 0; i < n; i++) {
2636  if ((i & 1) == 0)
2637  box = boxaGetBox(boxae, i / 2, L_COPY);
2638  else
2639  box = boxaGetBox(boxao, i / 2, L_COPY);
2640  boxaAddBox(boxad, box, L_INSERT);
2641  }
2642  } else { /* both are full size and have invalid placeholders */
2643  for (i = 0; i < ne; i++) {
2644  if ((i & 1) == 0)
2645  box = boxaGetBox(boxae, i, L_COPY);
2646  else
2647  box = boxaGetBox(boxao, i, L_COPY);
2648  boxaAddBox(boxad, box, L_INSERT);
2649  }
2650  }
2651  return boxad;
2652 }
BOXA * boxaSaveValid(BOXA *boxas, l_int32 copyflag)
boxaSaveValid()
Definition: boxbasic.c:1023
l_ok boxGetGeometry(const BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:301
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:475
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
l_ok boxaReplaceBox(BOXA *boxa, l_int32 index, BOX *box)
boxaReplaceBox()
Definition: boxbasic.c:875
l_ok boxGetSideLocations(const BOX *box, l_int32 *pl, l_int32 *pr, l_int32 *pt, l_int32 *pb)
boxGetSideLocations()
Definition: boxbasic.c:358
l_int32 boxaaGetCount(BOXAA *baa)
boxaaGetCount()
Definition: boxbasic.c:1343
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:796
l_ok boxaaAddBoxa(BOXAA *baa, BOXA *ba, l_int32 copyflag)
boxaaAddBoxa()
Definition: boxbasic.c:1241
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:553
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
l_int32 boxaGetCount(const BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:661
l_ok boxIsValid(BOX *box, l_int32 *pvalid)
boxIsValid()
Definition: boxbasic.c:417
l_ok boxSetGeometry(BOX *box, l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxSetGeometry()
Definition: boxbasic.c:329
BOX * boxaGetValidBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetValidBox()
Definition: boxbasic.c:739
BOXA * boxaaGetBoxa(BOXAA *baa, l_int32 index, l_int32 accessflag)
boxaaGetBoxa()
Definition: boxbasic.c:1386
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:702
BOX * boxCopy(BOX *box)
boxCopy()
Definition: boxbasic.c:230
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:171
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:442
BOX * boxaGetNearestToLine(BOXA *boxa, l_int32 x, l_int32 y)
boxaGetNearestToLine()
Definition: boxfunc1.c:1266
l_ok boxEqual(BOX *box1, BOX *box2, l_int32 *psame)
boxEqual()
Definition: boxfunc1.c:2209
l_ok boxCompareSize(BOX *box1, BOX *box2, l_int32 type, l_int32 *prel)
boxCompareSize()
Definition: boxfunc1.c:1129
BOX * boxaGetNearestToPt(BOXA *boxa, l_int32 x, l_int32 y)
boxaGetNearestToPt()
Definition: boxfunc1.c:1215
BOX * boxRelocateOneSide(BOX *boxd, BOX *boxs, l_int32 loc, l_int32 sideflag)
boxRelocateOneSide()
Definition: boxfunc1.c:1794
BOXA * boxaMergeEvenOdd(BOXA *boxae, BOXA *boxao, l_int32 fillflag)
boxaMergeEvenOdd()
Definition: boxfunc1.c:2617
BOXA * boxaContainedInBox(BOXA *boxas, BOX *box)
boxaContainedInBox()
Definition: boxfunc1.c:185
BOXA * boxaSetSide(BOXA *boxad, BOXA *boxas, l_int32 side, l_int32 val, l_int32 thresh)
boxaSetSide()
Definition: boxfunc1.c:1982
l_ok boxaGetNearestByDirection(BOXA *boxa, l_int32 i, l_int32 dir, l_int32 dist_select, l_int32 range, l_int32 *pindex, l_int32 *pdist)
boxaGetNearestByDirection()
Definition: boxfunc1.c:1401
BOXA * boxaAdjustHeightToTarget(BOXA *boxad, BOXA *boxas, l_int32 sides, l_int32 target, l_int32 thresh)
boxaAdjustHeightToTarget()
Definition: boxfunc1.c:2156
BOX * boxClipToRectangle(BOX *box, l_int32 wi, l_int32 hi)
boxClipToRectangle()
Definition: boxfunc1.c:1679
l_ok boxIntersectByLine(const BOX *box, l_int32 x, l_int32 y, l_float32 slope, l_int32 *px1, l_int32 *py1, l_int32 *px2, l_int32 *py2, l_int32 *pn)
boxIntersectByLine()
Definition: boxfunc1.c:1578
l_ok boxaEqual(BOXA *boxa1, BOXA *boxa2, l_int32 maxdist, NUMA **pnaindex, l_int32 *psame)
boxaEqual()
Definition: boxfunc1.c:2254
l_ok boxaAdjustBoxSides(BOXA *boxa, l_int32 index, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxaAdjustBoxSides()
Definition: boxfunc1.c:1886
l_ok boxaJoin(BOXA *boxad, BOXA *boxas, l_int32 istart, l_int32 iend)
boxaJoin()
Definition: boxfunc1.c:2460
BOXA * boxaIntersectsBox(BOXA *boxas, BOX *box)
boxaIntersectsBox()
Definition: boxfunc1.c:322
l_ok boxaCombineOverlapsInPair(BOXA *boxas1, BOXA *boxas2, BOXA **pboxad1, BOXA **pboxad2, PIXA *pixadb)
boxaCombineOverlapsInPair()
Definition: boxfunc1.c:555
l_ok boxGetCenter(const BOX *box, l_float32 *pcx, l_float32 *pcy)
boxGetCenter()
Definition: boxfunc1.c:1538
l_ok boxOverlapDistance(BOX *box1, BOX *box2, l_int32 *ph_ovl, l_int32 *pv_ovl)
boxOverlapDistance()
Definition: boxfunc1.c:1015
l_ok boxSimilar(BOX *box1, BOX *box2, l_int32 leftdiff, l_int32 rightdiff, l_int32 topdiff, l_int32 botdiff, l_int32 *psimilar)
boxSimilar()
Definition: boxfunc1.c:2331
l_ok boxIntersects(BOX *box1, BOX *box2, l_int32 *presult)
boxIntersects()
Definition: boxfunc1.c:140
l_ok boxaContainedInBoxa(BOXA *boxa1, BOXA *boxa2, l_int32 *pcontained)
boxaContainedInBoxa()
Definition: boxfunc1.c:269
l_ok boxaFindNearestBoxes(BOXA *boxa, l_int32 dist_select, l_int32 range, NUMAA **pnaaindex, NUMAA **pnaadist)
boxaFindNearestBoxes()
Definition: boxfunc1.c:1322
l_ok boxaSimilar(BOXA *boxa1, BOXA *boxa2, l_int32 leftdiff, l_int32 rightdiff, l_int32 topdiff, l_int32 botdiff, l_int32 debug, l_int32 *psimilar, NUMA **pnasim)
boxaSimilar()
Definition: boxfunc1.c:2388
BOX * boxOverlapRegion(BOX *box1, BOX *box2)
boxOverlapRegion()
Definition: boxfunc1.c:691
BOXA * boxaAdjustSides(BOXA *boxas, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxaAdjustSides()
Definition: boxfunc1.c:1838
BOXA * boxaClipToBox(BOXA *boxas, BOX *box)
boxaClipToBox()
Definition: boxfunc1.c:406
l_ok boxaContainedInBoxCount(BOXA *boxa, BOX *box, l_int32 *pcount)
boxaContainedInBoxCount()
Definition: boxfunc1.c:229
l_ok boxOverlapArea(BOX *box1, BOX *box2, l_int32 *parea)
boxOverlapArea()
Definition: boxfunc1.c:825
l_ok boxaIntersectsBoxCount(BOXA *boxa, BOX *box, l_int32 *pcount)
boxaIntersectsBoxCount()
Definition: boxfunc1.c:361
l_ok boxContains(BOX *box1, BOX *box2, l_int32 *presult)
boxContains()
Definition: boxfunc1.c:107
l_ok boxSetSide(BOX *boxs, l_int32 side, l_int32 val, l_int32 thresh)
boxSetSide()
Definition: boxfunc1.c:2030
static l_int32 boxHasOverlapInXorY(l_int32 c1, l_int32 s1, l_int32 c2, l_int32 s2)
boxHasOverlapInXorY()
Definition: boxfunc1.c:1489
BOXA * boxaHandleOverlaps(BOXA *boxas, l_int32 op, l_int32 range, l_float32 min_overlap, l_float32 max_ratio, NUMA **pnamap)
boxaHandleOverlaps()
Definition: boxfunc1.c:887
l_ok boxContainsPt(BOX *box, l_float32 x, l_float32 y, l_int32 *pcontains)
boxContainsPt()
Definition: boxfunc1.c:1182
BOX * boxBoundingRegion(BOX *box1, BOX *box2)
boxBoundingRegion()
Definition: boxfunc1.c:739
l_ok boxSeparationDistance(BOX *box1, BOX *box2, l_int32 *ph_sep, l_int32 *pv_sep)
boxSeparationDistance()
Definition: boxfunc1.c:1086
l_ok boxaaJoin(BOXAA *baad, BOXAA *baas, l_int32 istart, l_int32 iend)
boxaaJoin()
Definition: boxfunc1.c:2507
static l_int32 boxGetDistanceInXorY(l_int32 c1, l_int32 s1, l_int32 c2, l_int32 s2)
boxGetDistanceInXorY()
Definition: boxfunc1.c:1515
BOX * boxAdjustSides(BOX *boxd, BOX *boxs, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxAdjustSides()
Definition: boxfunc1.c:1932
l_ok boxClipToRectangleParams(BOX *box, l_int32 w, l_int32 h, l_int32 *pxstart, l_int32 *pystart, l_int32 *pxend, l_int32 *pyend, l_int32 *pbw, l_int32 *pbh)
boxClipToRectangleParams()
Definition: boxfunc1.c:1734
BOXA * boxaCombineOverlaps(BOXA *boxas, PIXA *pixadb)
boxaCombineOverlaps()
Definition: boxfunc1.c:463
BOXA * boxaAdjustWidthToTarget(BOXA *boxad, BOXA *boxas, l_int32 sides, l_int32 target, l_int32 thresh)
boxaAdjustWidthToTarget()
Definition: boxfunc1.c:2090
l_ok boxOverlapFraction(BOX *box1, BOX *box2, l_float32 *pfract)
boxOverlapFraction()
Definition: boxfunc1.c:787
l_ok boxaSplitEvenOdd(BOXA *boxa, l_int32 fillflag, BOXA **pboxae, BOXA **pboxao)
boxaSplitEvenOdd()
Definition: boxfunc1.c:2555
l_ok boxaGetArea(BOXA *boxa, l_int32 *parea)
boxaGetArea()
Definition: boxfunc4.c:1244
l_ok boxaGetExtent(BOXA *boxa, l_int32 *pw, l_int32 *ph, BOX **pbox)
boxaGetExtent()
Definition: boxfunc4.c:922
l_ok pixRenderBoxaArb(PIX *pix, BOXA *boxa, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxaArb()
Definition: graphics.c:1717
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
l_ok numaReplaceNumber(NUMA *na, l_int32 index, l_float32 val)
numaReplaceNumber()
Definition: numabasic.c:601
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1302
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:750
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1435
NUMA * numaMakeConstant(l_float32 val, l_int32 size)
numaMakeConstant()
Definition: numafunc1.c:820
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:799
@ L_SORT_BY_AREA
Definition: pix.h:537
@ L_SORT_BY_PERIMETER
Definition: pix.h:536
@ L_SORT_BY_WIDTH
Definition: pix.h:532
@ L_SORT_BY_HEIGHT
Definition: pix.h:533
@ L_SORT_BY_MAX_DIMENSION
Definition: pix.h:535
@ L_COPY
Definition: pix.h:505
@ L_CLONE
Definition: pix.h:506
@ L_INSERT
Definition: pix.h:504
@ L_SET_RIGHT
Definition: pix.h:853
@ L_SET_LEFT
Definition: pix.h:852
@ L_ADJUST_LEFT
Definition: pix.h:844
@ L_SET_BOT
Definition: pix.h:855
@ L_ADJUST_LEFT_AND_RIGHT
Definition: pix.h:846
@ L_ADJUST_RIGHT
Definition: pix.h:845
@ L_ADJUST_BOT
Definition: pix.h:848
@ L_ADJUST_TOP
Definition: pix.h:847
@ L_SET_TOP
Definition: pix.h:854
@ L_ADJUST_TOP_AND_BOT
Definition: pix.h:849
@ L_FROM_BOT
Definition: pix.h:830
@ L_FROM_LEFT
Definition: pix.h:827
@ L_FROM_RIGHT
Definition: pix.h:828
@ L_FROM_TOP
Definition: pix.h:829
@ L_REMOVE_SMALL
Definition: pix.h:881
@ L_COMBINE
Definition: pix.h:880
@ L_NON_NEGATIVE
Definition: pix.h:749
@ L_ALL
Definition: pix.h:753
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:527
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:328
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:480
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:191
l_int32 y
Definition: pix_internal.h:258
l_int32 x
Definition: pix_internal.h:257
l_int32 w
Definition: pix_internal.h:259
l_int32 h
Definition: pix_internal.h:260