INTERFACE PZSegment;

(* A PZSegment.T is a descriptor of part of a fragment contour *)
(* Last edited on 1999-11-16 19:55:47 by hcgl *)

IMPORT Wr, Rd;
FROM PZTypes IMPORT INT, NAT, NATS, BOOL, BOOLS;

TYPE
  T = RECORD
      cvx: NAT;     (* Contour index. *)
      tot: NAT;     (* Number of samples in curve. *)
      ini: NAT;     (* Initial sample index. *)
      ns: NAT;      (* Number of samples in segment. *)
      rev: BOOL;    (* TRUE to use the segment in reverse. *)
    END;
    (*
      A "PZSegment.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 with sample
      "(s.ini + s.ns - 1) MOD s.tot" and finish with "s.ini".
      
      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. *)
      
  Pair = ARRAY [0..1] OF T;
      
CONST
  Empty = T{cvx := 0, tot := 1, ini := 0, ns := 0, rev := FALSE};
  (* 
    An empty segment (NOT the only one!). *)
    
PROCEDURE IsEmpty(READONLY s: T): BOOL;
  (*
    TRUE if the segment is empty (has zero samples). *)

PROCEDURE AbsIndex(iRel: INT; READONLY s: T): INT;
  (*
    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. *)

PROCEDURE RelIndex(iAbs: INT; READONLY s: T): INT;
  (*
    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. *)

PROCEDURE AbsIndexClip(i: NAT; READONLY s: T): NAT;
  (*
    Given a sample index "i" relative to the segment "s",
    returns the corresponding sample index in the whole curve. *)
    
PROCEDURE RelIndexClip(i: NAT; READONLY s: T): NAT;
  (*
    Given a sample index "i" in some curve, returns the corresponding
    sample index relative to segment "s" of that curve.
    Returns "LAST(NAT)" if that sample lies outside "s". *)

PROCEDURE Complement(READONLY s: T): T; 
  (* 
    The complement of segment "s" with respect to its parent curve,
    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". *)

PROCEDURE Overlap(READONLY a, b: T): NAT;
  (*
    Maximum number of consecutive samples in common beween
    "a" and "b". Returns 0 if "a" and "b" are on different
    curves or have different orientations. If they intersect
    in two disjoint segments, considers only the longest one. *)

PROCEDURE Join(READONLY a, b: T): T;
  (*
    Joins two segments of the same curve (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. *)
    
PROCEDURE Meet(READONLY a, b: T): T;
  (*
    Returns the intersection of two segments, which must
    belong to the same curve 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. *)

PROCEDURE Expand(
    READONLY s: T;                 (* Segment to expand *)
    iniExtra, finExtra: INT;   (* Number of steps to add/delete. *)
  ): T;
  (*
    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. *)


TYPE
  List = ARRAY OF T;
  
  ReadData = RECORD
      cmt: TEXT;
      s: REF List
    END;

PROCEDURE Write(
    wr :Wr.T; 
    cmt: TEXT;
    READONLY s: List;
  );
  (*
    Writes the list of segments "s" to the writer "wr". *)

PROCEDURE Read(rd :Rd.T): ReadData;
  (*
    Reads from "rd" a list of segments that was written by "Write". *)

PROCEDURE ReadOld(rd :Rd.T; READONLY m: NATS): ReadData;
  (* 
    Reads from "rd" a list of segments that was written BY the old
    version of "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". *)

PROCEDURE GetCurves(READONLY s: List): REF BOOLS;
  (*
    Returns a vector "seen" such that "seen[k]" is TRUE
    iff curve "k" occurs in some segment "s[i]". *)

PROCEDURE Print (wr: Wr.T; READONLY s: T);
  (* 
    Prints the segment descriptor "s" to "wr", in a readable format,
    without trailing newline. *)

END PZSegment.  
     
(*
  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.
*)