#ifndef frb_curve_H
#define frb_curve_H

/* Sequences of points of {R^3}, closed or open. */
/* Last edited on 2004-12-31 12:20:05 by stolfi */

#include <r3.h>
#include <r4x4.h>
#include <frb_signal.h>
#include <frb_segment.h>
#include <frb_window.h>
#include <frb_types.h>

typedef r3_vec_t frb_curve_t;
  /* A sequence of points of {R^3}, often used to represent points on
    the plane (with the third component set to zero). The elements may
    be also velocities or accelerations. The curve may be interpreted
    as a polygonal or a spline, closed or open, depending on the
    context. */

#define frb_curve_new r3_vec_new

/* BASIC MANIPULATION */

/*
  The {DoXXX} procedures below are analogous to the {XXX} procedures,
  except that the result is returned in an array provided by the
  client (which must have the correct size). */

frb_curve_t frb_curve_from_line_segment ( r3_t *p, r3_t *q, int n );
  /* Creates a curve with {n} points equally spaced
    along the segment {p--q}. */

frb_curve_t frb_curve_trim ( frb_curve_t *c, int start, int length );

void frb_curve_do_trim 
  ( frb_curve_t *c,
    int start,
    int length,
    frb_curve_t *x
  );
  /* Returns a new curve that is a copy of elements from {c[start]}
    to {c[start+length-1]}.  Assumes the curve is periodic, i.e.
    {c[i+n]==c[i]} for all {i}, where {n==(c.nel)}. */

void frb_curve_reverse ( frb_curve_t *c );
  /* frb_curve_reverses the direction of traversal of the Curve {c}. */

frb_curve_t frb_curve_extract_segment ( frb_curve_t *c, frb_segment_t *s );
  /* Extracts from {c} the part described by {s},
    reversing it if {s.rev} is TRUE. */

void frb_curve_do_extract_segment ( frb_curve_t *c, frb_segment_t *s, frb_curve_t *t );
  /* Same as {frb_curve_extract_segment} but stores the result
    in the preallocated curve {*t}. */

r3_t frb_curve_sample_barycenter ( frb_curve_t *c );
  /* The barycenter of all points of the curve. */

r3_t frb_curve_area_barycenter ( frb_curve_t *c );
  /* Returns the barycenter {b} of the projection of {c} on the
    XY plane, seen as a polygonal *area*, with {b[2] == 0}. */

frb_window_t frb_curve_get_window ( frb_curve_t *c );
  /* Returns the curve's bounding box. */

frb_curve_t frb_curve_translate ( frb_curve_t *c, r3_t t );

void frb_curve_do_translate ( frb_curve_t *c, r3_t t );
  /* Translates {c} by the vector {t}. {frb_curve_translate} makes a
    new copy and translates it, leaving {c} unchanged;
    {frb_curve_do_translate} modifies {c} itself. */

frb_curve_t frb_curve_map ( frb_curve_t *c, r4x4_t *M );

void frb_curve_do_map ( frb_curve_t *c, r4x4_t *M );
  /* Maps {c} by the given projective transformation.  {frb_curve_map} makes a
    new copy and transforms it, leaving {c} unchanged; {frb_curve_do_map}
    modifies {c} itself. */

r4x4_t frb_curve_normalization_matrix ( frb_curve_t *c, bool_t reverse );
  /* Returns a matrix that moves the first sample of {c} to the
    origin, and the last sample to a point on the positive {X}-axis.
    If {reverse} is true, reverses the roles of the first and last
    samples. Requires that the line be open. */

r4x4_t frb_curve_alignment_matrix ( frb_curve_t *a, frb_curve_t *b, double pos );
  /* Given two open curves {a} and {b}, returns a matrix that moves the
    barycenter of {a} to the barycenter of {b}, and rotates {a} so
    that its general direction is parallel to the general direction of {b}.
    The general direction is computed from two points {pos*n} steps away from
    each    end, where {n} is the total steps in the curve. */

/* CURVES AS CLOSED POLYGONS */

/*
  The procedures in this section interpret the curve {p} as the
  vertices of a closed polygonal curve with {m == (p.nel)} sides.  It
  is assumed that each edge is traversed at constant speed, in such a
  way that the curve reaches vertex {p[i]} at time {t[i]}, for {i IN
  [0..m-1]}; and the curve goes back to vertex {p[0]} at time {t[0] + tPeriod}. */

double frb_curve_linear_lengths ( frb_curve_t *p, frb_signal_t *s );
  /* Assumes that {p[j]} is the curve position at time {t[j]}.
    Computes the Euclidean length {s[j]} on the polygonal from
    vertex {p[0]} to vertex {p[j]}, for {j} in {[0..(p.nel - 1)]}.
    Returns the total length of the polygonal as the result of the call. */

void frb_curve_linear_uniform_sample 
  ( frb_signal_t *t,  /* Times of input samples. */
    double tPeriod,        /* Time period */
    frb_curve_t *p,      /* {p[i]} is curve position at time {t[i]}. */
    double tStart,         /* Time of first output sample */
    frb_curve_t *q       /* {q[j]} will be position sample number {j}. */
  );
  /* Computes {n} samples along the curve, equally spaced in time, starting
    with time {tStart}.  The samples are returned in {q[j]}, {j IN [0..n-1]}. */

void frb_curve_linear_equidistant_sample 
  ( frb_curve_t *p,  /* {p[i]} is curve position at time {t[i]}. */
    double tStart,     /* Time of first output sample */
    frb_curve_t *q   /* {q[j]} will be position sample number {j}. */
  );
  /* Same as {frb_curve_linear_uniform_sample}, assuming that the 
    curve is traversed with constant velocity in unit time. */

void frb_curve_linear_time_sample 
  ( frb_signal_t *t,  /* Times of input samples. */
    double tPeriod,        /* Time period */
    frb_curve_t *p,      /* Input curve positions at times {t[i]}. */
    frb_signal_t *r,  /* Times of output samples. */
    frb_curve_t *q       /* Output curve positions at times {r[j]}. */
  );
  /* Computes the positions {q[j]} at the specified times {tq[j]},
    {j IN [0..n-1]}. */

/* CURVES AS CLOSED C_1 CUBIC SPLINES */

/*
  The procedures in this section interpret the curves {p} and {dp} as the
  positions and velocities of a closed spline curve with {m == (p.nel)}
  cubic arcs, at the nodal times {t[0..m-1]}.  It is assumed the curve
  goes back to vertex {p[0]} and velocity {dp[0]} at time {t[0] + tPeriod}. */

void frb_curve_hermite_uniform_sample 
  ( frb_signal_t *t,  /* Times of input samples. */
    double tPeriod,        /* Time period */
    frb_curve_t *p,      /* {p[i]} is curve position at time {t[i]}. */
    frb_curve_t *dp,     /* {dp[i]} is velocity at time {t[i]}. */
    double tStart,         /* Time of first output sample */
    frb_curve_t *q,      /* {q[j]} will be position sample number {j}. */
    frb_curve_t *dq      /* {dq[j]} will be velocity at point {q[j]}. */
  );
  /* Computes {n} samples {q[0..n-1]} along the curve, and their
    velocities {dq[0..n-1]}, equally spaced in time, starting
    with time {tStart}. */

void frb_curve_hermite_equidistant_sample 
  ( frb_curve_t *p,  /* {p[i]} is curve position at time {t[i]}. */
    double tStart,     /* Time of first output sample */
    frb_curve_t *q,  /* {q[j]} will be position sample number {j}. */
    frb_curve_t *dq  /* {dq[j]} will be velocity at point {q[j]}. */
  );
  /* Same as {frb_curve_hermite_uniform_sample}, assuming that
    the curve is traversed with constant velocity in the 
    total time {tPeriod}. */

void frb_curve_hermite_time_sample 
  ( frb_signal_t *t,  /* Times of input samples. */
    double tPeriod,        /* Time period */
    frb_curve_t *p,      /* {p[i]} is curve position at time {t[i]}. */
    frb_curve_t *dp,     /* {dp[i]} is velocity at time {t[i]}. */
    frb_signal_t *r,  /* Times of output samples. */
    frb_curve_t *q,      /* {q[j]} will be curve position at time {r[j]}. */
    frb_curve_t *dq      /* {dq[j]} will be velocity at time {r[j]}. */
  );
  /* Computes the positions {q[j]} and velocities {dq[j]} at the specified
    times {r[j]}, {j IN [0..n-1]}. */

typedef r3_t frb_curve_vel_estimator_t 
  ( double a,
    r3_t *pa,
    double b,
    r3_t *pb,
    double c,
    r3_t *pc
  );

void frb_curve_estimate_velocities 
  ( frb_signal_t *t,
    double tPeriod,
    frb_curve_t *p,
    frb_curve_t *dp,
    frb_curve_vel_estimator_t est
  );
  /* Estimates the velocity {dp[i]} at each point {p[i]},
    by applying the estimator {est} to three consecutive times. */

/* INPUT/OUTPUT */

double frb_curve_adjust_unit ( double givenUnit, frb_curve_t *c );
  /* Adjusts the {givenUnit} if needed to avoid overflow
    or excessive error when quantizing the values in {c}.
    May print warnings to {stderr}. */

typedef
  struct frb_curve_read_data_t
    { char *cmt;         /* Comment text. */
      int samples;       /* Number of samples in curve. */
      frb_curve_t c;     /* The samples. */
      double unit;       /* Quantization unit used. */
    } frb_curve_read_data_t;

frb_curve_read_data_t frb_curve_read
  ( FILE *rd,
    double scale,
    bool_t header_only, 
    bool_t centralize
  );
  /* Reads a curve (and its comments) from {rd}. The curve is
    magnified by the given {scale} factor. If {header_only==TRUE},
    reads only the parameters, and leaves the {c} field as NULL. If
    {centralize==TRUE}, displaces the curve so that its
    {frb_curve_area_barycenter} lies at the origin. */

void frb_curve_write
  ( FILE *wr,
    char *cmt,
    frb_curve_t *c,
    double unit,
    double scale
  );
  /* Writes curve {c} to {wr}, prefixed with comments {cmt}. The
    coordinates will be written as integer multiples of the given
    {unit}. The curve coordinates (as well as the {unit}) are
    automatically scaled by {1/scale}. */

typedef
  struct frb_curve_list_read_data_t
    { frb_curve_read_data_t **sgData;
      int ncv;         /* Number of entries in {sgData}. */
      double unitMin;  /* Minimum quantization unit. */
      double unitMax;  /* Maximum quantization unit. */
      char *cmt;       /* Comment of first curve, if any. */
    } frb_curve_list_read_data_t;

frb_curve_list_read_data_t frb_curve_list_read
  ( char *dir,
    char *fileName,
    double scale,
    bool_vec_t *sel,
    bool_t header_only,
    bool_t centralize
  );
  /* Reads a set of numbered curves, scales them by the given {scale}
    factor. Curve number {i} is read if and only if {sel[i] == TRUE},
    and its {frb_curve_read_data_t} is stored in {r.curve[i]};
    otherwise {r.curve[i] } is set to a record with null {c} field.

    The data is read from file "{dir}/{KKKK}/{fileName}", where {KKKK}
    is the curve number {k} (4 digits, zero padded).

    If {header_only} is TRUE, only the header of each file is read;
    the {c} fields are all set to NULL.

    The range of quantization {unit}s of the curves that were read,
    after scaling, is returned in {r.unitMin}, {r.unitMax}. The
    comment of the first curve read, plus the call arguments, are
    stored in {r.cmt}. */

#endif
