Leptonica  1.77.0
Image processing and image analysis suite
ptafunc2.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 
79 #include "allheaders.h"
80 
81 
82 /*---------------------------------------------------------------------*
83  * Sorting *
84  *---------------------------------------------------------------------*/
95 PTA *
96 ptaSort(PTA *ptas,
97  l_int32 sorttype,
98  l_int32 sortorder,
99  NUMA **pnaindex)
100 {
101 PTA *ptad;
102 NUMA *naindex;
103 
104  PROCNAME("ptaSort");
105 
106  if (pnaindex) *pnaindex = NULL;
107  if (!ptas)
108  return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
109  if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y)
110  return (PTA *)ERROR_PTR("invalid sort type", procName, NULL);
111  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
112  return (PTA *)ERROR_PTR("invalid sort order", procName, NULL);
113 
114  if (ptaGetSortIndex(ptas, sorttype, sortorder, &naindex) != 0)
115  return (PTA *)ERROR_PTR("naindex not made", procName, NULL);
116 
117  ptad = ptaSortByIndex(ptas, naindex);
118  if (pnaindex)
119  *pnaindex = naindex;
120  else
121  numaDestroy(&naindex);
122  if (!ptad)
123  return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
124  return ptad;
125 }
126 
127 
138 l_ok
140  l_int32 sorttype,
141  l_int32 sortorder,
142  NUMA **pnaindex)
143 {
144 l_int32 i, n;
145 l_float32 x, y;
146 NUMA *na;
147 
148  PROCNAME("ptaGetSortIndex");
149 
150  if (!pnaindex)
151  return ERROR_INT("&naindex not defined", procName, 1);
152  *pnaindex = NULL;
153  if (!ptas)
154  return ERROR_INT("ptas not defined", procName, 1);
155  if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y)
156  return ERROR_INT("invalid sort type", procName, 1);
157  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
158  return ERROR_INT("invalid sort order", procName, 1);
159 
160  /* Build up numa of specific data */
161  n = ptaGetCount(ptas);
162  if ((na = numaCreate(n)) == NULL)
163  return ERROR_INT("na not made", procName, 1);
164  for (i = 0; i < n; i++) {
165  ptaGetPt(ptas, i, &x, &y);
166  if (sorttype == L_SORT_BY_X)
167  numaAddNumber(na, x);
168  else
169  numaAddNumber(na, y);
170  }
171 
172  /* Get the sort index for data array */
173  *pnaindex = numaGetSortIndex(na, sortorder);
174  numaDestroy(&na);
175  if (!*pnaindex)
176  return ERROR_INT("naindex not made", procName, 1);
177  return 0;
178 }
179 
180 
188 PTA *
190  NUMA *naindex)
191 {
192 l_int32 i, index, n;
193 l_float32 x, y;
194 PTA *ptad;
195 
196  PROCNAME("ptaSortByIndex");
197 
198  if (!ptas)
199  return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
200  if (!naindex)
201  return (PTA *)ERROR_PTR("naindex not defined", procName, NULL);
202 
203  /* Build up sorted pta using sort index */
204  n = numaGetCount(naindex);
205  if ((ptad = ptaCreate(n)) == NULL)
206  return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
207  for (i = 0; i < n; i++) {
208  numaGetIValue(naindex, i, &index);
209  ptaGetPt(ptas, index, &x, &y);
210  ptaAddPt(ptad, x, y);
211  }
212 
213  return ptad;
214 }
215 
216 
224 PTAA *
226  NUMA *naindex)
227 {
228 l_int32 i, n, index;
229 PTA *pta;
230 PTAA *ptaad;
231 
232  PROCNAME("ptaaSortByIndex");
233 
234  if (!ptaas)
235  return (PTAA *)ERROR_PTR("ptaas not defined", procName, NULL);
236  if (!naindex)
237  return (PTAA *)ERROR_PTR("naindex not defined", procName, NULL);
238 
239  n = ptaaGetCount(ptaas);
240  if (numaGetCount(naindex) != n)
241  return (PTAA *)ERROR_PTR("numa and ptaa sizes differ", procName, NULL);
242  ptaad = ptaaCreate(n);
243  for (i = 0; i < n; i++) {
244  numaGetIValue(naindex, i, &index);
245  pta = ptaaGetPta(ptaas, index, L_COPY);
246  ptaaAddPta(ptaad, pta, L_INSERT);
247  }
248 
249  return ptaad;
250 }
251 
252 
263 l_ok
265  l_float32 fract,
266  PTA *ptasort,
267  l_int32 sorttype,
268  l_float32 *pval)
269 {
270 l_int32 index, n;
271 PTA *ptas;
272 
273  PROCNAME("ptaGetRankValue");
274 
275  if (!pval)
276  return ERROR_INT("&val not defined", procName, 1);
277  *pval = 0.0;
278  if (!pta)
279  return ERROR_INT("pta not defined", procName, 1);
280  if (sorttype != L_SORT_BY_X && sorttype != L_SORT_BY_Y)
281  return ERROR_INT("invalid sort type", procName, 1);
282  if (fract < 0.0 || fract > 1.0)
283  return ERROR_INT("fract not in [0.0 ... 1.0]", procName, 1);
284  if ((n = ptaGetCount(pta)) == 0)
285  return ERROR_INT("pta empty", procName, 1);
286 
287  if (ptasort)
288  ptas = ptasort;
289  else
290  ptas = ptaSort(pta, sorttype, L_SORT_INCREASING, NULL);
291 
292  index = (l_int32)(fract * (l_float32)(n - 1) + 0.5);
293  if (sorttype == L_SORT_BY_X)
294  ptaGetPt(ptas, index, pval, NULL);
295  else /* sort by y */
296  ptaGetPt(ptas, index, NULL, pval);
297 
298  if (!ptasort) ptaDestroy(&ptas);
299  return 0;
300 }
301 
302 
303 /*---------------------------------------------------------------------*
304  * Set operations using aset (rbtree) *
305  *---------------------------------------------------------------------*/
323 PTA *
325  PTA *pta2)
326 {
327 PTA *pta3, *ptad;
328 
329  PROCNAME("ptaUnionByAset");
330 
331  if (!pta1)
332  return (PTA *)ERROR_PTR("pta1 not defined", procName, NULL);
333  if (!pta2)
334  return (PTA *)ERROR_PTR("pta2 not defined", procName, NULL);
335 
336  /* Join */
337  pta3 = ptaCopy(pta1);
338  ptaJoin(pta3, pta2, 0, -1);
339 
340  /* Eliminate duplicates */
341  ptad = ptaRemoveDupsByAset(pta3);
342  ptaDestroy(&pta3);
343  return ptad;
344 }
345 
346 
360 PTA *
362 {
363 l_int32 i, n, x, y;
364 PTA *ptad;
365 l_uint64 hash;
366 L_ASET *set;
367 RB_TYPE key;
368 
369  PROCNAME("ptaRemoveDupsByAset");
370 
371  if (!ptas)
372  return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
373 
374  set = l_asetCreate(L_UINT_TYPE);
375  n = ptaGetCount(ptas);
376  ptad = ptaCreate(n);
377  for (i = 0; i < n; i++) {
378  ptaGetIPt(ptas, i, &x, &y);
379  l_hashPtToUint64(x, y, &hash);
380  key.utype = hash;
381  if (!l_asetFind(set, key)) {
382  ptaAddPt(ptad, x, y);
383  l_asetInsert(set, key);
384  }
385  }
386 
387  l_asetDestroy(&set);
388  return ptad;
389 }
390 
391 
407 PTA *
409  PTA *pta2)
410 {
411 l_int32 n1, n2, i, n, x, y;
412 l_uint64 hash;
413 L_ASET *set1, *set2;
414 RB_TYPE key;
415 PTA *pta_small, *pta_big, *ptad;
416 
417  PROCNAME("ptaIntersectionByAset");
418 
419  if (!pta1)
420  return (PTA *)ERROR_PTR("pta1 not defined", procName, NULL);
421  if (!pta2)
422  return (PTA *)ERROR_PTR("pta2 not defined", procName, NULL);
423 
424  /* Put the elements of the biggest array into a set */
425  n1 = ptaGetCount(pta1);
426  n2 = ptaGetCount(pta2);
427  pta_small = (n1 < n2) ? pta1 : pta2; /* do not destroy pta_small */
428  pta_big = (n1 < n2) ? pta2 : pta1; /* do not destroy pta_big */
429  set1 = l_asetCreateFromPta(pta_big);
430 
431  /* Build up the intersection of points */
432  ptad = ptaCreate(0);
433  n = ptaGetCount(pta_small);
434  set2 = l_asetCreate(L_UINT_TYPE);
435  for (i = 0; i < n; i++) {
436  ptaGetIPt(pta_small, i, &x, &y);
437  l_hashPtToUint64(x, y, &hash);
438  key.utype = hash;
439  if (l_asetFind(set1, key) && !l_asetFind(set2, key)) {
440  ptaAddPt(ptad, x, y);
441  l_asetInsert(set2, key);
442  }
443  }
444 
445  l_asetDestroy(&set1);
446  l_asetDestroy(&set2);
447  return ptad;
448 }
449 
450 
457 L_ASET *
459 {
460 l_int32 i, n, x, y;
461 l_uint64 hash;
462 L_ASET *set;
463 RB_TYPE key;
464 
465  PROCNAME("l_asetCreateFromPta");
466 
467  if (!pta)
468  return (L_ASET *)ERROR_PTR("pta not defined", procName, NULL);
469 
470  set = l_asetCreate(L_UINT_TYPE);
471  n = ptaGetCount(pta);
472  for (i = 0; i < n; i++) {
473  ptaGetIPt(pta, i, &x, &y);
474  l_hashPtToUint64(x, y, &hash);
475  key.utype = hash;
476  l_asetInsert(set, key);
477  }
478 
479  return set;
480 }
481 
482 
483 /*---------------------------------------------------------------------*
484  * Set operations using hashing (rbtree) *
485  *---------------------------------------------------------------------*/
499 PTA *
501  PTA *pta2)
502 {
503 PTA *pta3, *ptad;
504 
505  PROCNAME("ptaUnionByHash");
506 
507  if (!pta1)
508  return (PTA *)ERROR_PTR("pta1 not defined", procName, NULL);
509  if (!pta2)
510  return (PTA *)ERROR_PTR("pta2 not defined", procName, NULL);
511 
512  /* Join */
513  pta3 = ptaCopy(pta1);
514  ptaJoin(pta3, pta2, 0, -1);
515 
516  /* Eliminate duplicates */
517  ptaRemoveDupsByHash(pta3, &ptad, NULL);
518  ptaDestroy(&pta3);
519  return ptad;
520 }
521 
522 
549 l_ok
551  PTA **pptad,
552  L_DNAHASH **pdahash)
553 {
554 l_int32 i, n, index, items, x, y;
555 l_uint32 nsize;
556 l_uint64 key;
557 PTA *ptad;
558 L_DNAHASH *dahash;
559 
560  PROCNAME("ptaRemoveDupsByHash");
561 
562  if (pdahash) *pdahash = NULL;
563  if (!pptad)
564  return ERROR_INT("&ptad not defined", procName, 1);
565  *pptad = NULL;
566  if (!ptas)
567  return ERROR_INT("ptas not defined", procName, 1);
568 
569  n = ptaGetCount(ptas);
570  findNextLargerPrime(n / 20, &nsize); /* buckets in hash table */
571  dahash = l_dnaHashCreate(nsize, 8);
572  ptad = ptaCreate(n);
573  *pptad = ptad;
574  for (i = 0, items = 0; i < n; i++) {
575  ptaGetIPt(ptas, i, &x, &y);
576  ptaFindPtByHash(ptad, dahash, x, y, &index);
577  if (index < 0) { /* not found */
578  l_hashPtToUint64(x, y, &key);
579  l_dnaHashAdd(dahash, key, (l_float64)items);
580  ptaAddPt(ptad, x, y);
581  items++;
582  }
583  }
584 
585  if (pdahash)
586  *pdahash = dahash;
587  else
588  l_dnaHashDestroy(&dahash);
589  return 0;
590 }
591 
592 
606 PTA *
608  PTA *pta2)
609 {
610 l_int32 n1, n2, nsmall, i, x, y, index1, index2;
611 l_uint32 nsize2;
612 l_uint64 key;
613 L_DNAHASH *dahash1, *dahash2;
614 PTA *pta_small, *pta_big, *ptad;
615 
616  PROCNAME("ptaIntersectionByHash");
617 
618  if (!pta1)
619  return (PTA *)ERROR_PTR("pta1 not defined", procName, NULL);
620  if (!pta2)
621  return (PTA *)ERROR_PTR("pta2 not defined", procName, NULL);
622 
623  /* Put the elements of the biggest pta into a dnahash */
624  n1 = ptaGetCount(pta1);
625  n2 = ptaGetCount(pta2);
626  pta_small = (n1 < n2) ? pta1 : pta2; /* do not destroy pta_small */
627  pta_big = (n1 < n2) ? pta2 : pta1; /* do not destroy pta_big */
628  dahash1 = l_dnaHashCreateFromPta(pta_big);
629 
630  /* Build up the intersection of points. Add to ptad
631  * if the point is in pta_big (using dahash1) but hasn't
632  * yet been seen in the traversal of pta_small (using dahash2). */
633  ptad = ptaCreate(0);
634  nsmall = ptaGetCount(pta_small);
635  findNextLargerPrime(nsmall / 20, &nsize2); /* buckets in hash table */
636  dahash2 = l_dnaHashCreate(nsize2, 0);
637  for (i = 0; i < nsmall; i++) {
638  ptaGetIPt(pta_small, i, &x, &y);
639  ptaFindPtByHash(pta_big, dahash1, x, y, &index1);
640  if (index1 >= 0) { /* found */
641  ptaFindPtByHash(pta_small, dahash2, x, y, &index2);
642  if (index2 == -1) { /* not found */
643  ptaAddPt(ptad, x, y);
644  l_hashPtToUint64(x, y, &key);
645  l_dnaHashAdd(dahash2, key, (l_float64)i);
646  }
647  }
648  }
649 
650  l_dnaHashDestroy(&dahash1);
651  l_dnaHashDestroy(&dahash2);
652  return ptad;
653 }
654 
655 
680 l_ok
682  L_DNAHASH *dahash,
683  l_int32 x,
684  l_int32 y,
685  l_int32 *pindex)
686 {
687 l_int32 i, nvals, index, xi, yi;
688 l_uint64 key;
689 L_DNA *da;
690 
691  PROCNAME("ptaFindPtByHash");
692 
693  if (!pindex)
694  return ERROR_INT("&index not defined", procName, 1);
695  *pindex = -1;
696  if (!pta)
697  return ERROR_INT("pta not defined", procName, 1);
698  if (!dahash)
699  return ERROR_INT("dahash not defined", procName, 1);
700 
701  l_hashPtToUint64(x, y, &key);
702  da = l_dnaHashGetDna(dahash, key, L_NOCOPY);
703  if (!da) return 0;
704 
705  /* Run through the da, looking for this point */
706  nvals = l_dnaGetCount(da);
707  for (i = 0; i < nvals; i++) {
708  l_dnaGetIValue(da, i, &index);
709  ptaGetIPt(pta, index, &xi, &yi);
710  if (x == xi && y == yi) {
711  *pindex = index;
712  return 0;
713  }
714  }
715 
716  return 0;
717 }
718 
719 
726 L_DNAHASH *
728 {
729 l_int32 i, n, x, y;
730 l_uint32 nsize;
731 l_uint64 key;
732 L_DNAHASH *dahash;
733 
734  PROCNAME("l_dnaHashCreateFromPta");
735 
736  if (!pta)
737  return (L_DNAHASH *)ERROR_PTR("pta not defined", procName, NULL);
738 
739  /* Build up dnaHash of indices, hashed by a key that is
740  * a large linear combination of x and y values designed to
741  * randomize the key. Having about 20 pts in each bucket is
742  * roughly optimal for speed for large sets. */
743  n = ptaGetCount(pta);
744  findNextLargerPrime(n / 20, &nsize); /* buckets in hash table */
745 /* fprintf(stderr, "Prime used: %d\n", nsize); */
746 
747  /* Add each point, using the hash as key and the index into
748  * %ptas as the value. Storing the index enables operations
749  * that check for duplicates. */
750  dahash = l_dnaHashCreate(nsize, 8);
751  for (i = 0; i < n; i++) {
752  ptaGetIPt(pta, i, &x, &y);
753  l_hashPtToUint64(x, y, &key);
754  l_dnaHashAdd(dahash, key, (l_float64)i);
755  }
756 
757  return dahash;
758 }
l_ok l_hashPtToUint64(l_int32 x, l_int32 y, l_uint64 *phash)
l_hashPtToUint64()
Definition: utils1.c:625
l_ok ptaGetRankValue(PTA *pta, l_float32 fract, PTA *ptasort, l_int32 sorttype, l_float32 *pval)
ptaGetRankValue()
Definition: ptafunc2.c:264
Definition: pix.h:717
L_DNA * l_dnaHashGetDna(L_DNAHASH *dahash, l_uint64 key, l_int32 copyflag)
l_dnaHashGetDna()
Definition: dnahash.c:232
NUMA * numaGetSortIndex(NUMA *na, l_int32 sortorder)
numaGetSortIndex()
Definition: numafunc1.c:2637
l_int32 l_dnaGetCount(L_DNA *da)
l_dnaGetCount()
Definition: dnabasic.c:597
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:342
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
Definition: pix.h:716
void l_dnaHashDestroy(L_DNAHASH **pdahash)
l_dnaHashDestroy()
Definition: dnahash.c:152
l_ok ptaFindPtByHash(PTA *pta, L_DNAHASH *dahash, l_int32 x, l_int32 y, l_int32 *pindex)
ptaFindPtByHash()
Definition: ptafunc2.c:681
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:116
l_ok l_dnaGetIValue(L_DNA *da, l_int32 index, l_int32 *pival)
l_dnaGetIValue()
Definition: dnabasic.c:693
l_ok ptaGetSortIndex(PTA *ptas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
ptaGetSortIndex()
Definition: ptafunc2.c:139
Definition: array.h:83
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:504
l_ok findNextLargerPrime(l_int32 start, l_uint32 *pprime)
findNextLargerPrime()
Definition: utils1.c:689
PTA * ptaSort(PTA *ptas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
ptaSort()
Definition: ptafunc2.c:96
PTA * ptaRemoveDupsByAset(PTA *ptas)
ptaRemoveDupsByAset()
Definition: ptafunc2.c:361
l_ok ptaJoin(PTA *ptad, PTA *ptas, l_int32 istart, l_int32 iend)
ptaJoin()
Definition: ptafunc1.c:164
PTAA * ptaaSortByIndex(PTAA *ptaas, NUMA *naindex)
ptaaSortByIndex()
Definition: ptafunc2.c:225
l_ok l_dnaHashAdd(L_DNAHASH *dahash, l_uint64 key, l_float64 value)
l_dnaHashAdd()
Definition: dnahash.c:267
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1094
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
Definition: array.h:59
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
Definition: pix.h:532
l_ok ptaGetPt(PTA *pta, l_int32 index, l_float32 *px, l_float32 *py)
ptaGetPt()
Definition: ptabasic.c:525
PTA * ptaUnionByAset(PTA *pta1, PTA *pta2)
ptaUnionByAset()
Definition: ptafunc2.c:324
PTA * ptaCopy(PTA *pta)
ptaCopy()
Definition: ptabasic.c:225
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
PTA * ptaIntersectionByHash(PTA *pta1, PTA *pta2)
ptaIntersectionByHash()
Definition: ptafunc2.c:607
PTA * ptaIntersectionByAset(PTA *pta1, PTA *pta2)
ptaIntersectionByAset()
Definition: ptafunc2.c:408
L_ASET * l_asetCreateFromPta(PTA *pta)
l_asetCreateFromPta()
Definition: ptafunc2.c:458
l_ok ptaRemoveDupsByHash(PTA *ptas, PTA **pptad, L_DNAHASH **pdahash)
ptaRemoveDupsByHash()
Definition: ptafunc2.c:550
l_int32 ptaaGetCount(PTAA *ptaa)
ptaaGetCount()
Definition: ptabasic.c:1074
Definition: pix.h:718
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:192
L_DNAHASH * l_dnaHashCreateFromPta(PTA *pta)
l_dnaHashCreateFromPta()
Definition: ptafunc2.c:727
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:555
Definition: rbtree.h:61
l_ok ptaaAddPta(PTAA *ptaa, PTA *pta, l_int32 copyflag)
ptaaAddPta()
Definition: ptabasic.c:1004
L_DNAHASH * l_dnaHashCreate(l_int32 nbuckets, l_int32 initsize)
l_dnaHashCreate()
Definition: dnahash.c:122
PTAA * ptaaCreate(l_int32 n)
ptaaCreate()
Definition: ptabasic.c:939
PTA * ptaSortByIndex(PTA *ptas, NUMA *naindex)
ptaSortByIndex()
Definition: ptafunc2.c:189
PTA * ptaUnionByHash(PTA *pta1, PTA *pta2)
ptaUnionByHash()
Definition: ptafunc2.c:500
Definition: pix.h:517