1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include "gtf.h"
5
6 /*******************************************************************************
7 *
8 * Comparison functions
9 *
10 * These are according to Allen's Interval Algebra
11 *
12 *******************************************************************************/
rangeAny(uint32_t start,uint32_t end,GTFentry * e)13 static inline int rangeAny(uint32_t start, uint32_t end, GTFentry *e) {
14 if(end <= e->start) return -1;
15 if(start >= e->end) return 1;
16 return 0;
17 }
18
rangeContains(uint32_t start,uint32_t end,GTFentry * e)19 static inline int rangeContains(uint32_t start, uint32_t end, GTFentry *e) {
20 if(e->start >= start && e->end <= end) return 0;
21 if(e->end < end) return -1;
22 return 1;
23 }
24
rangeWithin(uint32_t start,uint32_t end,GTFentry * e)25 static inline int rangeWithin(uint32_t start, uint32_t end, GTFentry *e) {
26 if(start >= e->start && end <= e->end) return 0;
27 if(start < e->start) return -1;
28 return 1;
29 }
30
rangeExact(uint32_t start,uint32_t end,GTFentry * e)31 static inline int rangeExact(uint32_t start, uint32_t end, GTFentry *e) {
32 if(start == e->start && end == e->end) return 0;
33 if(start < e->start) return -1;
34 if(end < e->end) return -1;
35 return 1;
36 }
37
rangeStart(uint32_t start,uint32_t end,GTFentry * e)38 static inline int rangeStart(uint32_t start, uint32_t end, GTFentry *e) {
39 if(start == e->start) return 0;
40 if(start < e->start) return -1;
41 return 1;
42 }
43
rangeEnd(uint32_t start,uint32_t end,GTFentry * e)44 static inline int rangeEnd(uint32_t start, uint32_t end, GTFentry *e) {
45 if(end == e->end) return 0;
46 if(end < e->end) return -1;
47 return 1;
48 }
49
exactSameStrand(int strand,GTFentry * e)50 static inline int exactSameStrand(int strand, GTFentry *e) {
51 return strand == e->strand;
52 }
53
sameStrand(int strand,GTFentry * e)54 static inline int sameStrand(int strand, GTFentry *e) {
55 if(strand == 3 || e->strand == 3) return 1;
56 if(strand == e->strand) return 1;
57 return 0;
58 }
59
oppositeStrand(int strand,GTFentry * e)60 static inline int oppositeStrand(int strand, GTFentry *e) {
61 if(strand == 3 || e->strand == 3) return 1;
62 if(strand != e->strand) return 1;
63 return 0;
64 }
65
66 /*******************************************************************************
67 *
68 * OverlapSet functions
69 *
70 *******************************************************************************/
os_init(GTFtree * t)71 overlapSet *os_init(GTFtree *t) {
72 overlapSet *os = calloc(1, sizeof(overlapSet));
73 assert(os);
74 os->tree = t;
75 return os;
76 }
77
os_reset(overlapSet * os)78 void os_reset(overlapSet *os) {
79 int i;
80 for(i=0; i<os->l; i++) os->overlaps[i] = NULL;
81 os->l = 0;
82 }
83
os_destroy(overlapSet * os)84 void os_destroy(overlapSet *os) {
85 if(os->overlaps) free(os->overlaps);
86 free(os);
87 }
88
os_grow(overlapSet * os)89 overlapSet *os_grow(overlapSet *os) {
90 int i;
91 os->m++;
92 kroundup32(os->m);
93 os->overlaps = realloc(os->overlaps, os->m * sizeof(GTFentry*));
94 assert(os->overlaps);
95 for(i=os->l; i<os->m; i++) os->overlaps[i] = NULL;
96
97 return os;
98 }
99
os_push(overlapSet * os,GTFentry * e)100 static void os_push(overlapSet *os, GTFentry *e) {
101 if(os->l+1 >= os->m) os = os_grow(os);
102 os->overlaps[os->l++] = e;
103 }
104
os_dup(overlapSet * os)105 overlapSet *os_dup(overlapSet *os) {
106 int i;
107 overlapSet *os2 = os_init(os->tree);
108 for(i=0; i<os->l; i++) os_push(os2, os->overlaps[i]);
109 return os2;
110 }
111
os_exclude(overlapSet * os,int i)112 void os_exclude(overlapSet *os, int i) {
113 int j;
114 for(j=i; j<os->l-1; j++) os->overlaps[j] = os->overlaps[j+1];
115 os->overlaps[--os->l] = NULL;
116 }
117
os_sortFunc(const void * a,const void * b)118 static int os_sortFunc(const void *a, const void *b) {
119 GTFentry *pa = *(GTFentry**) a;
120 GTFentry *pb = *(GTFentry**) b;
121
122 if(pa->start < pb->start) return -1;
123 if(pb->start < pa->start) return 1;
124 if(pa->end < pb->end) return -1;
125 if(pb->end < pa->end) return 1;
126 return 0;
127 }
128
os_sort(overlapSet * os)129 static void os_sort(overlapSet *os) {
130 qsort((void *) os->overlaps, os->l, sizeof(GTFentry**), os_sortFunc);
131 }
132
133 //Non-existant keys/values will be ignored
os_requireAttributes(overlapSet * os,char ** key,char ** val,int len)134 void os_requireAttributes(overlapSet *os, char **key, char **val, int len) {
135 int i, j, k, filter;
136 int32_t keyHash, valHash;
137
138 for(i=0; i<len; i++) {
139 if(!os->l) break;
140
141 keyHash = str2valHT(os->tree->htAttributes, key[i]);
142 valHash = str2valHT(os->tree->htAttributes, val[i]);
143 assert(keyHash>=0);
144 assert(valHash>=0);
145 for(j=0; j<os->l; j++) {
146 filter = 1;
147 for(k=0; k<os->overlaps[j]->nAttributes; k++) {
148 if(os->overlaps[j]->attrib[k]->key == keyHash) {
149 if(os->overlaps[j]->attrib[k]->val == valHash) {
150 filter = 0;
151 break;
152 }
153 }
154 }
155 if(filter) {
156 os_exclude(os, j);
157 j--; //os_exclude shifts everything
158 }
159 }
160 }
161 }
162
163 //This is an inefficient implementation. It would be faster to sort according
164 //to COMPARE_FUNC and then do an O(n) merge.
os_intersect(overlapSet * os1,overlapSet * os2,COMPARE_FUNC f)165 overlapSet *os_intersect(overlapSet *os1, overlapSet *os2, COMPARE_FUNC f) {
166 overlapSet *os = os_init(os1->tree);
167 int i, j;
168
169 for(i=0; i<os1->l; i++) {
170 for(j=0; j<os2->l; j++) {
171 if(f(os1->overlaps[i],os2->overlaps[j]) == 0) {
172 os_push(os, os1->overlaps[i]);
173 os_exclude(os2, j);
174 break;
175 }
176 }
177 }
178
179 return os;
180 }
181 /*******************************************************************************
182 *
183 * OverlapSetList functions
184 *
185 *******************************************************************************/
osl_init()186 overlapSetList *osl_init() {
187 overlapSetList *osl = calloc(1, sizeof(overlapSetList));
188 assert(osl);
189 return osl;
190 }
191
osl_reset(overlapSetList * osl)192 void osl_reset(overlapSetList *osl) {
193 int i;
194 for(i=0; i<osl->l; i++) os_destroy(osl->os[i]);
195 osl->l = 0;
196 }
197
osl_destroy(overlapSetList * osl)198 void osl_destroy(overlapSetList *osl) {
199 osl_reset(osl);
200 if(osl->os) free(osl->os);
201 free(osl);
202 }
203
osl_grow(overlapSetList * osl)204 void osl_grow(overlapSetList *osl) {
205 int i;
206 osl->m++;
207 kroundup32(osl->m);
208 osl->os = realloc(osl->os, osl->m * sizeof(overlapSet*));
209 assert(osl->os);
210 for(i=osl->l; i<osl->m; i++) osl->os[i] = NULL;
211 }
212
osl_push(overlapSetList * osl,overlapSet * os)213 void osl_push(overlapSetList *osl, overlapSet *os) {
214 if(osl->l+1 >= osl->m) osl_grow(osl);
215 osl->os[osl->l++] = os;
216 }
217
218 //The output needs to be destroyed
osl_intersect(overlapSetList * osl,COMPARE_FUNC f)219 overlapSet *osl_intersect(overlapSetList *osl, COMPARE_FUNC f) {
220 int i;
221 if(!osl->l) return NULL;
222
223 overlapSet *osTmp, *os = os_dup(osl->os[0]);
224 for(i=1; i<osl->l; i++) {
225 osTmp = os_intersect(os, osl->os[i], f);
226 os_destroy(os);
227 os = osTmp;
228 if(os->l == 0) break;
229 }
230 return os;
231 }
232
233 //Returns 1 if the node is in the overlapSet, otherwise 0.
os_contains(overlapSet * os,GTFentry * e)234 int os_contains(overlapSet *os, GTFentry *e) {
235 int i;
236 for(i=0; i<os->l; i++) {
237 if(os->overlaps[i] == e) return 1;
238 }
239 return 0;
240 }
241
242 //This could be made much more efficient
osl_union(overlapSetList * osl)243 overlapSet *osl_union(overlapSetList *osl) {
244 int i, j;
245 if(!osl->l) NULL;
246
247 if(!osl->os) return NULL;
248 if(!osl->os[0]) return NULL;
249 overlapSet *os = os_dup(osl->os[0]);
250 for(i=1; i<osl->l; i++) {
251 for(j=0; j<osl->os[i]->l; j++) {
252 if(!os_contains(os, osl->os[i]->overlaps[j])) {
253 os_push(os, osl->os[i]->overlaps[j]);
254 }
255 }
256 }
257 return os;
258 }
259
260 /*******************************************************************************
261 *
262 * uniqueSet functions
263 *
264 *******************************************************************************/
us_init(hashTable * ht)265 static uniqueSet *us_init(hashTable *ht) {
266 uniqueSet *us = calloc(1, sizeof(uniqueSet));
267 assert(us);
268 us->ht = ht;
269 return us;
270 }
271
us_destroy(uniqueSet * us)272 void us_destroy(uniqueSet *us) {
273 if(!us) return;
274 if(us->IDs) {
275 free(us->IDs);
276 free(us->cnts);
277 }
278 free(us);
279 }
280
us_grow(uniqueSet * us)281 static uniqueSet *us_grow(uniqueSet *us) {
282 int i;
283 us->m++;
284 kroundup32(us->m);
285 us->IDs = realloc(us->IDs, us->m * sizeof(int32_t));
286 assert(us->IDs);
287 us->cnts = realloc(us->cnts, us->m * sizeof(uint32_t));
288 assert(us->cnts);
289 for(i=us->l; i<us->m; i++) {
290 us->IDs[i] = -1;
291 us->cnts[i] = 0;
292 }
293
294 return us;
295 }
296
us_push(uniqueSet * us,int32_t ID)297 static void us_push(uniqueSet *us, int32_t ID) {
298 if(us->l+1 >= us->m) us = us_grow(us);
299 us->IDs[us->l] = ID;
300 us->cnts[us->l++] = 1;
301 }
302
us_inc(uniqueSet * us)303 static void us_inc(uniqueSet *us) {
304 assert(us->l<=us->m);
305 us->cnts[us->l-1]++;
306 }
307
us_cnt(uniqueSet * us,int32_t i)308 uint32_t us_cnt(uniqueSet *us, int32_t i) {
309 assert(i<us->l);
310 return us->cnts[i];
311 }
312
us_val(uniqueSet * us,int32_t i)313 char *us_val(uniqueSet *us, int32_t i) {
314 if(i>=us->l) return NULL;
315 return val2strHT(us->ht, us->IDs[i]);
316 }
317
318 /*******************************************************************************
319 *
320 * Overlap set count/unique functions
321 *
322 *******************************************************************************/
int32_t_cmp(const void * a,const void * b)323 static int int32_t_cmp(const void *a, const void *b) {
324 int32_t ia = *((int32_t*) a);
325 int32_t ib = *((int32_t*) b);
326 return ia-ib;
327 }
328
cntAttributes(overlapSet * os,char * attributeName)329 int32_t cntAttributes(overlapSet *os, char *attributeName) {
330 int32_t IDs[os->l], i, j, key, last, n = 0;
331 if(!strExistsHT(os->tree->htAttributes, attributeName)) return n;
332
333 key = str2valHT(os->tree->htAttributes, attributeName);
334 for(i=0; i<os->l; i++) {
335 IDs[i] = -1;
336 for(j=0; j<os->overlaps[i]->nAttributes; j++) {
337 if(os->overlaps[i]->attrib[j]->key == key) {
338 IDs[i] = os->overlaps[i]->attrib[j]->val;
339 break;
340 }
341 }
342 }
343 qsort((void*) IDs, os->l, sizeof(int32_t), int32_t_cmp);
344
345 last = IDs[0];
346 n = (last >= 0) ? 1 : 0;
347 for(i = 1; i<os->l; i++) {
348 if(IDs[i] != last) {
349 n++;
350 last = IDs[i];
351 }
352 }
353 return n;
354 }
355
uniqueAttributes(overlapSet * os,char * attributeName)356 uniqueSet *uniqueAttributes(overlapSet *os, char *attributeName) {
357 if(!os) return NULL;
358 if(os->l == 0) return NULL;
359 int32_t IDs[os->l], i, j, key, last;
360 if(!strExistsHT(os->tree->htAttributes, attributeName)) return NULL;
361 uniqueSet *us = us_init(os->tree->htAttributes);
362
363 key = str2valHT(os->tree->htAttributes, attributeName);
364 for(i=0; i<os->l; i++) {
365 IDs[i] = -1;
366 for(j=0; j<os->overlaps[i]->nAttributes; j++) {
367 if(os->overlaps[i]->attrib[j]->key == key) {
368 IDs[i] = os->overlaps[i]->attrib[j]->val;
369 break;
370 }
371 }
372 }
373 qsort((void*) IDs, os->l, sizeof(int32_t), int32_t_cmp);
374
375 last = -1;
376 for(i=0; i<os->l; i++) {
377 if(IDs[i] != last || last < 0) {
378 us_push(us, IDs[i]);
379 last = IDs[i];
380 } else {
381 us_inc(us);
382 }
383 }
384
385 if(us->l) return us;
386 us_destroy(us);
387 return NULL;
388 }
389
390 /*******************************************************************************
391 *
392 * Node iterator functions
393 *
394 *******************************************************************************/
395 //bit 1: go left, bit 2: go right (a value of 3 is then "do both")
centerDirection(uint32_t start,uint32_t end,GTFnode * n)396 static int centerDirection(uint32_t start, uint32_t end, GTFnode *n) {
397 if(n->center >= start && n->center < end) return 3;
398 if(n->center < start) return 2;
399 return 1;
400 }
401
matchingStrand(GTFentry * e,int strand,int strandType)402 static int matchingStrand(GTFentry *e, int strand, int strandType) {
403 if(strandType == GTF_IGNORE_STRAND) return 1;
404
405 if(strandType == GTF_SAME_STRAND) {
406 return sameStrand(strand, e);
407 } else if(strandType == GTF_OPPOSITE_STRAND) {
408 return oppositeStrand(strand, e);
409 } else if(strandType == GTF_EXACT_SAME_STRAND) {
410 return exactSameStrand(strand, e);
411 }
412
413 fprintf(stderr, "[matchingStrand] Unknown strand type %i. Assuming a match.\n", strandType);
414 return 1;
415 }
416
filterStrand(overlapSet * os,int strand,int strandType)417 static void filterStrand(overlapSet *os, int strand, int strandType) {
418 int i;
419
420 if(strandType == GTF_IGNORE_STRAND) return;
421
422 for(i=os->l-1; i>=0; i--) {
423 if(strandType == GTF_SAME_STRAND) {
424 if(!sameStrand(strand, os->overlaps[i])) os_exclude(os, i);
425 } else if(strandType == GTF_OPPOSITE_STRAND) {
426 if(!oppositeStrand(strand, os->overlaps[i])) os_exclude(os, i);
427 } else if(strandType == GTF_EXACT_SAME_STRAND) {
428 if(!exactSameStrand(strand, os->overlaps[i])) os_exclude(os, i);
429 }
430 }
431 }
432
pushOverlaps(overlapSet * os,GTFtree * t,GTFentry * e,uint32_t start,uint32_t end,int comparisonType,int direction,FILTER_ENTRY_FUNC ffunc)433 static void pushOverlaps(overlapSet *os, GTFtree *t, GTFentry *e, uint32_t start, uint32_t end, int comparisonType, int direction, FILTER_ENTRY_FUNC ffunc) {
434 int dir;
435 int keep = 1;
436 if(!e) return;
437
438 if(ffunc) keep = ffunc(t, e);
439
440 switch(comparisonType) {
441 case GTF_MATCH_EXACT :
442 if((dir = rangeExact(start, end, e)) == 0) {
443 if(keep) os_push(os, e);
444 }
445 break;
446 case GTF_MATCH_WITHIN :
447 if((dir = rangeAny(start, end, e)) == 0) {
448 if(keep) if(rangeWithin(start, end ,e) == 0) os_push(os, e);
449 }
450 break;
451 case GTF_MATCH_CONTAIN :
452 if((dir = rangeAny(start, end, e)) == 0) {
453 if(keep) if(rangeContains(start, end, e) == 0) os_push(os, e);
454 }
455 break;
456 case GTF_MATCH_START :
457 if((dir = rangeStart(start, end, e)) == 0) {
458 if(keep) os_push(os, e);
459 }
460 break;
461 case GTF_MATCH_END :
462 if((dir = rangeEnd(start, end, e)) == 0) {
463 if(keep) os_push(os, e);
464 }
465 break;
466 default :
467 if((dir = rangeAny(start, end, e)) == 0) {
468 if(keep) os_push(os, e);
469 }
470 break;
471 }
472
473 if(direction) {
474 if(dir > 0) return;
475 pushOverlaps(os, t, e->right, start, end, comparisonType, direction, ffunc);
476 } else {
477 if(dir < 0) return;
478 pushOverlaps(os, t, e->left, start, end, comparisonType, direction, ffunc);
479 }
480 }
481
countOverlapsEntry(GTFtree * t,GTFentry * e,uint32_t start,uint32_t end,int strand,int matchType,int strandType,int direction,int32_t max,FILTER_ENTRY_FUNC ffunc)482 static int32_t countOverlapsEntry(GTFtree *t, GTFentry *e, uint32_t start, uint32_t end, int strand, int matchType, int strandType, int direction, int32_t max, FILTER_ENTRY_FUNC ffunc) {
483 int dir;
484 int32_t cnt = 0;
485 if(!e) return cnt;
486
487 switch(matchType) {
488 case GTF_MATCH_EXACT :
489 if((dir = rangeExact(start, end, e)) == 0) {
490 cnt = 1;
491 }
492 break;
493 case GTF_MATCH_WITHIN :
494 if((dir = rangeAny(start, end, e)) == 0) {
495 if(rangeWithin(start, end, e) == 0) cnt = 1;
496 }
497 break;
498 case GTF_MATCH_CONTAIN :
499 if((dir = rangeAny(start, end, e)) == 0) {
500 if(rangeContains(start, end, e) == 0) cnt = 1;
501 }
502 break;
503 case GTF_MATCH_START :
504 if((dir = rangeStart(start, end, e)) == 0) {
505 cnt = 1;
506 }
507 break;
508 case GTF_MATCH_END :
509 if((dir = rangeEnd(start, end, e)) == 0) {
510 cnt = 1;
511 }
512 break;
513 default :
514 if((dir = rangeAny(start, end, e)) == 0) {
515 cnt = 1;
516 }
517 break;
518 }
519
520 if(cnt) {
521 if(!matchingStrand(e, strand, strandType)) cnt = 0;
522 }
523
524 if(cnt && ffunc) {
525 if(!ffunc(t, e)) cnt = 0;
526 }
527
528 if(max && cnt >= max) return max;
529
530 if(direction) {
531 if(dir > 0) return cnt;
532 return cnt + countOverlapsEntry(t, e->right, start, end, strand, matchType, strandType, direction, max, ffunc);
533 } else {
534 if(dir < 0) return cnt;
535 return cnt + countOverlapsEntry(t, e->left, start, end, strand, matchType, strandType, direction, max, ffunc);
536 }
537 }
538
pushOverlapsNode(overlapSet * os,GTFtree * t,GTFnode * n,uint32_t start,uint32_t end,int matchType,FILTER_ENTRY_FUNC ffunc)539 static void pushOverlapsNode(overlapSet *os, GTFtree *t, GTFnode *n, uint32_t start, uint32_t end, int matchType, FILTER_ENTRY_FUNC ffunc) {
540 int dir;
541 if(!n) return;
542 dir = centerDirection(start, end, n);
543
544 if(dir&1) {
545 pushOverlaps(os, t, n->starts, start, end, matchType, 1, ffunc);
546 pushOverlapsNode(os, t, n->left, start, end, matchType, ffunc);
547 }
548 if(dir&2) {
549 if(dir!=3) pushOverlaps(os, t, n->ends, start, end, matchType, 0, ffunc);
550 pushOverlapsNode(os, t, n->right, start, end, matchType, ffunc);
551 }
552 }
553
countOverlapsNode(GTFtree * t,GTFnode * n,uint32_t start,uint32_t end,int strand,int matchType,int strandType,int32_t max,FILTER_ENTRY_FUNC ffunc)554 static int32_t countOverlapsNode(GTFtree *t, GTFnode *n, uint32_t start, uint32_t end, int strand, int matchType, int strandType, int32_t max, FILTER_ENTRY_FUNC ffunc) {
555 int32_t cnt = 0;
556 int dir;
557 if(!n) return cnt;
558 dir = centerDirection(start, end, n);
559
560 if(dir&1) {
561 cnt += countOverlapsEntry(t, n->starts, start, end, strand, matchType, strandType, 1, max, ffunc);
562 if(max && cnt >= max) return max;
563 cnt += countOverlapsNode(t, n->left, start, end, strand, matchType, strandType, max, ffunc);
564 if(max && cnt >= max) return max;
565 }
566 if(dir&2) {
567 if(dir!=3) cnt += countOverlapsEntry(t, n->starts, start, end, strand, matchType, strandType, 0, max, ffunc);
568 if(max && cnt >= max) return max;
569 cnt += countOverlapsNode(t, n->right, start, end, strand, matchType, strandType, max, ffunc);
570 if(max && cnt >= max) return max;
571 }
572 return cnt;
573 }
574
575 /*******************************************************************************
576 *
577 * Driver functions for end use.
578 *
579 *******************************************************************************/
findOverlaps(overlapSet * os,GTFtree * t,char * chrom,uint32_t start,uint32_t end,int strand,int matchType,int strandType,int keepOS,FILTER_ENTRY_FUNC ffunc)580 overlapSet * findOverlaps(overlapSet *os, GTFtree *t, char *chrom, uint32_t start, uint32_t end, int strand, int matchType, int strandType, int keepOS, FILTER_ENTRY_FUNC ffunc) {
581 int32_t tid = str2valHT(t->htChroms, chrom);
582 overlapSet *out = os;
583
584 if(out && !keepOS) os_reset(out);
585 else if(!out) out = os_init(t);
586
587 if(tid<0) return out;
588 if(!t->balanced) {
589 fprintf(stderr, "[findOverlaps] The tree has not been balanced! No overlaps will be returned.\n");
590 return out;
591 }
592
593 pushOverlapsNode(out, t, (GTFnode*) t->chroms[tid]->tree, start, end, matchType, ffunc);
594 if(out->l) filterStrand(out, strand, strandType);
595 if(out->l) os_sort(out);
596
597 return out;
598 }
599
countOverlaps(GTFtree * t,char * chrom,uint32_t start,uint32_t end,int strand,int matchType,int strandType,FILTER_ENTRY_FUNC ffunc)600 int32_t countOverlaps(GTFtree *t, char *chrom, uint32_t start, uint32_t end, int strand, int matchType, int strandType, FILTER_ENTRY_FUNC ffunc) {
601 int32_t tid = str2valHT(t->htChroms, chrom);
602 if(tid<0) return 0;
603
604 if(!t->balanced) {
605 fprintf(stderr, "[countOverlaps] The tree has not been balanced! No overlaps will be returned.\n");
606 return 0;
607 }
608
609 return countOverlapsNode(t, (GTFnode*) t->chroms[tid]->tree, start, end, strand, matchType, strandType, 0, ffunc);
610 }
611
overlapsAny(GTFtree * t,char * chrom,uint32_t start,uint32_t end,int strand,int matchType,int strandType,FILTER_ENTRY_FUNC ffunc)612 int overlapsAny(GTFtree *t, char *chrom, uint32_t start, uint32_t end, int strand, int matchType, int strandType, FILTER_ENTRY_FUNC ffunc) {
613 int32_t tid = str2valHT(t->htChroms, chrom);
614 if(tid<0) return 0;
615
616 if(!t->balanced) {
617 fprintf(stderr, "[overlapsAny] The tree has not been balanced! No overlaps will be returned.\n");
618 return 0;
619 }
620
621 return countOverlapsNode(t, (GTFnode*) t->chroms[tid]->tree, start, end, strand, matchType, strandType, 1, ffunc);
622 }
623