#ifndef pz_segment_H #define pz_segment_H /* A pz_segment_t is a descriptor of part of a fragment contour */ /* Last edited on 2015-01-20 16:49:57 by stolfilocal */ /* !!! Move to libmsmatch !!! */ #include typedef struct pz_segment_t { int cvx; /* Contour index. */ int tot; /* Number of samples in chain. */ int ini; /* Initial sample index. */ int ns; /* Number of samples in segment. */ bool_t rev; /* TRUE to use the segment in reverse. */ } pz_segment_t; /* A "pz_segment_t" record "s" describes a set of "s.ns" consecutive samples, starting at sample index "s.ini", along a fragment contour with a total of "s.tot" samples. The indices are always taken modulo "s.tot", so the segment may wrap around the end of the sample array. If "rev" is TRUE the samples are to be used in reverse order, and possibly complemented depending on their nature. Note that if "s.rev == TRUE" the client should start its processing with sample "(s.ini + s.ns - 1) MOD s.tot" and finish with sample "s.ini MOD s.tot". Normally a segment has at least two samples, and at most "s.tot" samples. Singleton segments ("s.ns == 1"), empty segments (with "ns == 0") and ``full circle'' segments ("s.ns == s.tot+1") are sometimes useful but may cause some operations to fail. */ typedef struct pz_segment_pair { pz_segment_t c[2]; } pz_segment_pair; #define pz_segment_empty \ (pz_segment_t){/*cvx*/ 0, /*tot*/ 1, /*ini*/ 0, /*ns*/ 0, /*rev*/ FALSE}; /* An empty segment (NOT the only one!). */ bool_t pz_segment_is_empty (pz_segment_t *s); /* TRUE if the segment is empty (has zero samples). */ int pz_segment_abs_index (int iRel, pz_segment_t *s); /* Given a sample index "iRel" relative to the segment "s", returns the corresponding sample index in the original chain, taking the direction of "s" into account. Note that the result must be reduced "MOD s.tot" before indexing the chain. */ int pz_segment_rel_index (int iAbs, pz_segment_t *s); /* Given a sample index "iAbs" in a whole chain, returns the corresponding sample index relative to the segment "s", taking the direction of "s" into account. Note that the result must be reduced "MOD s.tot" and checked against "s.ns" before indexing the extracted segment samples. */ int pz_segment_abs_index_clip (int i, pz_segment_t *s); /* Given a sample index "i" relative to the segment "s", returns the corresponding sample index in the whole chain. */ int pz_segment_rel_index_clip (int i, pz_segment_t *s); /* Given a sample index "i" in some chain, returns the corresponding sample index relative to segment "s" of that chain. Returns "(int.ne - 1)" if that sample lies outside "s". */ pz_segment_t pz_segment_complement (pz_segment_t *s); /* The complement of segment "s" with respect to its parent chain, which is assumed to be closed. The result has same initial and final samples as "s", in the opposite order, and same sense "rev". Fails if "s.ns == 0" or "s.ns > s.tot + 1". */ int pz_segment_overlap (pz_segment_t *a, pz_segment_t *b); /* Maximum number of consecutive samples in common beween "a" and "b". Returns 0 if "a" and "b" are on different chains or have different orientations. If they intersect in two disjoint segments, considers only the longest one. */ pz_segment_t pz_segment_join (pz_segment_t *a, pz_segment_t *b); /* Joins two segments of the same chain (with same direction) into a single segment. If the segments don't overlap, they are joined by the shortest uncovered arc. If the segments overlap at both ends, the result is a segment that covers the whole contour once, starting and ending at sample 0. */ pz_segment_t pz_segment_meet (pz_segment_t *a, pz_segment_t *b); /* Returns the intersection of two segments, which must belong to the same chain and have the same reading direction. The result is an empty segment ("ns == 0") if they are disjoint, or if their intersection is not a single segment. */ pz_segment_t pz_segment_expand (pz_segment_t *s, int iniExtra, int finExtra); /* Expands the given segment by "iniExtra" steps at the low end, and "finExtra" steps at the high end. If either quantity is negative, removes that many steps from the respective end. In any case, the result will have at least one sample and at most "s.tot + 1" samples. */ pz_segment_t pz_segment_read_one (FILE *rd); /* Reads a single segment description from "rd", in the format | s.cvx s.tot s.ini s.ns s.rev where "s.rev" is "+" for FALSE (forward direction) ) || ( "-" for TRUE (reverse direction) */ void pz_segment_write_one (FILE *wr, pz_segment_t *s); /* Writes a segment description to "wr", in a format that can be read back by "pz_segment_read_one". */ /* VECTORS OF SEGMENTS */ vec_typedef(pz_segment_vec_t,pz_segment_vec,pz_segment_t); /* Vectors of segments ({pz_segment_t}s) */ typedef struct pz_segment_read_data { char *cmt; pz_segment_vec_t s; } pz_segment_read_data; void pz_segment_write (FILE *wr, char *cmt, pz_segment_vec_t *s); /* Writes the list of segments "s" to the writer "wr". */ pz_segment_read_data pz_segment_read (FILE *rd); /* Reads from "rd" a list of segments that was written by "pz_segment_write". */ pz_segment_read_data pz_segment_read_old (FILE *rd, int_vec_t *m); /* pz_segment_reads from "rd" a list of segments that was written BY the old version of "pz_segment_write", without the "rev" bits. Takes the "tot" fields of the result from from the argument "m", assuming that "m[k]" the number of samples of contour "k". */ bool_vec_t pz_segment_chains_used (pz_segment_vec_t *s); /* Returns a vector "used" such that "used[k]" is TRUE iff chain "k" occurs in some segment "s[i]". */ void pz_segment_print (FILE *wr, pz_segment_t *s); /* pz_segment_prints the segment descriptor "s" to "wr", in a readable format, without trailing newline. */ #endif