/*! * \brief boxaPermutePseudorandom() * * \param[in] boxas input boxa * \return boxad with boxes permuted, or NULL on error * * <pre> * Notes: * (1) This does a pseudorandom in-place permutation of the boxes. * (2) The result is guaranteed not to have any boxes in their * original position, but it is not very random. If you * need randomness, use boxaPermuteRandom(). * </pre> */ BOXA * boxaPermutePseudorandom(BOXA *boxas) { l_int32 n; NUMA *na; BOXA *boxad; PROCNAME("boxaPermutePseudorandom"); if (!boxas) return (BOXA *)ERROR_PTR("boxa not defined", procName, NULL); n = boxaGetCount(boxas); na = numaPseudorandomSequence(n, 0); boxad = boxaSortByIndex(boxas, na); numaDestroy(&na); return boxad; }
/*! * boxaBinSort() * * Input: boxa * sorttype (L_SORT_BY_X, L_SORT_BY_Y, L_SORT_BY_WIDTH, * L_SORT_BY_HEIGHT, L_SORT_BY_PERIMETER) * sortorder (L_SORT_INCREASING, L_SORT_DECREASING) * &naindex (<optional return> index of sorted order into * original array) * Return: boxad (sorted version of boxas), or null on error * * Notes: * (1) For a large number of boxes (say, greater than 1000), this * O(n) binsort is much faster than the O(nlogn) shellsort. * For 5000 components, this is over 20x faster than boxaSort(). * (2) Consequently, boxaSort() calls this function if it will * likely go much faster. */ BOXA * boxaBinSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex) { l_int32 i, n, x, y, w, h; BOXA *boxad; NUMA *na, *naindex; PROCNAME("boxaBinSort"); if (pnaindex) *pnaindex = NULL; if (!boxas) return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL); if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y && sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT && sorttype != L_SORT_BY_PERIMETER) return (BOXA *)ERROR_PTR("invalid sort type", procName, NULL); if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING) return (BOXA *)ERROR_PTR("invalid sort order", procName, NULL); /* Generate Numa of appropriate box dimensions */ n = boxaGetCount(boxas); if ((na = numaCreate(n)) == NULL) return (BOXA *)ERROR_PTR("na not made", procName, NULL); for (i = 0; i < n; i++) { boxaGetBoxGeometry(boxas, i, &x, &y, &w, &h); switch (sorttype) { case L_SORT_BY_X: numaAddNumber(na, x); break; case L_SORT_BY_Y: numaAddNumber(na, y); break; case L_SORT_BY_WIDTH: numaAddNumber(na, w); break; case L_SORT_BY_HEIGHT: numaAddNumber(na, h); break; case L_SORT_BY_PERIMETER: numaAddNumber(na, w + h); break; default: L_WARNING("invalid sort type", procName); } } /* Get the sort index for data array */ if ((naindex = numaGetBinSortIndex(na, sortorder)) == NULL) return (BOXA *)ERROR_PTR("naindex not made", procName, NULL); /* Build up sorted boxa using the sort index */ boxad = boxaSortByIndex(boxas, naindex); if (pnaindex) *pnaindex = naindex; else numaDestroy(&naindex); numaDestroy(&na); return boxad; }
/*! * boxaSort() * * Input: boxa * sorttype (L_SORT_BY_X, L_SORT_BY_Y, L_SORT_BY_WIDTH, * L_SORT_BY_HEIGHT, L_SORT_BY_MIN_DIMENSION, * L_SORT_BY_MAX_DIMENSION, L_SORT_BY_PERIMETER, * L_SORT_BY_AREA, L_SORT_BY_ASPECT_RATIO) * sortorder (L_SORT_INCREASING, L_SORT_DECREASING) * &naindex (<optional return> index of sorted order into * original array) * Return: boxad (sorted version of boxas), or null on error */ BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex) { l_int32 i, n, x, y, w, h, size; BOXA *boxad; NUMA *na, *naindex; PROCNAME("boxaSort"); if (pnaindex) *pnaindex = NULL; if (!boxas) return (BOXA *)ERROR_PTR("boxas not defined", procName, NULL); if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y && sorttype != L_SORT_BY_WIDTH && sorttype != L_SORT_BY_HEIGHT && sorttype != L_SORT_BY_MIN_DIMENSION && sorttype != L_SORT_BY_MAX_DIMENSION && sorttype != L_SORT_BY_PERIMETER && sorttype != L_SORT_BY_AREA && sorttype != L_SORT_BY_ASPECT_RATIO) return (BOXA *)ERROR_PTR("invalid sort type", procName, NULL); if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING) return (BOXA *)ERROR_PTR("invalid sort order", procName, NULL); /* Use O(n) binsort if possible */ n = boxaGetCount(boxas); if (n > MIN_COMPS_FOR_BIN_SORT && ((sorttype == L_SORT_BY_X) || (sorttype == L_SORT_BY_Y) || (sorttype == L_SORT_BY_WIDTH) || (sorttype == L_SORT_BY_HEIGHT) || (sorttype == L_SORT_BY_PERIMETER))) return boxaBinSort(boxas, sorttype, sortorder, pnaindex); /* Build up numa of specific data */ if ((na = numaCreate(n)) == NULL) return (BOXA *)ERROR_PTR("na not made", procName, NULL); for (i = 0; i < n; i++) { boxaGetBoxGeometry(boxas, i, &x, &y, &w, &h); switch (sorttype) { case L_SORT_BY_X: numaAddNumber(na, x); break; case L_SORT_BY_Y: numaAddNumber(na, y); break; case L_SORT_BY_WIDTH: numaAddNumber(na, w); break; case L_SORT_BY_HEIGHT: numaAddNumber(na, h); break; case L_SORT_BY_MIN_DIMENSION: size = L_MIN(w, h); numaAddNumber(na, size); break; case L_SORT_BY_MAX_DIMENSION: size = L_MAX(w, h); numaAddNumber(na, size); break; case L_SORT_BY_PERIMETER: size = w + h; numaAddNumber(na, size); break; case L_SORT_BY_AREA: size = w * h; numaAddNumber(na, size); break; case L_SORT_BY_ASPECT_RATIO: numaAddNumber(na, (l_float32)w / (l_float32)h); break; default: L_WARNING("invalid sort type", procName); } } /* Get the sort index for data array */ if ((naindex = numaGetSortIndex(na, sortorder)) == NULL) return (BOXA *)ERROR_PTR("naindex not made", procName, NULL); /* Build up sorted boxa using sort index */ boxad = boxaSortByIndex(boxas, naindex); if (pnaindex) *pnaindex = naindex; else numaDestroy(&naindex); numaDestroy(&na); return boxad; }