/src/leptonica/src/ptabasic.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
27 | | /*! |
28 | | * \file ptabasic.c |
29 | | * <pre> |
30 | | * |
31 | | * Pta creation, destruction, copy, clone, empty |
32 | | * PTA *ptaCreate() |
33 | | * PTA *ptaCreateFromNuma() |
34 | | * void ptaDestroy() |
35 | | * PTA *ptaCopy() |
36 | | * PTA *ptaCopyRange() |
37 | | * PTA *ptaClone() |
38 | | * l_int32 ptaEmpty() |
39 | | * |
40 | | * Pta array extension |
41 | | * l_int32 ptaAddPt() |
42 | | * static l_int32 ptaExtendArrays() |
43 | | * |
44 | | * Pta insertion and removal |
45 | | * l_int32 ptaInsertPt() |
46 | | * l_int32 ptaRemovePt() |
47 | | * |
48 | | * Pta accessors |
49 | | * l_int32 ptaGetCount() |
50 | | * l_int32 ptaGetPt() |
51 | | * l_int32 ptaGetIPt() |
52 | | * l_int32 ptaSetPt() |
53 | | * l_int32 ptaGetArrays() |
54 | | * |
55 | | * Pta serialized for I/O |
56 | | * PTA *ptaRead() |
57 | | * PTA *ptaReadStream() |
58 | | * PTA *ptaReadMem() |
59 | | * l_int32 ptaWriteDebug() |
60 | | * l_int32 ptaWrite() |
61 | | * l_int32 ptaWriteStream() |
62 | | * l_int32 ptaWriteMem() |
63 | | * |
64 | | * Ptaa creation, destruction |
65 | | * PTAA *ptaaCreate() |
66 | | * void ptaaDestroy() |
67 | | * |
68 | | * Ptaa array extension |
69 | | * l_int32 ptaaAddPta() |
70 | | * static l_int32 ptaaExtendArray() |
71 | | * |
72 | | * Ptaa accessors |
73 | | * l_int32 ptaaGetCount() |
74 | | * l_int32 ptaaGetPta() |
75 | | * l_int32 ptaaGetPt() |
76 | | * |
77 | | * Ptaa array modifiers |
78 | | * l_int32 ptaaInitFull() |
79 | | * l_int32 ptaaReplacePta() |
80 | | * l_int32 ptaaAddPt() |
81 | | * l_int32 ptaaTruncate() |
82 | | * |
83 | | * Ptaa serialized for I/O |
84 | | * PTAA *ptaaRead() |
85 | | * PTAA *ptaaReadStream() |
86 | | * PTAA *ptaaReadMem() |
87 | | * l_int32 ptaaWrite() |
88 | | * l_int32 ptaaWriteStream() |
89 | | * l_int32 ptaaWriteMem() |
90 | | * </pre> |
91 | | */ |
92 | | |
93 | | #ifdef HAVE_CONFIG_H |
94 | | #include <config_auto.h> |
95 | | #endif /* HAVE_CONFIG_H */ |
96 | | |
97 | | #include <string.h> |
98 | | #include "allheaders.h" |
99 | | #include "array_internal.h" |
100 | | #include "pix_internal.h" |
101 | | |
102 | | static const l_uint32 MaxArraySize = 100000000; /* 100 million */ |
103 | | static const l_uint32 MaxPtrArraySize = 10000000; /* 10 million */ |
104 | | static const l_int32 InitialArraySize = 50; /*!< n'importe quoi */ |
105 | | |
106 | | /* Static functions */ |
107 | | static l_int32 ptaExtendArrays(PTA *pta); |
108 | | static l_int32 ptaaExtendArray(PTAA *ptaa); |
109 | | |
110 | | /*---------------------------------------------------------------------* |
111 | | * Pta creation, destruction, copy, clone * |
112 | | *---------------------------------------------------------------------*/ |
113 | | /*! |
114 | | * \brief ptaCreate() |
115 | | * |
116 | | * \param[in] n initial array sizes |
117 | | * \return pta, or NULL on error. |
118 | | */ |
119 | | PTA * |
120 | | ptaCreate(l_int32 n) |
121 | 0 | { |
122 | 0 | PTA *pta; |
123 | |
|
124 | 0 | if (n <= 0 || n > (l_int32)MaxArraySize) |
125 | 0 | n = InitialArraySize; |
126 | |
|
127 | 0 | pta = (PTA *)LEPT_CALLOC(1, sizeof(PTA)); |
128 | 0 | pta->n = 0; |
129 | 0 | pta->nalloc = n; |
130 | 0 | pta->refcount = 1; |
131 | 0 | pta->x = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32)); |
132 | 0 | pta->y = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32)); |
133 | 0 | if (!pta->x || !pta->y) { |
134 | 0 | ptaDestroy(&pta); |
135 | 0 | return (PTA *)ERROR_PTR("x and y arrays not both made", __func__, NULL); |
136 | 0 | } |
137 | | |
138 | 0 | return pta; |
139 | 0 | } |
140 | | |
141 | | |
142 | | /*! |
143 | | * \brief ptaCreateFromNuma() |
144 | | * |
145 | | * \param[in] nax [optional] can be null |
146 | | * \param[in] nay |
147 | | * \return pta, or NULL on error. |
148 | | */ |
149 | | PTA * |
150 | | ptaCreateFromNuma(NUMA *nax, |
151 | | NUMA *nay) |
152 | 0 | { |
153 | 0 | l_int32 i, n; |
154 | 0 | l_float32 startx, delx, xval, yval; |
155 | 0 | PTA *pta; |
156 | |
|
157 | 0 | if (!nay) |
158 | 0 | return (PTA *)ERROR_PTR("nay not defined", __func__, NULL); |
159 | 0 | n = numaGetCount(nay); |
160 | 0 | if (nax && numaGetCount(nax) != n) |
161 | 0 | return (PTA *)ERROR_PTR("nax and nay sizes differ", __func__, NULL); |
162 | | |
163 | 0 | pta = ptaCreate(n); |
164 | 0 | numaGetParameters(nay, &startx, &delx); |
165 | 0 | for (i = 0; i < n; i++) { |
166 | 0 | if (nax) |
167 | 0 | numaGetFValue(nax, i, &xval); |
168 | 0 | else /* use implicit x values from nay */ |
169 | 0 | xval = startx + i * delx; |
170 | 0 | numaGetFValue(nay, i, &yval); |
171 | 0 | ptaAddPt(pta, xval, yval); |
172 | 0 | } |
173 | |
|
174 | 0 | return pta; |
175 | 0 | } |
176 | | |
177 | | |
178 | | /*! |
179 | | * \brief ptaDestroy() |
180 | | * |
181 | | * \param[in,out] ppta will be set to null before returning |
182 | | * \return void |
183 | | * |
184 | | * <pre> |
185 | | * Notes: |
186 | | * (1) Decrements the ref count and, if 0, destroys the pta. |
187 | | * (2) Always nulls the input ptr. |
188 | | * </pre> |
189 | | */ |
190 | | void |
191 | | ptaDestroy(PTA **ppta) |
192 | 0 | { |
193 | 0 | PTA *pta; |
194 | |
|
195 | 0 | if (ppta == NULL) { |
196 | 0 | L_WARNING("ptr address is NULL!\n", __func__); |
197 | 0 | return; |
198 | 0 | } |
199 | | |
200 | 0 | if ((pta = *ppta) == NULL) |
201 | 0 | return; |
202 | | |
203 | 0 | if (--pta->refcount == 0) { |
204 | 0 | LEPT_FREE(pta->x); |
205 | 0 | LEPT_FREE(pta->y); |
206 | 0 | LEPT_FREE(pta); |
207 | 0 | } |
208 | 0 | *ppta = NULL; |
209 | 0 | } |
210 | | |
211 | | |
212 | | /*! |
213 | | * \brief ptaCopy() |
214 | | * |
215 | | * \param[in] pta |
216 | | * \return copy of pta, or NULL on error |
217 | | */ |
218 | | PTA * |
219 | | ptaCopy(PTA *pta) |
220 | 0 | { |
221 | 0 | l_int32 i; |
222 | 0 | l_float32 x, y; |
223 | 0 | PTA *npta; |
224 | |
|
225 | 0 | if (!pta) |
226 | 0 | return (PTA *)ERROR_PTR("pta not defined", __func__, NULL); |
227 | | |
228 | 0 | if ((npta = ptaCreate(pta->nalloc)) == NULL) |
229 | 0 | return (PTA *)ERROR_PTR("npta not made", __func__, NULL); |
230 | | |
231 | 0 | for (i = 0; i < pta->n; i++) { |
232 | 0 | ptaGetPt(pta, i, &x, &y); |
233 | 0 | ptaAddPt(npta, x, y); |
234 | 0 | } |
235 | |
|
236 | 0 | return npta; |
237 | 0 | } |
238 | | |
239 | | |
240 | | /*! |
241 | | * \brief ptaCopyRange() |
242 | | * |
243 | | * \param[in] ptas |
244 | | * \param[in] istart starting index in ptas |
245 | | * \param[in] iend ending index in ptas; use 0 to copy to end |
246 | | * \return 0 if OK, 1 on error |
247 | | */ |
248 | | PTA * |
249 | | ptaCopyRange(PTA *ptas, |
250 | | l_int32 istart, |
251 | | l_int32 iend) |
252 | 0 | { |
253 | 0 | l_int32 n, i, x, y; |
254 | 0 | PTA *ptad; |
255 | |
|
256 | 0 | if (!ptas) |
257 | 0 | return (PTA *)ERROR_PTR("ptas not defined", __func__, NULL); |
258 | 0 | n = ptaGetCount(ptas); |
259 | 0 | if (istart < 0) |
260 | 0 | istart = 0; |
261 | 0 | if (istart >= n) |
262 | 0 | return (PTA *)ERROR_PTR("istart out of bounds", __func__, NULL); |
263 | 0 | if (iend <= 0 || iend >= n) |
264 | 0 | iend = n - 1; |
265 | 0 | if (istart > iend) |
266 | 0 | return (PTA *)ERROR_PTR("istart > iend; no pts", __func__, NULL); |
267 | | |
268 | 0 | if ((ptad = ptaCreate(iend - istart + 1)) == NULL) |
269 | 0 | return (PTA *)ERROR_PTR("ptad not made", __func__, NULL); |
270 | 0 | for (i = istart; i <= iend; i++) { |
271 | 0 | ptaGetIPt(ptas, i, &x, &y); |
272 | 0 | ptaAddPt(ptad, x, y); |
273 | 0 | } |
274 | |
|
275 | 0 | return ptad; |
276 | 0 | } |
277 | | |
278 | | |
279 | | /*! |
280 | | * \brief ptaClone() |
281 | | * |
282 | | * \param[in] pta |
283 | | * \return ptr to same pta, or NULL on error |
284 | | */ |
285 | | PTA * |
286 | | ptaClone(PTA *pta) |
287 | 0 | { |
288 | 0 | if (!pta) |
289 | 0 | return (PTA *)ERROR_PTR("pta not defined", __func__, NULL); |
290 | | |
291 | 0 | ++pta->refcount; |
292 | 0 | return pta; |
293 | 0 | } |
294 | | |
295 | | |
296 | | /*! |
297 | | * \brief ptaEmpty() |
298 | | * |
299 | | * \param[in] pta |
300 | | * \return 0 if OK, 1 on error |
301 | | * |
302 | | * <pre> |
303 | | * Notes: |
304 | | * This only resets the Pta::n field, for reuse |
305 | | * </pre> |
306 | | */ |
307 | | l_ok |
308 | | ptaEmpty(PTA *pta) |
309 | 0 | { |
310 | 0 | if (!pta) |
311 | 0 | return ERROR_INT("ptad not defined", __func__, 1); |
312 | 0 | pta->n = 0; |
313 | 0 | return 0; |
314 | 0 | } |
315 | | |
316 | | |
317 | | /*---------------------------------------------------------------------* |
318 | | * Pta array extension * |
319 | | *---------------------------------------------------------------------*/ |
320 | | /*! |
321 | | * \brief ptaAddPt() |
322 | | * |
323 | | * \param[in] pta |
324 | | * \param[in] x, y |
325 | | * \return 0 if OK, 1 on error |
326 | | */ |
327 | | l_ok |
328 | | ptaAddPt(PTA *pta, |
329 | | l_float32 x, |
330 | | l_float32 y) |
331 | 0 | { |
332 | 0 | l_int32 n; |
333 | |
|
334 | 0 | if (!pta) |
335 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
336 | | |
337 | 0 | n = pta->n; |
338 | 0 | if (n >= pta->nalloc) { |
339 | 0 | if (ptaExtendArrays(pta)) |
340 | 0 | return ERROR_INT("extension failed", __func__, 1); |
341 | 0 | } |
342 | | |
343 | 0 | pta->x[n] = x; |
344 | 0 | pta->y[n] = y; |
345 | 0 | pta->n++; |
346 | 0 | return 0; |
347 | 0 | } |
348 | | |
349 | | |
350 | | /*! |
351 | | * \brief ptaExtendArrays() |
352 | | * |
353 | | * \param[in] pta |
354 | | * \return 0 if OK; 1 on error |
355 | | * |
356 | | * <pre> |
357 | | * Notes: |
358 | | * (1) Doubles the size of the array. |
359 | | * (2) The max number of points is 100M. |
360 | | * </pre> |
361 | | */ |
362 | | static l_int32 |
363 | | ptaExtendArrays(PTA *pta) |
364 | 0 | { |
365 | 0 | size_t oldsize, newsize; |
366 | |
|
367 | 0 | if (!pta) |
368 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
369 | 0 | if (pta->nalloc > (l_int32)MaxArraySize) /* belt & suspenders */ |
370 | 0 | return ERROR_INT("pta at maximum size; can't extend", __func__, 1); |
371 | 0 | oldsize = 4 * pta->nalloc; |
372 | 0 | if (pta->nalloc > MaxArraySize / 2) { |
373 | 0 | newsize = 4 * MaxArraySize; |
374 | 0 | pta->nalloc = MaxArraySize; |
375 | 0 | } else { |
376 | 0 | newsize = 2 * oldsize; |
377 | 0 | pta->nalloc *= 2; |
378 | 0 | } |
379 | 0 | if ((pta->x = (l_float32 *)reallocNew((void **)&pta->x, |
380 | 0 | oldsize, newsize)) == NULL) |
381 | 0 | return ERROR_INT("new x array not returned", __func__, 1); |
382 | 0 | if ((pta->y = (l_float32 *)reallocNew((void **)&pta->y, |
383 | 0 | oldsize, newsize)) == NULL) |
384 | 0 | return ERROR_INT("new y array not returned", __func__, 1); |
385 | | |
386 | 0 | return 0; |
387 | 0 | } |
388 | | |
389 | | |
390 | | /*---------------------------------------------------------------------* |
391 | | * Pta insertion and removal * |
392 | | *---------------------------------------------------------------------*/ |
393 | | /*! |
394 | | * \brief ptaInsertPt() |
395 | | * |
396 | | * \param[in] pta |
397 | | * \param[in] index at which pt is to be inserted |
398 | | * \param[in] x, y point values |
399 | | * \return 0 if OK; 1 on error |
400 | | */ |
401 | | l_ok |
402 | | ptaInsertPt(PTA *pta, |
403 | | l_int32 index, |
404 | | l_int32 x, |
405 | | l_int32 y) |
406 | 0 | { |
407 | 0 | l_int32 i, n; |
408 | |
|
409 | 0 | if (!pta) |
410 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
411 | 0 | n = ptaGetCount(pta); |
412 | 0 | if (index < 0 || index > n) { |
413 | 0 | L_ERROR("index %d not in [0,...,%d]\n", __func__, index, n); |
414 | 0 | return 1; |
415 | 0 | } |
416 | | |
417 | 0 | if (n > pta->nalloc) { |
418 | 0 | if (ptaExtendArrays(pta)) |
419 | 0 | return ERROR_INT("extension failed", __func__, 1); |
420 | 0 | } |
421 | 0 | pta->n++; |
422 | 0 | for (i = n; i > index; i--) { |
423 | 0 | pta->x[i] = pta->x[i - 1]; |
424 | 0 | pta->y[i] = pta->y[i - 1]; |
425 | 0 | } |
426 | 0 | pta->x[index] = x; |
427 | 0 | pta->y[index] = y; |
428 | 0 | return 0; |
429 | 0 | } |
430 | | |
431 | | |
432 | | /*! |
433 | | * \brief ptaRemovePt() |
434 | | * |
435 | | * \param[in] pta |
436 | | * \param[in] index of point to be removed |
437 | | * \return 0 if OK, 1 on error |
438 | | * |
439 | | * <pre> |
440 | | * Notes: |
441 | | * (1) This shifts pta[i] --> pta[i - 1] for all i > index. |
442 | | * (2) It should not be used repeatedly on large arrays, |
443 | | * because the function is O(n). |
444 | | * </pre> |
445 | | */ |
446 | | l_ok |
447 | | ptaRemovePt(PTA *pta, |
448 | | l_int32 index) |
449 | 0 | { |
450 | 0 | l_int32 i, n; |
451 | |
|
452 | 0 | if (!pta) |
453 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
454 | 0 | n = ptaGetCount(pta); |
455 | 0 | if (index < 0 || index >= n) { |
456 | 0 | L_ERROR("index %d not in [0,...,%d]\n", __func__, index, n - 1); |
457 | 0 | return 1; |
458 | 0 | } |
459 | | |
460 | | /* Remove the point */ |
461 | 0 | for (i = index + 1; i < n; i++) { |
462 | 0 | pta->x[i - 1] = pta->x[i]; |
463 | 0 | pta->y[i - 1] = pta->y[i]; |
464 | 0 | } |
465 | 0 | pta->n--; |
466 | 0 | return 0; |
467 | 0 | } |
468 | | |
469 | | |
470 | | /*---------------------------------------------------------------------* |
471 | | * Pta accessors * |
472 | | *---------------------------------------------------------------------*/ |
473 | | /*! |
474 | | * \brief ptaGetCount() |
475 | | * |
476 | | * \param[in] pta |
477 | | * \return count, or 0 if no pta |
478 | | */ |
479 | | l_int32 |
480 | | ptaGetCount(PTA *pta) |
481 | 0 | { |
482 | 0 | if (!pta) |
483 | 0 | return ERROR_INT("pta not defined", __func__, 0); |
484 | | |
485 | 0 | return pta->n; |
486 | 0 | } |
487 | | |
488 | | |
489 | | /*! |
490 | | * \brief ptaGetPt() |
491 | | * |
492 | | * \param[in] pta |
493 | | * \param[in] index into arrays |
494 | | * \param[out] px [optional] float x value |
495 | | * \param[out] py [optional] float y value |
496 | | * \return 0 if OK; 1 on error |
497 | | */ |
498 | | l_ok |
499 | | ptaGetPt(PTA *pta, |
500 | | l_int32 index, |
501 | | l_float32 *px, |
502 | | l_float32 *py) |
503 | 0 | { |
504 | 0 | if (px) *px = 0; |
505 | 0 | if (py) *py = 0; |
506 | 0 | if (!pta) |
507 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
508 | 0 | if (index < 0 || index >= pta->n) |
509 | 0 | return ERROR_INT("invalid index", __func__, 1); |
510 | | |
511 | 0 | if (px) *px = pta->x[index]; |
512 | 0 | if (py) *py = pta->y[index]; |
513 | 0 | return 0; |
514 | 0 | } |
515 | | |
516 | | |
517 | | /*! |
518 | | * \brief ptaGetIPt() |
519 | | * |
520 | | * \param[in] pta |
521 | | * \param[in] index into arrays |
522 | | * \param[out] px [optional] integer x value |
523 | | * \param[out] py [optional] integer y value |
524 | | * \return 0 if OK; 1 on error |
525 | | */ |
526 | | l_ok |
527 | | ptaGetIPt(PTA *pta, |
528 | | l_int32 index, |
529 | | l_int32 *px, |
530 | | l_int32 *py) |
531 | 0 | { |
532 | 0 | if (px) *px = 0; |
533 | 0 | if (py) *py = 0; |
534 | 0 | if (!pta) |
535 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
536 | 0 | if (index < 0 || index >= pta->n) |
537 | 0 | return ERROR_INT("invalid index", __func__, 1); |
538 | | |
539 | 0 | if (px) *px = (l_int32)(pta->x[index] + 0.5); |
540 | 0 | if (py) *py = (l_int32)(pta->y[index] + 0.5); |
541 | 0 | return 0; |
542 | 0 | } |
543 | | |
544 | | |
545 | | /*! |
546 | | * \brief ptaSetPt() |
547 | | * |
548 | | * \param[in] pta |
549 | | * \param[in] index into arrays |
550 | | * \param[in] x, y |
551 | | * \return 0 if OK; 1 on error |
552 | | */ |
553 | | l_ok |
554 | | ptaSetPt(PTA *pta, |
555 | | l_int32 index, |
556 | | l_float32 x, |
557 | | l_float32 y) |
558 | 0 | { |
559 | 0 | if (!pta) |
560 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
561 | 0 | if (index < 0 || index >= pta->n) |
562 | 0 | return ERROR_INT("invalid index", __func__, 1); |
563 | | |
564 | 0 | pta->x[index] = x; |
565 | 0 | pta->y[index] = y; |
566 | 0 | return 0; |
567 | 0 | } |
568 | | |
569 | | |
570 | | /*! |
571 | | * \brief ptaGetArrays() |
572 | | * |
573 | | * \param[in] pta |
574 | | * \param[out] pnax [optional] numa of x array |
575 | | * \param[out] pnay [optional] numa of y array |
576 | | * \return 0 if OK; 1 on error or if pta is empty |
577 | | * |
578 | | * <pre> |
579 | | * Notes: |
580 | | * (1) This copies the internal arrays into new Numas. |
581 | | * </pre> |
582 | | */ |
583 | | l_ok |
584 | | ptaGetArrays(PTA *pta, |
585 | | NUMA **pnax, |
586 | | NUMA **pnay) |
587 | 0 | { |
588 | 0 | l_int32 i, n; |
589 | 0 | NUMA *nax, *nay; |
590 | |
|
591 | 0 | if (!pnax && !pnay) |
592 | 0 | return ERROR_INT("no output requested", __func__, 1); |
593 | 0 | if (pnax) *pnax = NULL; |
594 | 0 | if (pnay) *pnay = NULL; |
595 | 0 | if (!pta) |
596 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
597 | 0 | if ((n = ptaGetCount(pta)) == 0) |
598 | 0 | return ERROR_INT("pta is empty", __func__, 1); |
599 | | |
600 | 0 | if (pnax) { |
601 | 0 | if ((nax = numaCreate(n)) == NULL) |
602 | 0 | return ERROR_INT("nax not made", __func__, 1); |
603 | 0 | *pnax = nax; |
604 | 0 | for (i = 0; i < n; i++) |
605 | 0 | nax->array[i] = pta->x[i]; |
606 | 0 | nax->n = n; |
607 | 0 | } |
608 | 0 | if (pnay) { |
609 | 0 | if ((nay = numaCreate(n)) == NULL) |
610 | 0 | return ERROR_INT("nay not made", __func__, 1); |
611 | 0 | *pnay = nay; |
612 | 0 | for (i = 0; i < n; i++) |
613 | 0 | nay->array[i] = pta->y[i]; |
614 | 0 | nay->n = n; |
615 | 0 | } |
616 | 0 | return 0; |
617 | 0 | } |
618 | | |
619 | | |
620 | | /*---------------------------------------------------------------------* |
621 | | * Pta serialized for I/O * |
622 | | *---------------------------------------------------------------------*/ |
623 | | /*! |
624 | | * \brief ptaRead() |
625 | | * |
626 | | * \param[in] filename |
627 | | * \return pta, or NULL on error |
628 | | */ |
629 | | PTA * |
630 | | ptaRead(const char *filename) |
631 | 0 | { |
632 | 0 | FILE *fp; |
633 | 0 | PTA *pta; |
634 | |
|
635 | 0 | if (!filename) |
636 | 0 | return (PTA *)ERROR_PTR("filename not defined", __func__, NULL); |
637 | | |
638 | 0 | if ((fp = fopenReadStream(filename)) == NULL) |
639 | 0 | return (PTA *)ERROR_PTR_1("stream not opened", |
640 | 0 | filename, __func__, NULL); |
641 | 0 | pta = ptaReadStream(fp); |
642 | 0 | fclose(fp); |
643 | 0 | if (!pta) |
644 | 0 | return (PTA *)ERROR_PTR_1("pta not read", filename, __func__, NULL); |
645 | 0 | return pta; |
646 | 0 | } |
647 | | |
648 | | |
649 | | /*! |
650 | | * \brief ptaReadStream() |
651 | | * |
652 | | * \param[in] fp file stream |
653 | | * \return pta, or NULL on error |
654 | | * |
655 | | * <pre> |
656 | | * Notes: |
657 | | * (1) It is OK for the pta to be empty (n == 0). |
658 | | * </pre> |
659 | | |
660 | | */ |
661 | | PTA * |
662 | | ptaReadStream(FILE *fp) |
663 | 0 | { |
664 | 0 | char typestr[128]; /* hardcoded below in fscanf */ |
665 | 0 | l_int32 i, n, ix, iy, type, version; |
666 | 0 | l_float32 x, y; |
667 | 0 | PTA *pta; |
668 | |
|
669 | 0 | if (!fp) |
670 | 0 | return (PTA *)ERROR_PTR("stream not defined", __func__, NULL); |
671 | | |
672 | 0 | if (fscanf(fp, "\n Pta Version %d\n", &version) != 1) |
673 | 0 | return (PTA *)ERROR_PTR("not a pta file", __func__, NULL); |
674 | 0 | if (version != PTA_VERSION_NUMBER) |
675 | 0 | return (PTA *)ERROR_PTR("invalid pta version", __func__, NULL); |
676 | 0 | if (fscanf(fp, " Number of pts = %d; format = %127s\n", &n, typestr) != 2) |
677 | 0 | return (PTA *)ERROR_PTR("not a pta file", __func__, NULL); |
678 | 0 | if (n < 0) |
679 | 0 | return (PTA *)ERROR_PTR("num pts <= 0", __func__, NULL); |
680 | 0 | if (n > (l_int32)MaxArraySize) |
681 | 0 | return (PTA *)ERROR_PTR("too many pts", __func__, NULL); |
682 | 0 | if (n == 0) L_INFO("the pta is empty\n", __func__); |
683 | |
|
684 | 0 | if (!strcmp(typestr, "float")) |
685 | 0 | type = 0; |
686 | 0 | else /* typestr is "integer" */ |
687 | 0 | type = 1; |
688 | 0 | if ((pta = ptaCreate(n)) == NULL) |
689 | 0 | return (PTA *)ERROR_PTR("pta not made", __func__, NULL); |
690 | 0 | for (i = 0; i < n; i++) { |
691 | 0 | if (type == 0) { /* data is float */ |
692 | 0 | if (fscanf(fp, " (%f, %f)\n", &x, &y) != 2) { |
693 | 0 | ptaDestroy(&pta); |
694 | 0 | return (PTA *)ERROR_PTR("error reading floats", __func__, NULL); |
695 | 0 | } |
696 | 0 | ptaAddPt(pta, x, y); |
697 | 0 | } else { /* data is integer */ |
698 | 0 | if (fscanf(fp, " (%d, %d)\n", &ix, &iy) != 2) { |
699 | 0 | ptaDestroy(&pta); |
700 | 0 | return (PTA *)ERROR_PTR("error reading ints", __func__, NULL); |
701 | 0 | } |
702 | 0 | ptaAddPt(pta, ix, iy); |
703 | 0 | } |
704 | 0 | } |
705 | | |
706 | 0 | return pta; |
707 | 0 | } |
708 | | |
709 | | |
710 | | /*! |
711 | | * \brief ptaReadMem() |
712 | | * |
713 | | * \param[in] data serialization in ascii |
714 | | * \param[in] size of data in bytes; can use strlen to get it |
715 | | * \return pta, or NULL on error |
716 | | */ |
717 | | PTA * |
718 | | ptaReadMem(const l_uint8 *data, |
719 | | size_t size) |
720 | 0 | { |
721 | 0 | FILE *fp; |
722 | 0 | PTA *pta; |
723 | |
|
724 | 0 | if (!data) |
725 | 0 | return (PTA *)ERROR_PTR("data not defined", __func__, NULL); |
726 | 0 | if ((fp = fopenReadFromMemory(data, size)) == NULL) |
727 | 0 | return (PTA *)ERROR_PTR("stream not opened", __func__, NULL); |
728 | | |
729 | 0 | pta = ptaReadStream(fp); |
730 | 0 | fclose(fp); |
731 | 0 | if (!pta) L_ERROR("pta not read\n", __func__); |
732 | 0 | return pta; |
733 | 0 | } |
734 | | |
735 | | |
736 | | /*! |
737 | | * \brief ptaWriteDebug() |
738 | | * |
739 | | * \param[in] filename |
740 | | * \param[in] pta |
741 | | * \param[in] type 0 for float values; 1 for integer values |
742 | | * \return 0 if OK, 1 on error |
743 | | * |
744 | | * <pre> |
745 | | * Notes: |
746 | | * (1) Debug version, intended for use in the library when writing |
747 | | * to files in a temp directory with names that are compiled in. |
748 | | * This is used instead of ptaWrite() for all such library calls. |
749 | | * (2) The global variable LeptDebugOK defaults to 0, and can be set |
750 | | * or cleared by the function setLeptDebugOK(). |
751 | | * </pre> |
752 | | */ |
753 | | l_ok |
754 | | ptaWriteDebug(const char *filename, |
755 | | PTA *pta, |
756 | | l_int32 type) |
757 | 0 | { |
758 | 0 | if (LeptDebugOK) { |
759 | 0 | return ptaWrite(filename, pta, type); |
760 | 0 | } else { |
761 | 0 | L_INFO("write to named temp file %s is disabled\n", __func__, filename); |
762 | 0 | return 0; |
763 | 0 | } |
764 | 0 | } |
765 | | |
766 | | |
767 | | /*! |
768 | | * \brief ptaWrite() |
769 | | * |
770 | | * \param[in] filename |
771 | | * \param[in] pta |
772 | | * \param[in] type 0 for float values; 1 for integer values |
773 | | * \return 0 if OK, 1 on error |
774 | | */ |
775 | | l_ok |
776 | | ptaWrite(const char *filename, |
777 | | PTA *pta, |
778 | | l_int32 type) |
779 | 0 | { |
780 | 0 | l_int32 ret; |
781 | 0 | FILE *fp; |
782 | |
|
783 | 0 | if (!filename) |
784 | 0 | return ERROR_INT("filename not defined", __func__, 1); |
785 | 0 | if (!pta) |
786 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
787 | | |
788 | 0 | if ((fp = fopenWriteStream(filename, "w")) == NULL) |
789 | 0 | return ERROR_INT_1("stream not opened", filename, __func__, 1); |
790 | 0 | ret = ptaWriteStream(fp, pta, type); |
791 | 0 | fclose(fp); |
792 | 0 | if (ret) |
793 | 0 | return ERROR_INT_1("pta not written to stream", filename, __func__, 1); |
794 | 0 | return 0; |
795 | 0 | } |
796 | | |
797 | | |
798 | | /*! |
799 | | * \brief ptaWriteStream() |
800 | | * |
801 | | * \param[in] fp file stream |
802 | | * \param[in] pta |
803 | | * \param[in] type 0 for float values; 1 for integer values |
804 | | * \return 0 if OK; 1 on error |
805 | | */ |
806 | | l_ok |
807 | | ptaWriteStream(FILE *fp, |
808 | | PTA *pta, |
809 | | l_int32 type) |
810 | 0 | { |
811 | 0 | l_int32 i, n, ix, iy; |
812 | 0 | l_float32 x, y; |
813 | |
|
814 | 0 | if (!fp) |
815 | 0 | return ERROR_INT("stream not defined", __func__, 1); |
816 | 0 | if (!pta) |
817 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
818 | | |
819 | 0 | n = ptaGetCount(pta); |
820 | 0 | fprintf(fp, "\n Pta Version %d\n", PTA_VERSION_NUMBER); |
821 | 0 | if (type == 0) |
822 | 0 | fprintf(fp, " Number of pts = %d; format = float\n", n); |
823 | 0 | else /* type == 1 */ |
824 | 0 | fprintf(fp, " Number of pts = %d; format = integer\n", n); |
825 | 0 | for (i = 0; i < n; i++) { |
826 | 0 | if (type == 0) { /* data is float */ |
827 | 0 | ptaGetPt(pta, i, &x, &y); |
828 | 0 | fprintf(fp, " (%f, %f)\n", x, y); |
829 | 0 | } else { /* data is integer */ |
830 | 0 | ptaGetIPt(pta, i, &ix, &iy); |
831 | 0 | fprintf(fp, " (%d, %d)\n", ix, iy); |
832 | 0 | } |
833 | 0 | } |
834 | |
|
835 | 0 | return 0; |
836 | 0 | } |
837 | | |
838 | | |
839 | | /*! |
840 | | * \brief ptaWriteMem() |
841 | | * |
842 | | * \param[out] pdata data of serialized pta; ascii |
843 | | * \param[out] psize size of returned data |
844 | | * \param[in] pta |
845 | | * \param[in] type 0 for float values; 1 for integer values |
846 | | * \return 0 if OK, 1 on error |
847 | | * |
848 | | * <pre> |
849 | | * Notes: |
850 | | * (1) Serializes a pta in memory and puts the result in a buffer. |
851 | | * </pre> |
852 | | */ |
853 | | l_ok |
854 | | ptaWriteMem(l_uint8 **pdata, |
855 | | size_t *psize, |
856 | | PTA *pta, |
857 | | l_int32 type) |
858 | 0 | { |
859 | 0 | l_int32 ret; |
860 | 0 | FILE *fp; |
861 | |
|
862 | 0 | if (pdata) *pdata = NULL; |
863 | 0 | if (psize) *psize = 0; |
864 | 0 | if (!pdata) |
865 | 0 | return ERROR_INT("&data not defined", __func__, 1); |
866 | 0 | if (!psize) |
867 | 0 | return ERROR_INT("&size not defined", __func__, 1); |
868 | 0 | if (!pta) |
869 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
870 | | |
871 | 0 | #if HAVE_FMEMOPEN |
872 | 0 | if ((fp = open_memstream((char **)pdata, psize)) == NULL) |
873 | 0 | return ERROR_INT("stream not opened", __func__, 1); |
874 | 0 | ret = ptaWriteStream(fp, pta, type); |
875 | 0 | fputc('\0', fp); |
876 | 0 | fclose(fp); |
877 | 0 | *psize = *psize - 1; |
878 | | #else |
879 | | L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__); |
880 | | #ifdef _WIN32 |
881 | | if ((fp = fopenWriteWinTempfile()) == NULL) |
882 | | return ERROR_INT("tmpfile stream not opened", __func__, 1); |
883 | | #else |
884 | | if ((fp = tmpfile()) == NULL) |
885 | | return ERROR_INT("tmpfile stream not opened", __func__, 1); |
886 | | #endif /* _WIN32 */ |
887 | | ret = ptaWriteStream(fp, pta, type); |
888 | | rewind(fp); |
889 | | *pdata = l_binaryReadStream(fp, psize); |
890 | | fclose(fp); |
891 | | #endif /* HAVE_FMEMOPEN */ |
892 | 0 | return ret; |
893 | 0 | } |
894 | | |
895 | | |
896 | | /*---------------------------------------------------------------------* |
897 | | * PTAA creation, destruction * |
898 | | *---------------------------------------------------------------------*/ |
899 | | /*! |
900 | | * \brief ptaaCreate() |
901 | | * |
902 | | * \param[in] n initial number of ptrs |
903 | | * \return ptaa, or NULL on error |
904 | | */ |
905 | | PTAA * |
906 | | ptaaCreate(l_int32 n) |
907 | 0 | { |
908 | 0 | PTAA *ptaa; |
909 | |
|
910 | 0 | if (n <= 0 || n > (l_int32)MaxPtrArraySize) |
911 | 0 | n = InitialArraySize; |
912 | |
|
913 | 0 | ptaa = (PTAA *)LEPT_CALLOC(1, sizeof(PTAA)); |
914 | 0 | ptaa->n = 0; |
915 | 0 | ptaa->nalloc = n; |
916 | 0 | if ((ptaa->pta = (PTA **)LEPT_CALLOC(n, sizeof(PTA *))) == NULL) { |
917 | 0 | ptaaDestroy(&ptaa); |
918 | 0 | return (PTAA *)ERROR_PTR("pta ptrs not made", __func__, NULL); |
919 | 0 | } |
920 | 0 | return ptaa; |
921 | 0 | } |
922 | | |
923 | | |
924 | | /*! |
925 | | * \brief ptaaDestroy() |
926 | | * |
927 | | * \param[in,out] pptaa will be set to null before returning |
928 | | * \return void |
929 | | */ |
930 | | void |
931 | | ptaaDestroy(PTAA **pptaa) |
932 | 0 | { |
933 | 0 | l_int32 i; |
934 | 0 | PTAA *ptaa; |
935 | |
|
936 | 0 | if (pptaa == NULL) { |
937 | 0 | L_WARNING("ptr address is NULL!\n", __func__); |
938 | 0 | return; |
939 | 0 | } |
940 | | |
941 | 0 | if ((ptaa = *pptaa) == NULL) |
942 | 0 | return; |
943 | | |
944 | 0 | for (i = 0; i < ptaa->n; i++) |
945 | 0 | ptaDestroy(&ptaa->pta[i]); |
946 | 0 | LEPT_FREE(ptaa->pta); |
947 | 0 | LEPT_FREE(ptaa); |
948 | 0 | *pptaa = NULL; |
949 | 0 | } |
950 | | |
951 | | |
952 | | /*---------------------------------------------------------------------* |
953 | | * PTAA array extension * |
954 | | *---------------------------------------------------------------------*/ |
955 | | /*! |
956 | | * \brief ptaaAddPta() |
957 | | * |
958 | | * \param[in] ptaa |
959 | | * \param[in] pta to be added |
960 | | * \param[in] copyflag L_INSERT, L_COPY, L_CLONE |
961 | | * \return 0 if OK, 1 on error |
962 | | */ |
963 | | l_ok |
964 | | ptaaAddPta(PTAA *ptaa, |
965 | | PTA *pta, |
966 | | l_int32 copyflag) |
967 | 0 | { |
968 | 0 | l_int32 n; |
969 | 0 | PTA *ptac; |
970 | |
|
971 | 0 | if (!ptaa) |
972 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
973 | 0 | if (!pta) |
974 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
975 | | |
976 | 0 | if (copyflag == L_INSERT) { |
977 | 0 | ptac = pta; |
978 | 0 | } else if (copyflag == L_COPY) { |
979 | 0 | if ((ptac = ptaCopy(pta)) == NULL) |
980 | 0 | return ERROR_INT("ptac not made", __func__, 1); |
981 | 0 | } else if (copyflag == L_CLONE) { |
982 | 0 | if ((ptac = ptaClone(pta)) == NULL) |
983 | 0 | return ERROR_INT("pta clone not made", __func__, 1); |
984 | 0 | } else { |
985 | 0 | return ERROR_INT("invalid copyflag", __func__, 1); |
986 | 0 | } |
987 | | |
988 | 0 | n = ptaaGetCount(ptaa); |
989 | 0 | if (n >= ptaa->nalloc) { |
990 | 0 | if (ptaaExtendArray(ptaa)) { |
991 | 0 | if (copyflag != L_INSERT) |
992 | 0 | ptaDestroy(&ptac); |
993 | 0 | return ERROR_INT("extension failed", __func__, 1); |
994 | 0 | } |
995 | 0 | } |
996 | | |
997 | 0 | ptaa->pta[n] = ptac; |
998 | 0 | ptaa->n++; |
999 | 0 | return 0; |
1000 | 0 | } |
1001 | | |
1002 | | |
1003 | | /*! |
1004 | | * \brief ptaaExtendArray() |
1005 | | * |
1006 | | * \param[in] ptaa |
1007 | | * \return 0 if OK, 1 on error |
1008 | | * |
1009 | | * <pre> |
1010 | | * Notes: |
1011 | | * (1) This doubles the pta ptr array size. |
1012 | | * (2) The max number of pta ptrs is 10M. |
1013 | | * </pre> |
1014 | | * |
1015 | | */ |
1016 | | static l_int32 |
1017 | | ptaaExtendArray(PTAA *ptaa) |
1018 | 0 | { |
1019 | 0 | size_t oldsize, newsize; |
1020 | |
|
1021 | 0 | if (!ptaa) |
1022 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1023 | 0 | oldsize = ptaa->nalloc * sizeof(PTA *); |
1024 | 0 | newsize = 2 * oldsize; |
1025 | 0 | if (newsize > 8 * MaxPtrArraySize) |
1026 | 0 | return ERROR_INT("newsize > 80 MB; too large", __func__, 1); |
1027 | | |
1028 | 0 | if ((ptaa->pta = (PTA **)reallocNew((void **)&ptaa->pta, |
1029 | 0 | oldsize, newsize)) == NULL) |
1030 | 0 | return ERROR_INT("new ptr array not returned", __func__, 1); |
1031 | | |
1032 | 0 | ptaa->nalloc *= 2; |
1033 | 0 | return 0; |
1034 | 0 | } |
1035 | | |
1036 | | |
1037 | | /*---------------------------------------------------------------------* |
1038 | | * Ptaa accessors * |
1039 | | *---------------------------------------------------------------------*/ |
1040 | | /*! |
1041 | | * \brief ptaaGetCount() |
1042 | | * |
1043 | | * \param[in] ptaa |
1044 | | * \return count, or 0 if no ptaa |
1045 | | */ |
1046 | | l_int32 |
1047 | | ptaaGetCount(PTAA *ptaa) |
1048 | 0 | { |
1049 | 0 | if (!ptaa) |
1050 | 0 | return ERROR_INT("ptaa not defined", __func__, 0); |
1051 | | |
1052 | 0 | return ptaa->n; |
1053 | 0 | } |
1054 | | |
1055 | | |
1056 | | /*! |
1057 | | * \brief ptaaGetPta() |
1058 | | * |
1059 | | * \param[in] ptaa |
1060 | | * \param[in] index to the i-th pta |
1061 | | * \param[in] accessflag L_COPY or L_CLONE |
1062 | | * \return pta, or NULL on error |
1063 | | */ |
1064 | | PTA * |
1065 | | ptaaGetPta(PTAA *ptaa, |
1066 | | l_int32 index, |
1067 | | l_int32 accessflag) |
1068 | 0 | { |
1069 | 0 | if (!ptaa) |
1070 | 0 | return (PTA *)ERROR_PTR("ptaa not defined", __func__, NULL); |
1071 | 0 | if (index < 0 || index >= ptaa->n) |
1072 | 0 | return (PTA *)ERROR_PTR("index not valid", __func__, NULL); |
1073 | | |
1074 | 0 | if (accessflag == L_COPY) |
1075 | 0 | return ptaCopy(ptaa->pta[index]); |
1076 | 0 | else if (accessflag == L_CLONE) |
1077 | 0 | return ptaClone(ptaa->pta[index]); |
1078 | 0 | else |
1079 | 0 | return (PTA *)ERROR_PTR("invalid accessflag", __func__, NULL); |
1080 | 0 | } |
1081 | | |
1082 | | |
1083 | | /*! |
1084 | | * \brief ptaaGetPt() |
1085 | | * |
1086 | | * \param[in] ptaa |
1087 | | * \param[in] ipta to the i-th pta |
1088 | | * \param[in] jpt index to the j-th pt in the pta |
1089 | | * \param[out] px [optional] float x value |
1090 | | * \param[out] py [optional] float y value |
1091 | | * \return 0 if OK; 1 on error |
1092 | | */ |
1093 | | l_ok |
1094 | | ptaaGetPt(PTAA *ptaa, |
1095 | | l_int32 ipta, |
1096 | | l_int32 jpt, |
1097 | | l_float32 *px, |
1098 | | l_float32 *py) |
1099 | 0 | { |
1100 | 0 | PTA *pta; |
1101 | |
|
1102 | 0 | if (px) *px = 0; |
1103 | 0 | if (py) *py = 0; |
1104 | 0 | if (!ptaa) |
1105 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1106 | 0 | if (ipta < 0 || ipta >= ptaa->n) |
1107 | 0 | return ERROR_INT("index ipta not valid", __func__, 1); |
1108 | | |
1109 | 0 | pta = ptaaGetPta(ptaa, ipta, L_CLONE); |
1110 | 0 | if (jpt < 0 || jpt >= pta->n) { |
1111 | 0 | ptaDestroy(&pta); |
1112 | 0 | return ERROR_INT("index jpt not valid", __func__, 1); |
1113 | 0 | } |
1114 | | |
1115 | 0 | ptaGetPt(pta, jpt, px, py); |
1116 | 0 | ptaDestroy(&pta); |
1117 | 0 | return 0; |
1118 | 0 | } |
1119 | | |
1120 | | |
1121 | | /*---------------------------------------------------------------------* |
1122 | | * Ptaa array modifiers * |
1123 | | *---------------------------------------------------------------------*/ |
1124 | | /*! |
1125 | | * \brief ptaaInitFull() |
1126 | | * |
1127 | | * \param[in] ptaa can have non-null ptrs in the ptr array |
1128 | | * \param[in] pta to be replicated into the entire ptr array |
1129 | | * \return 0 if OK; 1 on error |
1130 | | */ |
1131 | | l_ok |
1132 | | ptaaInitFull(PTAA *ptaa, |
1133 | | PTA *pta) |
1134 | 0 | { |
1135 | 0 | l_int32 n, i; |
1136 | 0 | PTA *ptat; |
1137 | |
|
1138 | 0 | if (!ptaa) |
1139 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1140 | 0 | if (!pta) |
1141 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
1142 | | |
1143 | 0 | n = ptaa->nalloc; |
1144 | 0 | ptaa->n = n; |
1145 | 0 | for (i = 0; i < n; i++) { |
1146 | 0 | ptat = ptaCopy(pta); |
1147 | 0 | ptaaReplacePta(ptaa, i, ptat); |
1148 | 0 | } |
1149 | 0 | return 0; |
1150 | 0 | } |
1151 | | |
1152 | | |
1153 | | /*! |
1154 | | * \brief ptaaReplacePta() |
1155 | | * |
1156 | | * \param[in] ptaa |
1157 | | * \param[in] index to the index-th pta |
1158 | | * \param[in] pta insert and replace any existing one |
1159 | | * \return 0 if OK, 1 on error |
1160 | | * |
1161 | | * <pre> |
1162 | | * Notes: |
1163 | | * (1) Any existing pta is destroyed, and the input one |
1164 | | * is inserted in its place. |
1165 | | * (2) If %index is invalid, return 1 (error) |
1166 | | * </pre> |
1167 | | */ |
1168 | | l_ok |
1169 | | ptaaReplacePta(PTAA *ptaa, |
1170 | | l_int32 index, |
1171 | | PTA *pta) |
1172 | 0 | { |
1173 | 0 | l_int32 n; |
1174 | |
|
1175 | 0 | if (!ptaa) |
1176 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1177 | 0 | if (!pta) |
1178 | 0 | return ERROR_INT("pta not defined", __func__, 1); |
1179 | 0 | n = ptaaGetCount(ptaa); |
1180 | 0 | if (index < 0 || index >= n) |
1181 | 0 | return ERROR_INT("index not valid", __func__, 1); |
1182 | | |
1183 | 0 | ptaDestroy(&ptaa->pta[index]); |
1184 | 0 | ptaa->pta[index] = pta; |
1185 | 0 | return 0; |
1186 | 0 | } |
1187 | | |
1188 | | |
1189 | | /*! |
1190 | | * \brief ptaaAddPt() |
1191 | | * |
1192 | | * \param[in] ptaa |
1193 | | * \param[in] ipta to the i-th pta |
1194 | | * \param[in] x,y point coordinates |
1195 | | * \return 0 if OK; 1 on error |
1196 | | */ |
1197 | | l_ok |
1198 | | ptaaAddPt(PTAA *ptaa, |
1199 | | l_int32 ipta, |
1200 | | l_float32 x, |
1201 | | l_float32 y) |
1202 | 0 | { |
1203 | 0 | PTA *pta; |
1204 | |
|
1205 | 0 | if (!ptaa) |
1206 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1207 | 0 | if (ipta < 0 || ipta >= ptaa->n) |
1208 | 0 | return ERROR_INT("index ipta not valid", __func__, 1); |
1209 | | |
1210 | 0 | pta = ptaaGetPta(ptaa, ipta, L_CLONE); |
1211 | 0 | ptaAddPt(pta, x, y); |
1212 | 0 | ptaDestroy(&pta); |
1213 | 0 | return 0; |
1214 | 0 | } |
1215 | | |
1216 | | |
1217 | | /*! |
1218 | | * \brief ptaaTruncate() |
1219 | | * |
1220 | | * \param[in] ptaa |
1221 | | * \return 0 if OK, 1 on error |
1222 | | * |
1223 | | * <pre> |
1224 | | * Notes: |
1225 | | * (1) This identifies the largest index containing a pta that |
1226 | | * has any points within it, destroys all pta above that index, |
1227 | | * and resets the count. |
1228 | | * </pre> |
1229 | | */ |
1230 | | l_ok |
1231 | | ptaaTruncate(PTAA *ptaa) |
1232 | 0 | { |
1233 | 0 | l_int32 i, n, np; |
1234 | 0 | PTA *pta; |
1235 | |
|
1236 | 0 | if (!ptaa) |
1237 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1238 | | |
1239 | 0 | n = ptaaGetCount(ptaa); |
1240 | 0 | for (i = n - 1; i >= 0; i--) { |
1241 | 0 | pta = ptaaGetPta(ptaa, i, L_CLONE); |
1242 | 0 | if (!pta) { |
1243 | 0 | ptaa->n--; |
1244 | 0 | continue; |
1245 | 0 | } |
1246 | 0 | np = ptaGetCount(pta); |
1247 | 0 | ptaDestroy(&pta); |
1248 | 0 | if (np == 0) { |
1249 | 0 | ptaDestroy(&ptaa->pta[i]); |
1250 | 0 | ptaa->n--; |
1251 | 0 | } else { |
1252 | 0 | break; |
1253 | 0 | } |
1254 | 0 | } |
1255 | 0 | return 0; |
1256 | 0 | } |
1257 | | |
1258 | | |
1259 | | /*---------------------------------------------------------------------* |
1260 | | * Ptaa serialized for I/O * |
1261 | | *---------------------------------------------------------------------*/ |
1262 | | /*! |
1263 | | * \brief ptaaRead() |
1264 | | * |
1265 | | * \param[in] filename |
1266 | | * \return ptaa, or NULL on error |
1267 | | */ |
1268 | | PTAA * |
1269 | | ptaaRead(const char *filename) |
1270 | 0 | { |
1271 | 0 | FILE *fp; |
1272 | 0 | PTAA *ptaa; |
1273 | |
|
1274 | 0 | if (!filename) |
1275 | 0 | return (PTAA *)ERROR_PTR("filename not defined", __func__, NULL); |
1276 | | |
1277 | 0 | if ((fp = fopenReadStream(filename)) == NULL) |
1278 | 0 | return (PTAA *)ERROR_PTR_1("stream not opened", |
1279 | 0 | filename, __func__, NULL); |
1280 | 0 | ptaa = ptaaReadStream(fp); |
1281 | 0 | fclose(fp); |
1282 | 0 | if (!ptaa) |
1283 | 0 | return (PTAA *)ERROR_PTR_1("ptaa not read", filename, __func__, NULL); |
1284 | 0 | return ptaa; |
1285 | 0 | } |
1286 | | |
1287 | | |
1288 | | /*! |
1289 | | * \brief ptaaReadStream() |
1290 | | * |
1291 | | * \param[in] fp file stream |
1292 | | * \return ptaa, or NULL on error |
1293 | | * |
1294 | | * <pre> |
1295 | | * Notes: |
1296 | | * (1) It is OK for the ptaa to be empty (n == 0). |
1297 | | * </pre> |
1298 | | */ |
1299 | | PTAA * |
1300 | | ptaaReadStream(FILE *fp) |
1301 | 0 | { |
1302 | 0 | l_int32 i, n, version; |
1303 | 0 | PTA *pta; |
1304 | 0 | PTAA *ptaa; |
1305 | |
|
1306 | 0 | if (!fp) |
1307 | 0 | return (PTAA *)ERROR_PTR("stream not defined", __func__, NULL); |
1308 | | |
1309 | 0 | if (fscanf(fp, "\nPtaa Version %d\n", &version) != 1) |
1310 | 0 | return (PTAA *)ERROR_PTR("not a ptaa file", __func__, NULL); |
1311 | 0 | if (version != PTA_VERSION_NUMBER) |
1312 | 0 | return (PTAA *)ERROR_PTR("invalid ptaa version", __func__, NULL); |
1313 | 0 | if (fscanf(fp, "Number of Pta = %d\n", &n) != 1) |
1314 | 0 | return (PTAA *)ERROR_PTR("not a ptaa file", __func__, NULL); |
1315 | 0 | if (n < 0) |
1316 | 0 | return (PTAA *)ERROR_PTR("num pta ptrs <= 0", __func__, NULL); |
1317 | 0 | if (n > (l_int32)MaxPtrArraySize) |
1318 | 0 | return (PTAA *)ERROR_PTR("too many pta ptrs", __func__, NULL); |
1319 | 0 | if (n == 0) L_INFO("the ptaa is empty\n", __func__); |
1320 | |
|
1321 | 0 | if ((ptaa = ptaaCreate(n)) == NULL) |
1322 | 0 | return (PTAA *)ERROR_PTR("ptaa not made", __func__, NULL); |
1323 | 0 | for (i = 0; i < n; i++) { |
1324 | 0 | if ((pta = ptaReadStream(fp)) == NULL) { |
1325 | 0 | ptaaDestroy(&ptaa); |
1326 | 0 | return (PTAA *)ERROR_PTR("error reading pta", __func__, NULL); |
1327 | 0 | } |
1328 | 0 | ptaaAddPta(ptaa, pta, L_INSERT); |
1329 | 0 | } |
1330 | | |
1331 | 0 | return ptaa; |
1332 | 0 | } |
1333 | | |
1334 | | |
1335 | | /*! |
1336 | | * \brief ptaaReadMem() |
1337 | | * |
1338 | | * \param[in] data serialization in ascii |
1339 | | * \param[in] size of data in bytes; can use strlen to get it |
1340 | | * \return ptaa, or NULL on error |
1341 | | */ |
1342 | | PTAA * |
1343 | | ptaaReadMem(const l_uint8 *data, |
1344 | | size_t size) |
1345 | 0 | { |
1346 | 0 | FILE *fp; |
1347 | 0 | PTAA *ptaa; |
1348 | |
|
1349 | 0 | if (!data) |
1350 | 0 | return (PTAA *)ERROR_PTR("data not defined", __func__, NULL); |
1351 | 0 | if ((fp = fopenReadFromMemory(data, size)) == NULL) |
1352 | 0 | return (PTAA *)ERROR_PTR("stream not opened", __func__, NULL); |
1353 | | |
1354 | 0 | ptaa = ptaaReadStream(fp); |
1355 | 0 | fclose(fp); |
1356 | 0 | if (!ptaa) L_ERROR("ptaa not read\n", __func__); |
1357 | 0 | return ptaa; |
1358 | 0 | } |
1359 | | |
1360 | | |
1361 | | /*! |
1362 | | * \brief ptaaWriteDebug() |
1363 | | * |
1364 | | * \param[in] filename |
1365 | | * \param[in] ptaa |
1366 | | * \param[in] type 0 for float values; 1 for integer values |
1367 | | * \return 0 if OK, 1 on error |
1368 | | * |
1369 | | * <pre> |
1370 | | * Notes: |
1371 | | * (1) Debug version, intended for use in the library when writing |
1372 | | * to files in a temp directory with names that are compiled in. |
1373 | | * This is used instead of ptaaWrite() for all such library calls. |
1374 | | * (2) The global variable LeptDebugOK defaults to 0, and can be set |
1375 | | * or cleared by the function setLeptDebugOK(). |
1376 | | * </pre> |
1377 | | */ |
1378 | | l_ok |
1379 | | ptaaWriteDebug(const char *filename, |
1380 | | PTAA *ptaa, |
1381 | | l_int32 type) |
1382 | 0 | { |
1383 | 0 | if (LeptDebugOK) { |
1384 | 0 | return ptaaWrite(filename, ptaa, type); |
1385 | 0 | } else { |
1386 | 0 | L_INFO("write to named temp file %s is disabled\n", __func__, filename); |
1387 | 0 | return 0; |
1388 | 0 | } |
1389 | 0 | } |
1390 | | |
1391 | | |
1392 | | /*! |
1393 | | * \brief ptaaWrite() |
1394 | | * |
1395 | | * \param[in] filename |
1396 | | * \param[in] ptaa |
1397 | | * \param[in] type 0 for float values; 1 for integer values |
1398 | | * \return 0 if OK, 1 on error |
1399 | | */ |
1400 | | l_ok |
1401 | | ptaaWrite(const char *filename, |
1402 | | PTAA *ptaa, |
1403 | | l_int32 type) |
1404 | 0 | { |
1405 | 0 | l_int32 ret; |
1406 | 0 | FILE *fp; |
1407 | |
|
1408 | 0 | if (!filename) |
1409 | 0 | return ERROR_INT("filename not defined", __func__, 1); |
1410 | 0 | if (!ptaa) |
1411 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1412 | | |
1413 | 0 | if ((fp = fopenWriteStream(filename, "w")) == NULL) |
1414 | 0 | return ERROR_INT_1("stream not opened", filename, __func__, 1); |
1415 | 0 | ret = ptaaWriteStream(fp, ptaa, type); |
1416 | 0 | fclose(fp); |
1417 | 0 | if (ret) |
1418 | 0 | return ERROR_INT_1("ptaa not written to stream", filename, __func__, 1); |
1419 | 0 | return 0; |
1420 | 0 | } |
1421 | | |
1422 | | |
1423 | | /*! |
1424 | | * \brief ptaaWriteStream() |
1425 | | * |
1426 | | * \param[in] fp file stream |
1427 | | * \param[in] ptaa |
1428 | | * \param[in] type 0 for float values; 1 for integer values |
1429 | | * \return 0 if OK; 1 on error |
1430 | | */ |
1431 | | l_ok |
1432 | | ptaaWriteStream(FILE *fp, |
1433 | | PTAA *ptaa, |
1434 | | l_int32 type) |
1435 | 0 | { |
1436 | 0 | l_int32 i, n; |
1437 | 0 | PTA *pta; |
1438 | |
|
1439 | 0 | if (!fp) |
1440 | 0 | return ERROR_INT("stream not defined", __func__, 1); |
1441 | 0 | if (!ptaa) |
1442 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1443 | | |
1444 | 0 | n = ptaaGetCount(ptaa); |
1445 | 0 | fprintf(fp, "\nPtaa Version %d\n", PTA_VERSION_NUMBER); |
1446 | 0 | fprintf(fp, "Number of Pta = %d\n", n); |
1447 | 0 | for (i = 0; i < n; i++) { |
1448 | 0 | pta = ptaaGetPta(ptaa, i, L_CLONE); |
1449 | 0 | ptaWriteStream(fp, pta, type); |
1450 | 0 | ptaDestroy(&pta); |
1451 | 0 | } |
1452 | |
|
1453 | 0 | return 0; |
1454 | 0 | } |
1455 | | |
1456 | | |
1457 | | /*! |
1458 | | * \brief ptaaWriteMem() |
1459 | | * |
1460 | | * \param[out] pdata data of serialized ptaa; ascii |
1461 | | * \param[out] psize size of returned data |
1462 | | * \param[in] ptaa |
1463 | | * \param[in] type 0 for float values; 1 for integer values |
1464 | | * \return 0 if OK, 1 on error |
1465 | | * |
1466 | | * <pre> |
1467 | | * Notes: |
1468 | | * (1) Serializes %ptaa in memory and puts the result in a buffer. |
1469 | | * </pre> |
1470 | | */ |
1471 | | l_ok |
1472 | | ptaaWriteMem(l_uint8 **pdata, |
1473 | | size_t *psize, |
1474 | | PTAA *ptaa, |
1475 | | l_int32 type) |
1476 | 0 | { |
1477 | 0 | l_int32 ret; |
1478 | 0 | FILE *fp; |
1479 | |
|
1480 | 0 | if (pdata) *pdata = NULL; |
1481 | 0 | if (psize) *psize = 0; |
1482 | 0 | if (!pdata) |
1483 | 0 | return ERROR_INT("&data not defined", __func__, 1); |
1484 | 0 | if (!psize) |
1485 | 0 | return ERROR_INT("&size not defined", __func__, 1); |
1486 | 0 | if (!ptaa) |
1487 | 0 | return ERROR_INT("ptaa not defined", __func__, 1); |
1488 | | |
1489 | 0 | #if HAVE_FMEMOPEN |
1490 | 0 | if ((fp = open_memstream((char **)pdata, psize)) == NULL) |
1491 | 0 | return ERROR_INT("stream not opened", __func__, 1); |
1492 | 0 | ret = ptaaWriteStream(fp, ptaa, type); |
1493 | 0 | fputc('\0', fp); |
1494 | 0 | fclose(fp); |
1495 | 0 | *psize = *psize - 1; |
1496 | | #else |
1497 | | L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__); |
1498 | | #ifdef _WIN32 |
1499 | | if ((fp = fopenWriteWinTempfile()) == NULL) |
1500 | | return ERROR_INT("tmpfile stream not opened", __func__, 1); |
1501 | | #else |
1502 | | if ((fp = tmpfile()) == NULL) |
1503 | | return ERROR_INT("tmpfile stream not opened", __func__, 1); |
1504 | | #endif /* _WIN32 */ |
1505 | | ret = ptaaWriteStream(fp, ptaa, type); |
1506 | | rewind(fp); |
1507 | | *pdata = l_binaryReadStream(fp, psize); |
1508 | | fclose(fp); |
1509 | | #endif /* HAVE_FMEMOPEN */ |
1510 | 0 | return ret; |
1511 | 0 | } |