diff options
Diffstat (limited to 'leptonica/src/ptabasic.c')
-rw-r--r-- | leptonica/src/ptabasic.c | 1607 |
1 files changed, 1607 insertions, 0 deletions
diff --git a/leptonica/src/ptabasic.c b/leptonica/src/ptabasic.c new file mode 100644 index 00000000..25b23a70 --- /dev/null +++ b/leptonica/src/ptabasic.c @@ -0,0 +1,1607 @@ +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + +/*! + * \file ptabasic.c + * <pre> + * + * Pta creation, destruction, copy, clone, empty + * PTA *ptaCreate() + * PTA *ptaCreateFromNuma() + * void ptaDestroy() + * PTA *ptaCopy() + * PTA *ptaCopyRange() + * PTA *ptaClone() + * l_int32 ptaEmpty() + * + * Pta array extension + * l_int32 ptaAddPt() + * static l_int32 ptaExtendArrays() + * + * Pta insertion and removal + * l_int32 ptaInsertPt() + * l_int32 ptaRemovePt() + * + * Pta accessors + * l_int32 ptaGetRefcount() + * l_int32 ptaChangeRefcount() + * l_int32 ptaGetCount() + * l_int32 ptaGetPt() + * l_int32 ptaGetIPt() + * l_int32 ptaSetPt() + * l_int32 ptaGetArrays() + * + * Pta serialized for I/O + * PTA *ptaRead() + * PTA *ptaReadStream() + * PTA *ptaReadMem() + * l_int32 ptaWriteDebug() + * l_int32 ptaWrite() + * l_int32 ptaWriteStream() + * l_int32 ptaWriteMem() + * + * Ptaa creation, destruction + * PTAA *ptaaCreate() + * void ptaaDestroy() + * + * Ptaa array extension + * l_int32 ptaaAddPta() + * static l_int32 ptaaExtendArray() + * + * Ptaa accessors + * l_int32 ptaaGetCount() + * l_int32 ptaaGetPta() + * l_int32 ptaaGetPt() + * + * Ptaa array modifiers + * l_int32 ptaaInitFull() + * l_int32 ptaaReplacePta() + * l_int32 ptaaAddPt() + * l_int32 ptaaTruncate() + * + * Ptaa serialized for I/O + * PTAA *ptaaRead() + * PTAA *ptaaReadStream() + * PTAA *ptaaReadMem() + * l_int32 ptaaWrite() + * l_int32 ptaaWriteStream() + * l_int32 ptaaWriteMem() + * </pre> + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include "allheaders.h" + +static const l_uint32 MaxArraySize = 100000000; /* 100 million */ +static const l_uint32 MaxPtrArraySize = 10000000; /* 10 million */ +static const l_int32 InitialArraySize = 50; /*!< n'importe quoi */ + + /* Static functions */ +static l_int32 ptaExtendArrays(PTA *pta); +static l_int32 ptaaExtendArray(PTAA *ptaa); + +/*---------------------------------------------------------------------* + * Pta creation, destruction, copy, clone * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaCreate() + * + * \param[in] n initial array sizes + * \return pta, or NULL on error. + */ +PTA * +ptaCreate(l_int32 n) +{ +PTA *pta; + + PROCNAME("ptaCreate"); + + if (n <= 0 || n > MaxArraySize) + n = InitialArraySize; + + pta = (PTA *)LEPT_CALLOC(1, sizeof(PTA)); + pta->n = 0; + pta->nalloc = n; + ptaChangeRefcount(pta, 1); /* sets to 1 */ + pta->x = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32)); + pta->y = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32)); + if (!pta->x || !pta->y) { + ptaDestroy(&pta); + return (PTA *)ERROR_PTR("x and y arrays not both made", procName, NULL); + } + + return pta; +} + + +/*! + * \brief ptaCreateFromNuma() + * + * \param[in] nax [optional] can be null + * \param[in] nay + * \return pta, or NULL on error. + */ +PTA * +ptaCreateFromNuma(NUMA *nax, + NUMA *nay) +{ +l_int32 i, n; +l_float32 startx, delx, xval, yval; +PTA *pta; + + PROCNAME("ptaCreateFromNuma"); + + if (!nay) + return (PTA *)ERROR_PTR("nay not defined", procName, NULL); + n = numaGetCount(nay); + if (nax && numaGetCount(nax) != n) + return (PTA *)ERROR_PTR("nax and nay sizes differ", procName, NULL); + + pta = ptaCreate(n); + numaGetParameters(nay, &startx, &delx); + for (i = 0; i < n; i++) { + if (nax) + numaGetFValue(nax, i, &xval); + else /* use implicit x values from nay */ + xval = startx + i * delx; + numaGetFValue(nay, i, &yval); + ptaAddPt(pta, xval, yval); + } + + return pta; +} + + +/*! + * \brief ptaDestroy() + * + * \param[in,out] ppta will be set to null before returning + * \return void + * + * <pre> + * Notes: + * (1) Decrements the ref count and, if 0, destroys the pta. + * (2) Always nulls the input ptr. + * </pre> + */ +void +ptaDestroy(PTA **ppta) +{ +PTA *pta; + + PROCNAME("ptaDestroy"); + + if (ppta == NULL) { + L_WARNING("ptr address is NULL!\n", procName); + return; + } + + if ((pta = *ppta) == NULL) + return; + + ptaChangeRefcount(pta, -1); + if (ptaGetRefcount(pta) <= 0) { + LEPT_FREE(pta->x); + LEPT_FREE(pta->y); + LEPT_FREE(pta); + } + *ppta = NULL; +} + + +/*! + * \brief ptaCopy() + * + * \param[in] pta + * \return copy of pta, or NULL on error + */ +PTA * +ptaCopy(PTA *pta) +{ +l_int32 i; +l_float32 x, y; +PTA *npta; + + PROCNAME("ptaCopy"); + + if (!pta) + return (PTA *)ERROR_PTR("pta not defined", procName, NULL); + + if ((npta = ptaCreate(pta->nalloc)) == NULL) + return (PTA *)ERROR_PTR("npta not made", procName, NULL); + + for (i = 0; i < pta->n; i++) { + ptaGetPt(pta, i, &x, &y); + ptaAddPt(npta, x, y); + } + + return npta; +} + + +/*! + * \brief ptaCopyRange() + * + * \param[in] ptas + * \param[in] istart starting index in ptas + * \param[in] iend ending index in ptas; use 0 to copy to end + * \return 0 if OK, 1 on error + */ +PTA * +ptaCopyRange(PTA *ptas, + l_int32 istart, + l_int32 iend) +{ +l_int32 n, i, x, y; +PTA *ptad; + + PROCNAME("ptaCopyRange"); + + if (!ptas) + return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); + n = ptaGetCount(ptas); + if (istart < 0) + istart = 0; + if (istart >= n) + return (PTA *)ERROR_PTR("istart out of bounds", procName, NULL); + if (iend <= 0 || iend >= n) + iend = n - 1; + if (istart > iend) + return (PTA *)ERROR_PTR("istart > iend; no pts", procName, NULL); + + if ((ptad = ptaCreate(iend - istart + 1)) == NULL) + return (PTA *)ERROR_PTR("ptad not made", procName, NULL); + for (i = istart; i <= iend; i++) { + ptaGetIPt(ptas, i, &x, &y); + ptaAddPt(ptad, x, y); + } + + return ptad; +} + + +/*! + * \brief ptaClone() + * + * \param[in] pta + * \return ptr to same pta, or NULL on error + */ +PTA * +ptaClone(PTA *pta) +{ + PROCNAME("ptaClone"); + + if (!pta) + return (PTA *)ERROR_PTR("pta not defined", procName, NULL); + + ptaChangeRefcount(pta, 1); + return pta; +} + + +/*! + * \brief ptaEmpty() + * + * \param[in] pta + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * This only resets the Pta::n field, for reuse + * </pre> + */ +l_ok +ptaEmpty(PTA *pta) +{ + PROCNAME("ptaEmpty"); + + if (!pta) + return ERROR_INT("ptad not defined", procName, 1); + pta->n = 0; + return 0; +} + + +/*---------------------------------------------------------------------* + * Pta array extension * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaAddPt() + * + * \param[in] pta + * \param[in] x, y + * \return 0 if OK, 1 on error + */ +l_ok +ptaAddPt(PTA *pta, + l_float32 x, + l_float32 y) +{ +l_int32 n; + + PROCNAME("ptaAddPt"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + + n = pta->n; + if (n >= pta->nalloc) { + if (ptaExtendArrays(pta)) + return ERROR_INT("extension failed", procName, 1); + } + + pta->x[n] = x; + pta->y[n] = y; + pta->n++; + return 0; +} + + +/*! + * \brief ptaExtendArrays() + * + * \param[in] pta + * \return 0 if OK; 1 on error + * + * <pre> + * Notes: + * (1) The max number of points is 100M. + * </pre> + */ +static l_int32 +ptaExtendArrays(PTA *pta) +{ +size_t oldsize, newsize; + + PROCNAME("ptaExtendArrays"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + if (pta->nalloc > MaxArraySize) /* belt & suspenders */ + return ERROR_INT("pta has too many ptrs", procName, 1); + oldsize = pta->nalloc * sizeof(l_float32); + newsize = 2 * oldsize; + if (newsize > 4 * MaxArraySize) /* array of 100M floats */ + return ERROR_INT("newsize > 400 MB; too large", procName, 1); + + if ((pta->x = (l_float32 *)reallocNew((void **)&pta->x, + oldsize, newsize)) == NULL) + return ERROR_INT("new x array not returned", procName, 1); + if ((pta->y = (l_float32 *)reallocNew((void **)&pta->y, + oldsize, newsize)) == NULL) + return ERROR_INT("new y array not returned", procName, 1); + + pta->nalloc *= 2; + return 0; +} + + +/*---------------------------------------------------------------------* + * Pta insertion and removal * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaInsertPt() + * + * \param[in] pta + * \param[in] index at which pt is to be inserted + * \param[in] x, y point values + * \return 0 if OK; 1 on error + */ +l_ok +ptaInsertPt(PTA *pta, + l_int32 index, + l_int32 x, + l_int32 y) +{ +l_int32 i, n; + + PROCNAME("ptaInsertPt"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + n = ptaGetCount(pta); + if (index < 0 || index > n) { + L_ERROR("index %d not in [0,...,%d]\n", procName, index, n); + return 1; + } + + if (n > pta->nalloc) { + if (ptaExtendArrays(pta)) + return ERROR_INT("extension failed", procName, 1); + } + pta->n++; + for (i = n; i > index; i--) { + pta->x[i] = pta->x[i - 1]; + pta->y[i] = pta->y[i - 1]; + } + pta->x[index] = x; + pta->y[index] = y; + return 0; +} + + +/*! + * \brief ptaRemovePt() + * + * \param[in] pta + * \param[in] index of point to be removed + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This shifts pta[i] --> pta[i - 1] for all i > index. + * (2) It should not be used repeatedly on large arrays, + * because the function is O(n). + * </pre> + */ +l_ok +ptaRemovePt(PTA *pta, + l_int32 index) +{ +l_int32 i, n; + + PROCNAME("ptaRemovePt"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + n = ptaGetCount(pta); + if (index < 0 || index >= n) { + L_ERROR("index %d not in [0,...,%d]\n", procName, index, n - 1); + return 1; + } + + /* Remove the point */ + for (i = index + 1; i < n; i++) { + pta->x[i - 1] = pta->x[i]; + pta->y[i - 1] = pta->y[i]; + } + pta->n--; + return 0; +} + + +/*---------------------------------------------------------------------* + * Pta accessors * + *---------------------------------------------------------------------*/ +l_int32 +ptaGetRefcount(PTA *pta) +{ + PROCNAME("ptaGetRefcount"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + return pta->refcount; +} + + +l_int32 +ptaChangeRefcount(PTA *pta, + l_int32 delta) +{ + PROCNAME("ptaChangeRefcount"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + pta->refcount += delta; + return 0; +} + + +/*! + * \brief ptaGetCount() + * + * \param[in] pta + * \return count, or 0 if no pta + */ +l_int32 +ptaGetCount(PTA *pta) +{ + PROCNAME("ptaGetCount"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 0); + + return pta->n; +} + + +/*! + * \brief ptaGetPt() + * + * \param[in] pta + * \param[in] index into arrays + * \param[out] px [optional] float x value + * \param[out] py [optional] float y value + * \return 0 if OK; 1 on error + */ +l_ok +ptaGetPt(PTA *pta, + l_int32 index, + l_float32 *px, + l_float32 *py) +{ + PROCNAME("ptaGetPt"); + + if (px) *px = 0; + if (py) *py = 0; + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + if (index < 0 || index >= pta->n) + return ERROR_INT("invalid index", procName, 1); + + if (px) *px = pta->x[index]; + if (py) *py = pta->y[index]; + return 0; +} + + +/*! + * \brief ptaGetIPt() + * + * \param[in] pta + * \param[in] index into arrays + * \param[out] px [optional] integer x value + * \param[out] py [optional] integer y value + * \return 0 if OK; 1 on error + */ +l_ok +ptaGetIPt(PTA *pta, + l_int32 index, + l_int32 *px, + l_int32 *py) +{ + PROCNAME("ptaGetIPt"); + + if (px) *px = 0; + if (py) *py = 0; + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + if (index < 0 || index >= pta->n) + return ERROR_INT("invalid index", procName, 1); + + if (px) *px = (l_int32)(pta->x[index] + 0.5); + if (py) *py = (l_int32)(pta->y[index] + 0.5); + return 0; +} + + +/*! + * \brief ptaSetPt() + * + * \param[in] pta + * \param[in] index into arrays + * \param[in] x, y + * \return 0 if OK; 1 on error + */ +l_ok +ptaSetPt(PTA *pta, + l_int32 index, + l_float32 x, + l_float32 y) +{ + PROCNAME("ptaSetPt"); + + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + if (index < 0 || index >= pta->n) + return ERROR_INT("invalid index", procName, 1); + + pta->x[index] = x; + pta->y[index] = y; + return 0; +} + + +/*! + * \brief ptaGetArrays() + * + * \param[in] pta + * \param[out] pnax [optional] numa of x array + * \param[out] pnay [optional] numa of y array + * \return 0 if OK; 1 on error or if pta is empty + * + * <pre> + * Notes: + * (1) This copies the internal arrays into new Numas. + * </pre> + */ +l_ok +ptaGetArrays(PTA *pta, + NUMA **pnax, + NUMA **pnay) +{ +l_int32 i, n; +NUMA *nax, *nay; + + PROCNAME("ptaGetArrays"); + + if (!pnax && !pnay) + return ERROR_INT("no output requested", procName, 1); + if (pnax) *pnax = NULL; + if (pnay) *pnay = NULL; + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + if ((n = ptaGetCount(pta)) == 0) + return ERROR_INT("pta is empty", procName, 1); + + if (pnax) { + if ((nax = numaCreate(n)) == NULL) + return ERROR_INT("nax not made", procName, 1); + *pnax = nax; + for (i = 0; i < n; i++) + nax->array[i] = pta->x[i]; + nax->n = n; + } + if (pnay) { + if ((nay = numaCreate(n)) == NULL) + return ERROR_INT("nay not made", procName, 1); + *pnay = nay; + for (i = 0; i < n; i++) + nay->array[i] = pta->y[i]; + nay->n = n; + } + return 0; +} + + +/*---------------------------------------------------------------------* + * Pta serialized for I/O * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaRead() + * + * \param[in] filename + * \return pta, or NULL on error + */ +PTA * +ptaRead(const char *filename) +{ +FILE *fp; +PTA *pta; + + PROCNAME("ptaRead"); + + if (!filename) + return (PTA *)ERROR_PTR("filename not defined", procName, NULL); + + if ((fp = fopenReadStream(filename)) == NULL) + return (PTA *)ERROR_PTR("stream not opened", procName, NULL); + pta = ptaReadStream(fp); + fclose(fp); + if (!pta) + return (PTA *)ERROR_PTR("pta not read", procName, NULL); + return pta; +} + + +/*! + * \brief ptaReadStream() + * + * \param[in] fp file stream + * \return pta, or NULL on error + * + * <pre> + * Notes: + * (1) It is OK for the pta to be empty (n == 0). + * </pre> + + */ +PTA * +ptaReadStream(FILE *fp) +{ +char typestr[128]; /* hardcoded below in fscanf */ +l_int32 i, n, ix, iy, type, version; +l_float32 x, y; +PTA *pta; + + PROCNAME("ptaReadStream"); + + if (!fp) + return (PTA *)ERROR_PTR("stream not defined", procName, NULL); + + if (fscanf(fp, "\n Pta Version %d\n", &version) != 1) + return (PTA *)ERROR_PTR("not a pta file", procName, NULL); + if (version != PTA_VERSION_NUMBER) + return (PTA *)ERROR_PTR("invalid pta version", procName, NULL); + if (fscanf(fp, " Number of pts = %d; format = %127s\n", &n, typestr) != 2) + return (PTA *)ERROR_PTR("not a pta file", procName, NULL); + if (n < 0) + return (PTA *)ERROR_PTR("num pts <= 0", procName, NULL); + if (n > MaxArraySize) + return (PTA *)ERROR_PTR("too many pts", procName, NULL); + if (n == 0) L_INFO("the pta is empty\n", procName); + + if (!strcmp(typestr, "float")) + type = 0; + else /* typestr is "integer" */ + type = 1; + if ((pta = ptaCreate(n)) == NULL) + return (PTA *)ERROR_PTR("pta not made", procName, NULL); + for (i = 0; i < n; i++) { + if (type == 0) { /* data is float */ + if (fscanf(fp, " (%f, %f)\n", &x, &y) != 2) { + ptaDestroy(&pta); + return (PTA *)ERROR_PTR("error reading floats", procName, NULL); + } + ptaAddPt(pta, x, y); + } else { /* data is integer */ + if (fscanf(fp, " (%d, %d)\n", &ix, &iy) != 2) { + ptaDestroy(&pta); + return (PTA *)ERROR_PTR("error reading ints", procName, NULL); + } + ptaAddPt(pta, ix, iy); + } + } + + return pta; +} + + +/*! + * \brief ptaReadMem() + * + * \param[in] data serialization in ascii + * \param[in] size of data in bytes; can use strlen to get it + * \return pta, or NULL on error + */ +PTA * +ptaReadMem(const l_uint8 *data, + size_t size) +{ +FILE *fp; +PTA *pta; + + PROCNAME("ptaReadMem"); + + if (!data) + return (PTA *)ERROR_PTR("data not defined", procName, NULL); + if ((fp = fopenReadFromMemory(data, size)) == NULL) + return (PTA *)ERROR_PTR("stream not opened", procName, NULL); + + pta = ptaReadStream(fp); + fclose(fp); + if (!pta) L_ERROR("pta not read\n", procName); + return pta; +} + + +/*! + * \brief ptaWriteDebug() + * + * \param[in] filename + * \param[in] pta + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Debug version, intended for use in the library when writing + * to files in a temp directory with names that are compiled in. + * This is used instead of ptaWrite() for all such library calls. + * (2) The global variable LeptDebugOK defaults to 0, and can be set + * or cleared by the function setLeptDebugOK(). + * </pre> + */ +l_ok +ptaWriteDebug(const char *filename, + PTA *pta, + l_int32 type) +{ + PROCNAME("ptaWriteDebug"); + + if (LeptDebugOK) { + return ptaWrite(filename, pta, type); + } else { + L_INFO("write to named temp file %s is disabled\n", procName, filename); + return 0; + } +} + + +/*! + * \brief ptaWrite() + * + * \param[in] filename + * \param[in] pta + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK, 1 on error + */ +l_ok +ptaWrite(const char *filename, + PTA *pta, + l_int32 type) +{ +l_int32 ret; +FILE *fp; + + PROCNAME("ptaWrite"); + + if (!filename) + return ERROR_INT("filename not defined", procName, 1); + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + + if ((fp = fopenWriteStream(filename, "w")) == NULL) + return ERROR_INT("stream not opened", procName, 1); + ret = ptaWriteStream(fp, pta, type); + fclose(fp); + if (ret) + return ERROR_INT("pta not written to stream", procName, 1); + return 0; +} + + +/*! + * \brief ptaWriteStream() + * + * \param[in] fp file stream + * \param[in] pta + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK; 1 on error + */ +l_ok +ptaWriteStream(FILE *fp, + PTA *pta, + l_int32 type) +{ +l_int32 i, n, ix, iy; +l_float32 x, y; + + PROCNAME("ptaWriteStream"); + + if (!fp) + return ERROR_INT("stream not defined", procName, 1); + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + + n = ptaGetCount(pta); + fprintf(fp, "\n Pta Version %d\n", PTA_VERSION_NUMBER); + if (type == 0) + fprintf(fp, " Number of pts = %d; format = float\n", n); + else /* type == 1 */ + fprintf(fp, " Number of pts = %d; format = integer\n", n); + for (i = 0; i < n; i++) { + if (type == 0) { /* data is float */ + ptaGetPt(pta, i, &x, &y); + fprintf(fp, " (%f, %f)\n", x, y); + } else { /* data is integer */ + ptaGetIPt(pta, i, &ix, &iy); + fprintf(fp, " (%d, %d)\n", ix, iy); + } + } + + return 0; +} + + +/*! + * \brief ptaWriteMem() + * + * \param[out] pdata data of serialized pta; ascii + * \param[out] psize size of returned data + * \param[in] pta + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Serializes a pta in memory and puts the result in a buffer. + * </pre> + */ +l_ok +ptaWriteMem(l_uint8 **pdata, + size_t *psize, + PTA *pta, + l_int32 type) +{ +l_int32 ret; +FILE *fp; + + PROCNAME("ptaWriteMem"); + + if (pdata) *pdata = NULL; + if (psize) *psize = 0; + if (!pdata) + return ERROR_INT("&data not defined", procName, 1); + if (!psize) + return ERROR_INT("&size not defined", procName, 1); + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + +#if HAVE_FMEMOPEN + if ((fp = open_memstream((char **)pdata, psize)) == NULL) + return ERROR_INT("stream not opened", procName, 1); + ret = ptaWriteStream(fp, pta, type); +#else + L_INFO("work-around: writing to a temp file\n", procName); + #ifdef _WIN32 + if ((fp = fopenWriteWinTempfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", procName, 1); + #else + if ((fp = tmpfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", procName, 1); + #endif /* _WIN32 */ + ret = ptaWriteStream(fp, pta, type); + rewind(fp); + *pdata = l_binaryReadStream(fp, psize); +#endif /* HAVE_FMEMOPEN */ + fclose(fp); + return ret; +} + + +/*---------------------------------------------------------------------* + * PTAA creation, destruction * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaaCreate() + * + * \param[in] n initial number of ptrs + * \return ptaa, or NULL on error + */ +PTAA * +ptaaCreate(l_int32 n) +{ +PTAA *ptaa; + + PROCNAME("ptaaCreate"); + + if (n <= 0 || n > MaxPtrArraySize) + n = InitialArraySize; + + ptaa = (PTAA *)LEPT_CALLOC(1, sizeof(PTAA)); + ptaa->n = 0; + ptaa->nalloc = n; + if ((ptaa->pta = (PTA **)LEPT_CALLOC(n, sizeof(PTA *))) == NULL) { + ptaaDestroy(&ptaa); + return (PTAA *)ERROR_PTR("pta ptrs not made", procName, NULL); + } + return ptaa; +} + + +/*! + * \brief ptaaDestroy() + * + * \param[in,out] pptaa will be set to null before returning + * \return void + */ +void +ptaaDestroy(PTAA **pptaa) +{ +l_int32 i; +PTAA *ptaa; + + PROCNAME("ptaaDestroy"); + + if (pptaa == NULL) { + L_WARNING("ptr address is NULL!\n", procName); + return; + } + + if ((ptaa = *pptaa) == NULL) + return; + + for (i = 0; i < ptaa->n; i++) + ptaDestroy(&ptaa->pta[i]); + LEPT_FREE(ptaa->pta); + LEPT_FREE(ptaa); + *pptaa = NULL; +} + + +/*---------------------------------------------------------------------* + * PTAA array extension * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaaAddPta() + * + * \param[in] ptaa + * \param[in] pta to be added + * \param[in] copyflag L_INSERT, L_COPY, L_CLONE + * \return 0 if OK, 1 on error + */ +l_ok +ptaaAddPta(PTAA *ptaa, + PTA *pta, + l_int32 copyflag) +{ +l_int32 n; +PTA *ptac; + + PROCNAME("ptaaAddPta"); + + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + + if (copyflag == L_INSERT) { + ptac = pta; + } else if (copyflag == L_COPY) { + if ((ptac = ptaCopy(pta)) == NULL) + return ERROR_INT("ptac not made", procName, 1); + } else if (copyflag == L_CLONE) { + if ((ptac = ptaClone(pta)) == NULL) + return ERROR_INT("pta clone not made", procName, 1); + } else { + return ERROR_INT("invalid copyflag", procName, 1); + } + + n = ptaaGetCount(ptaa); + if (n >= ptaa->nalloc) { + if (ptaaExtendArray(ptaa)) { + if (copyflag != L_INSERT) + ptaDestroy(&ptac); + return ERROR_INT("extension failed", procName, 1); + } + } + + ptaa->pta[n] = ptac; + ptaa->n++; + return 0; +} + + +/*! + * \brief ptaaExtendArray() + * + * \param[in] ptaa + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This doubles the pta ptr array size. + * (2) The max number of pta ptrs is 10M. + * </pre> + * + */ +static l_int32 +ptaaExtendArray(PTAA *ptaa) +{ +size_t oldsize, newsize; + + PROCNAME("ptaaExtendArray"); + + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + oldsize = ptaa->nalloc * sizeof(PTA *); + newsize = 2 * oldsize; + if (newsize > 8 * MaxPtrArraySize) + return ERROR_INT("newsize > 80 MB; too large", procName, 1); + + if ((ptaa->pta = (PTA **)reallocNew((void **)&ptaa->pta, + oldsize, newsize)) == NULL) + return ERROR_INT("new ptr array not returned", procName, 1); + + ptaa->nalloc *= 2; + return 0; +} + + +/*---------------------------------------------------------------------* + * Ptaa accessors * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaaGetCount() + * + * \param[in] ptaa + * \return count, or 0 if no ptaa + */ +l_int32 +ptaaGetCount(PTAA *ptaa) +{ + PROCNAME("ptaaGetCount"); + + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 0); + + return ptaa->n; +} + + +/*! + * \brief ptaaGetPta() + * + * \param[in] ptaa + * \param[in] index to the i-th pta + * \param[in] accessflag L_COPY or L_CLONE + * \return pta, or NULL on error + */ +PTA * +ptaaGetPta(PTAA *ptaa, + l_int32 index, + l_int32 accessflag) +{ + PROCNAME("ptaaGetPta"); + + if (!ptaa) + return (PTA *)ERROR_PTR("ptaa not defined", procName, NULL); + if (index < 0 || index >= ptaa->n) + return (PTA *)ERROR_PTR("index not valid", procName, NULL); + + if (accessflag == L_COPY) + return ptaCopy(ptaa->pta[index]); + else if (accessflag == L_CLONE) + return ptaClone(ptaa->pta[index]); + else + return (PTA *)ERROR_PTR("invalid accessflag", procName, NULL); +} + + +/*! + * \brief ptaaGetPt() + * + * \param[in] ptaa + * \param[in] ipta to the i-th pta + * \param[in] jpt index to the j-th pt in the pta + * \param[out] px [optional] float x value + * \param[out] py [optional] float y value + * \return 0 if OK; 1 on error + */ +l_ok +ptaaGetPt(PTAA *ptaa, + l_int32 ipta, + l_int32 jpt, + l_float32 *px, + l_float32 *py) +{ +PTA *pta; + + PROCNAME("ptaaGetPt"); + + if (px) *px = 0; + if (py) *py = 0; + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + if (ipta < 0 || ipta >= ptaa->n) + return ERROR_INT("index ipta not valid", procName, 1); + + pta = ptaaGetPta(ptaa, ipta, L_CLONE); + if (jpt < 0 || jpt >= pta->n) { + ptaDestroy(&pta); + return ERROR_INT("index jpt not valid", procName, 1); + } + + ptaGetPt(pta, jpt, px, py); + ptaDestroy(&pta); + return 0; +} + + +/*---------------------------------------------------------------------* + * Ptaa array modifiers * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaaInitFull() + * + * \param[in] ptaa can have non-null ptrs in the ptr array + * \param[in] pta to be replicated into the entire ptr array + * \return 0 if OK; 1 on error + */ +l_ok +ptaaInitFull(PTAA *ptaa, + PTA *pta) +{ +l_int32 n, i; +PTA *ptat; + + PROCNAME("ptaaInitFull"); + + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + + n = ptaa->nalloc; + ptaa->n = n; + for (i = 0; i < n; i++) { + ptat = ptaCopy(pta); + ptaaReplacePta(ptaa, i, ptat); + } + return 0; +} + + +/*! + * \brief ptaaReplacePta() + * + * \param[in] ptaa + * \param[in] index to the index-th pta + * \param[in] pta insert and replace any existing one + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Any existing pta is destroyed, and the input one + * is inserted in its place. + * (2) If %index is invalid, return 1 (error) + * </pre> + */ +l_ok +ptaaReplacePta(PTAA *ptaa, + l_int32 index, + PTA *pta) +{ +l_int32 n; + + PROCNAME("ptaaReplacePta"); + + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + if (!pta) + return ERROR_INT("pta not defined", procName, 1); + n = ptaaGetCount(ptaa); + if (index < 0 || index >= n) + return ERROR_INT("index not valid", procName, 1); + + ptaDestroy(&ptaa->pta[index]); + ptaa->pta[index] = pta; + return 0; +} + + +/*! + * \brief ptaaAddPt() + * + * \param[in] ptaa + * \param[in] ipta to the i-th pta + * \param[in] x,y point coordinates + * \return 0 if OK; 1 on error + */ +l_ok +ptaaAddPt(PTAA *ptaa, + l_int32 ipta, + l_float32 x, + l_float32 y) +{ +PTA *pta; + + PROCNAME("ptaaAddPt"); + + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + if (ipta < 0 || ipta >= ptaa->n) + return ERROR_INT("index ipta not valid", procName, 1); + + pta = ptaaGetPta(ptaa, ipta, L_CLONE); + ptaAddPt(pta, x, y); + ptaDestroy(&pta); + return 0; +} + + +/*! + * \brief ptaaTruncate() + * + * \param[in] ptaa + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) This identifies the largest index containing a pta that + * has any points within it, destroys all pta above that index, + * and resets the count. + * </pre> + */ +l_ok +ptaaTruncate(PTAA *ptaa) +{ +l_int32 i, n, np; +PTA *pta; + + PROCNAME("ptaaTruncate"); + + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + + n = ptaaGetCount(ptaa); + for (i = n - 1; i >= 0; i--) { + pta = ptaaGetPta(ptaa, i, L_CLONE); + if (!pta) { + ptaa->n--; + continue; + } + np = ptaGetCount(pta); + ptaDestroy(&pta); + if (np == 0) { + ptaDestroy(&ptaa->pta[i]); + ptaa->n--; + } else { + break; + } + } + return 0; +} + + +/*---------------------------------------------------------------------* + * Ptaa serialized for I/O * + *---------------------------------------------------------------------*/ +/*! + * \brief ptaaRead() + * + * \param[in] filename + * \return ptaa, or NULL on error + */ +PTAA * +ptaaRead(const char *filename) +{ +FILE *fp; +PTAA *ptaa; + + PROCNAME("ptaaRead"); + + if (!filename) + return (PTAA *)ERROR_PTR("filename not defined", procName, NULL); + + if ((fp = fopenReadStream(filename)) == NULL) + return (PTAA *)ERROR_PTR("stream not opened", procName, NULL); + ptaa = ptaaReadStream(fp); + fclose(fp); + if (!ptaa) + return (PTAA *)ERROR_PTR("ptaa not read", procName, NULL); + return ptaa; +} + + +/*! + * \brief ptaaReadStream() + * + * \param[in] fp file stream + * \return ptaa, or NULL on error + * + * <pre> + * Notes: + * (1) It is OK for the ptaa to be empty (n == 0). + * </pre> + */ +PTAA * +ptaaReadStream(FILE *fp) +{ +l_int32 i, n, version; +PTA *pta; +PTAA *ptaa; + + PROCNAME("ptaaReadStream"); + + if (!fp) + return (PTAA *)ERROR_PTR("stream not defined", procName, NULL); + + if (fscanf(fp, "\nPtaa Version %d\n", &version) != 1) + return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL); + if (version != PTA_VERSION_NUMBER) + return (PTAA *)ERROR_PTR("invalid ptaa version", procName, NULL); + if (fscanf(fp, "Number of Pta = %d\n", &n) != 1) + return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL); + if (n < 0) + return (PTAA *)ERROR_PTR("num pta ptrs <= 0", procName, NULL); + if (n > MaxPtrArraySize) + return (PTAA *)ERROR_PTR("too many pta ptrs", procName, NULL); + if (n == 0) L_INFO("the ptaa is empty\n", procName); + + if ((ptaa = ptaaCreate(n)) == NULL) + return (PTAA *)ERROR_PTR("ptaa not made", procName, NULL); + for (i = 0; i < n; i++) { + if ((pta = ptaReadStream(fp)) == NULL) { + ptaaDestroy(&ptaa); + return (PTAA *)ERROR_PTR("error reading pta", procName, NULL); + } + ptaaAddPta(ptaa, pta, L_INSERT); + } + + return ptaa; +} + + +/*! + * \brief ptaaReadMem() + * + * \param[in] data serialization in ascii + * \param[in] size of data in bytes; can use strlen to get it + * \return ptaa, or NULL on error + */ +PTAA * +ptaaReadMem(const l_uint8 *data, + size_t size) +{ +FILE *fp; +PTAA *ptaa; + + PROCNAME("ptaaReadMem"); + + if (!data) + return (PTAA *)ERROR_PTR("data not defined", procName, NULL); + if ((fp = fopenReadFromMemory(data, size)) == NULL) + return (PTAA *)ERROR_PTR("stream not opened", procName, NULL); + + ptaa = ptaaReadStream(fp); + fclose(fp); + if (!ptaa) L_ERROR("ptaa not read\n", procName); + return ptaa; +} + + +/*! + * \brief ptaaWriteDebug() + * + * \param[in] filename + * \param[in] ptaa + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Debug version, intended for use in the library when writing + * to files in a temp directory with names that are compiled in. + * This is used instead of ptaaWrite() for all such library calls. + * (2) The global variable LeptDebugOK defaults to 0, and can be set + * or cleared by the function setLeptDebugOK(). + * </pre> + */ +l_ok +ptaaWriteDebug(const char *filename, + PTAA *ptaa, + l_int32 type) +{ + PROCNAME("ptaaWriteDebug"); + + if (LeptDebugOK) { + return ptaaWrite(filename, ptaa, type); + } else { + L_INFO("write to named temp file %s is disabled\n", procName, filename); + return 0; + } +} + + +/*! + * \brief ptaaWrite() + * + * \param[in] filename + * \param[in] ptaa + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK, 1 on error + */ +l_ok +ptaaWrite(const char *filename, + PTAA *ptaa, + l_int32 type) +{ +l_int32 ret; +FILE *fp; + + PROCNAME("ptaaWrite"); + + if (!filename) + return ERROR_INT("filename not defined", procName, 1); + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + + if ((fp = fopenWriteStream(filename, "w")) == NULL) + return ERROR_INT("stream not opened", procName, 1); + ret = ptaaWriteStream(fp, ptaa, type); + fclose(fp); + if (ret) + return ERROR_INT("ptaa not written to stream", procName, 1); + return 0; +} + + +/*! + * \brief ptaaWriteStream() + * + * \param[in] fp file stream + * \param[in] ptaa + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK; 1 on error + */ +l_ok +ptaaWriteStream(FILE *fp, + PTAA *ptaa, + l_int32 type) +{ +l_int32 i, n; +PTA *pta; + + PROCNAME("ptaaWriteStream"); + + if (!fp) + return ERROR_INT("stream not defined", procName, 1); + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + + n = ptaaGetCount(ptaa); + fprintf(fp, "\nPtaa Version %d\n", PTA_VERSION_NUMBER); + fprintf(fp, "Number of Pta = %d\n", n); + for (i = 0; i < n; i++) { + pta = ptaaGetPta(ptaa, i, L_CLONE); + ptaWriteStream(fp, pta, type); + ptaDestroy(&pta); + } + + return 0; +} + + +/*! + * \brief ptaaWriteMem() + * + * \param[out] pdata data of serialized ptaa; ascii + * \param[out] psize size of returned data + * \param[in] ptaa + * \param[in] type 0 for float values; 1 for integer values + * \return 0 if OK, 1 on error + * + * <pre> + * Notes: + * (1) Serializes %ptaa in memory and puts the result in a buffer. + * </pre> + */ +l_ok +ptaaWriteMem(l_uint8 **pdata, + size_t *psize, + PTAA *ptaa, + l_int32 type) +{ +l_int32 ret; +FILE *fp; + + PROCNAME("ptaaWriteMem"); + + if (pdata) *pdata = NULL; + if (psize) *psize = 0; + if (!pdata) + return ERROR_INT("&data not defined", procName, 1); + if (!psize) + return ERROR_INT("&size not defined", procName, 1); + if (!ptaa) + return ERROR_INT("ptaa not defined", procName, 1); + +#if HAVE_FMEMOPEN + if ((fp = open_memstream((char **)pdata, psize)) == NULL) + return ERROR_INT("stream not opened", procName, 1); + ret = ptaaWriteStream(fp, ptaa, type); +#else + L_INFO("work-around: writing to a temp file\n", procName); + #ifdef _WIN32 + if ((fp = fopenWriteWinTempfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", procName, 1); + #else + if ((fp = tmpfile()) == NULL) + return ERROR_INT("tmpfile stream not opened", procName, 1); + #endif /* _WIN32 */ + ret = ptaaWriteStream(fp, ptaa, type); + rewind(fp); + *pdata = l_binaryReadStream(fp, psize); +#endif /* HAVE_FMEMOPEN */ + fclose(fp); + return ret; +} |