/* See pz_segment.h. */ /* Last edited on 2023-02-12 07:48:45 by stolfi */ /* !!! Move to {libmsmatch} !!! */ #include #include #include #include #include #include #include #include #include bool_t pz_segment_is_empty (pz_segment_t *s) { return s->ns == 0; } int pz_segment_abs_index (int iRel, pz_segment_t *s) { if (s->rev) { return s->ini + s->ns - 1 - iRel; } else { return s->ini + iRel; } } int pz_segment_rel_index (int iAbs, pz_segment_t *s) { if (s->rev) { return s->ini + s->ns - 1 - iAbs; } else { return iAbs - s->ini; } } int pz_segment_abs_index_clip (int iRel, pz_segment_t *s) { affirm(iRel <= s->ns, "bad iRel"); if (s->rev) { return (s->ini + s->ns - 1 - iRel) % s->tot; } else { return (iRel + s->ini) % s->tot; } } int pz_segment_rel_index_clip (int iAbs, pz_segment_t *s) { int j = (iAbs - s->ini) % s->tot; if (j < s->ns) { if (s->rev) { return s->ns - 1 - j; } else { return j; } } else { return (s->ns - 1); } } pz_segment_t pz_segment_complement (pz_segment_t *s) { affirm(s->ns > 0, "bad ns"); affirm(s->ns <= s->tot + 1, "bad ns"); return (pz_segment_t){ /*cvx*/ s->cvx, /*tot*/ s->tot, /*ini*/ (s->ini + s->ns - 1) % s->tot, /*ns*/ s->tot - s->ns + 2, /*rev*/ s->rev }; } pz_segment_t pz_segment_expand (pz_segment_t *s, int iniExtra, int finExtra) { int askedLen = s->ns + iniExtra + finExtra; int newLen = imax(1, imin(askedLen, s->tot + 1)); int excessSteps = askedLen - newLen; /* do */ return (pz_segment_t){ /*cvx*/ s->cvx, /*tot*/ s->tot, /*ini*/ (s->ini - iniExtra + excessSteps / 2) % s->tot, /*ns*/ newLen, /*rev*/ s->rev }; } int pz_segment_overlap (pz_segment_t *a, pz_segment_t *b) { if ((a->cvx != b->cvx) || (a->rev != b->rev)) { return 0; } else { affirm(a->tot == b->tot, "inconsistent segs"); if ((a->ns >= a->tot) || (b->ns >= b->tot)) { return imin(a->ns, b->ns); } else if (a->ini == b->ini) { return imin(a->ns, b->ns); } else { int m = a->tot; int dab = (b->ini - a->ini) % m; int nab = imin(a->ns - dab, b->ns); int dba = (a->ini - b->ini) % m; int nba = imin(b->ns - dba, a->ns); return imax(0, imax(nba, nab)); } } } pz_segment_t pz_segment_meet (pz_segment_t *a, pz_segment_t *b) { int ini, ns; if ((a->cvx != b->cvx) || (a->rev != b->rev)) { return pz_segment_empty; } else { affirm(a->tot == b->tot, "incosistent segs"); if ((a->ns == 0) || (b->ns == 0)) { return pz_segment_empty; } else if (a->ns >= a->tot + 1) { return *b; } else if (b->ns >= b->tot + 1) { return *a; } int m = a->tot; int dab = (b->ini - a->ini) % m; int dba = (a->ini - b->ini) % m; if (dab == 0) { /* Both segments start together */ ini = a->ini % m; ns = imin(a->ns, b->ns); } else if ((dab < a->ns) && (dba < b->ns)) { /* Each segment starts inside the other; wrap-around! */ return pz_segment_empty; } else if (dab < a->ns) { /* "b" starts inside "a" */ ini = b->ini % m; ns = imin(a->ns - dab, b->ns); } else if (dba < b->ns) { /* "a" starts inside "b" */ ini = a->ini % m; ns = imin(a->ns, b->ns - dba); } else { /* Disjoint */ return pz_segment_empty; } return (pz_segment_t){/*cvx*/ a->cvx, /*tot*/ m, /*ini*/ ini, /*ns*/ ns, /*rev*/ a->rev}; } } pz_segment_t pz_segment_join (pz_segment_t *a, pz_segment_t *b) { pz_segment_t res; affirm(a->cvx == b->cvx, "bad segs"); affirm(a->rev == b->rev, "bad segs"); affirm(a->tot == b->tot, "inconsistent segs"); res.cvx = a->cvx; res.tot = a->tot; res.rev = a->rev; int m = a->tot; int dab = (b->ini - a->ini) % m; int dba = m - dab; bool_t tab = dab < a->ns; /* Segment "a" runs into segment "b" */ bool_t tba = dba < b->ns; /* Segment "b" runs into segment "a" */ if ((tab && tba) || (a->ns > a->tot) || (b->ns > b->tot)) { /* The two segments cover the whole contour: */ res.ini = 0; res.ns = a->tot+1; } else { if (tab) { /* Segment "a" runs over "b" but there is a gap from "b" to "a": */ res.ini = a->ini; res.ns = imax(a->ns, dab + b->ns); } else if (tba) { /* Segment "b" runs over "a" but there is a gap from "a" to "b": */ res.ini = b->ini; res.ns = imax(b->ns, dba + a->ns); } else { /* The segments don't overlap; join through the smallest gap: */ if (dab - a->ns <= dba - b->ns) { res.ini = a->ini; res.ns = dab + b->ns; } else { res.ini = b->ini; res.ns = dba + a->ns; } } affirm(res.ns <= m, "bug"); } return res; } #define OldFileVersion "97-04-05" #define NewFileVersion "99-07-25" void pz_segment_write_one (FILE *wr, pz_segment_t *s) { fprintf(wr, "%5d %5d %6d %5d %c", s->cvx, s->tot, s->ini, s->ns, (s->rev ? '-' : '+') ); } void pz_segment_write (FILE *wr, char *cmt, pz_segment_vec_t *s) { int i; filefmt_write_header(wr, "pz_segment_vec_t", NewFileVersion); int ind = 0; /* Comment indentation. */ filefmt_write_comment(wr, cmt, ind, '|'); fprintf(wr, "segments = %d\n", s->nel); for (i = 0; i < s->nel; i++) { pz_segment_write_one(wr, &(s->el[i])); fprintf(wr, "\n"); } filefmt_write_footer(wr, "pz_segment_vec_t"); fflush(wr); } pz_segment_t pz_segment_read_one (FILE *rd) { pz_segment_t s; s.cvx = fget_int32(rd); fget_skip_spaces(rd); s.tot = fget_int32(rd); fget_skip_spaces(rd); s.ini = fget_int32(rd); fget_skip_spaces(rd); s.ns = fget_int32(rd); fget_skip_spaces(rd); int c = fgetc(rd); if (c == '-') { s.rev = TRUE; } else if (c == '+') { s.rev = FALSE; } else { fprintf(stderr, "Invalid segment direction\n"); affirm(FALSE, "bad format"); s.rev = FALSE; } return s; } pz_segment_read_data pz_segment_read (FILE *rd) { pz_segment_read_data d; filefmt_read_header(rd, "pz_segment_vec_t", NewFileVersion); d.cmt = filefmt_read_comment(rd, '|'); int n = nget_int32(rd, "segments"); fget_eol(rd); d.s = pz_segment_vec_new(n); int i; for (i = 0; i < n; i++) { fget_skip_spaces(rd); d.s.el[i] = pz_segment_read_one(rd); fget_eol(rd); } filefmt_read_footer(rd, "pz_segment_vec_t"); return d; } vec_typeimpl(pz_segment_vec_t,pz_segment_vec,pz_segment_t); pz_segment_read_data pz_segment_read_old (FILE *rd, int_vec_t *tot) { pz_segment_read_data d; filefmt_read_header(rd, "pz_segment_vec_t", OldFileVersion); d.cmt = filefmt_read_comment(rd, '|'); int n = nget_int32(rd, "segments"); fget_eol(rd); int i; d.s = pz_segment_vec_new(n); for (i = 0; i <= n-1 ; i++) { fget_skip_spaces(rd); pz_segment_t *si = &(d.s.el[i]); si->cvx = fget_int32(rd); fget_skip_spaces(rd); si->tot = tot->el[si->cvx]; si->ini = fget_int32(rd); fget_skip_spaces(rd); int fin = fget_int32(rd); fget_skip_spaces(rd); si->ns = (fin - si->ini) % si->tot + 1; fget_eol(rd); si->rev = FALSE; } filefmt_read_footer(rd, "pz_segment_vec_t"); return d; } bool_vec_t pz_segment_chains_used (pz_segment_vec_t *s) { /* Find number of elements to allocate: */ int max_cvx = 0; int i, k; for (i = 0; i < s->nel; i++) { max_cvx = imax(max_cvx, s->el[i].cvx); } /* Mark used chains: */ bool_vec_t used = bool_vec_new(max_cvx + 1); for (k = 0; k < used.ne; k++) { used.el[k] = FALSE; } for (i = 0; i < s->nel; i++) { used.el[s->el[i].cvx] = TRUE; } return used; } void pz_segment_print (FILE *wr, pz_segment_t *s) { double fm = ((double)s->tot); double pci = ((double)s->ini) / fm; int fin = (s->ini + s->ns - 1) % s->tot; double pcj = ((double)fin) / fm; fprintf(wr, "chain %4d - %6d samples in %6d", s->cvx, s->ns, s->tot); fprintf(wr, " %04d(%5.3f) .. %04d(%5.3f) ", s->ini, pci, fin, pcj); fprintf(wr, "%c", (s->rev ? '-' : '+')); } /* Copyright © 2001 Universidade Estadual de Campinas (UNICAMP). Authors: Helena C. G. Leitão and Jorge Stolfi. This file can be freely distributed, used, and modified, provided that this copyright and authorship notice is preserved, and that any modified versions are clearly marked as such. This software has NO WARRANTY of correctness or applicability for any purpose. Neither the authors nor their employers chall be held responsible for any losses or damages that may result from its use. */