/*
Copyright (c) 2004-2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/



/**	@file	dkxsp.h	X-spline module.

To calculate x, y, dx/dt and dy/dt for a given t between the control
points B and C we also need values from the control points A and D
next to B and C. See the section "X-Splines" in the chapter
"Technical Details" in fig2vect.pdf for calculation details.

First use dkxsp_reset() to reset the structure.

Next use dkxsp_setA(), dkxsp_setB(), dkxsp_setC(), dkxsp_setD()
and dkxsp_set_pos() to specify the control points and the position
of the segment in the spline.

Use dkxsp_step1() to find the control function types and calculate
the control function coefficients.

Now you can use dkxsp_step2() to calculate x, y, dx/dt and dy/dt
values for a given t in the range \f$0\leq{}t\leq{}1\f$.
The dkxsp_step2() function can be used multiple times if
necessary.
*/



#ifndef DK_XSP_INC



/** Protection from multiple inclusions. */
#define DK_XSP_INC 1



#include <dk.h>



/**	X-spline calculation structure.
*/
typedef struct {
  double	t;	/**< t for calculation.*/
  double	x;	/**< x value. */
  double	y;	/**< y value. */
  double	ddtx;	/**< dx/dt. */
  double	ddty;	/**< dy/dt. */
  int		usea;	/**< Flag: Use function from control point A. */
  int		useb;	/**< Flag: Use function from control point B. */
  int		usec;	/**< Flag: Use function from control point C. */
  int		used;	/**< Flag: Use function from control point D. */
  int		gha;	/**< Flag: Use g-h-blend from point A. */
  int		ghb;	/**< Flag: Use g-h-blend from point B. */
  int		ghc;	/**< Flag: Use g-h-blend from point C. */
  int		ghd;	/**< Flag: Use g-h-blend from point D. */
  double	sa;	/**< s-value at A. */
  double	sb;	/**< s-value at B. */
  double	sc;	/**< s-value at C. */
  double	sd;	/**< s-value at D. */
  double	Ta;	/**< \f$T_A^+\f$ */
  double	Tb;	/**< \f$T_B^+\f$ */
  double	Tc;	/**< \f$T_C^-\f$ */
  double	Td;	/**< \f$T_D^-\f$ */
  double	pa;	/**< p-value at A. */
  double	pb;	/**< p-value at B. */
  double	pc;	/**< p-value at C. */
  double	pd;	/**< p-value at D. */
  double	qa;	/**< q-value at A. */
  double	qb;	/**< q-value at B. */
  double	qc;	/**< q-value at C. */
  double	qd;	/**< q-value at D. */
  double	xa;	/**< x-value at A. */
  double	xb;	/**< x-value at B. */
  double	xc;	/**< x-value at C. */
  double	xd;	/**< x-value at D. */
  double	ya;	/**< y-value at A. */
  double	yb;	/**< y-value at B. */
  double	yc;	/**< y-value at C. */
  double	yd;	/**< y-value at D. */
  double	dudta;	/**< du_A/dt. */
  double	dudtb;	/**< du_B/dt. */
  double	dudtc;	/**< du_C/dt. */
  double	dudtd;	/**< du_D/dt. */
  int		docor;		/**< Flag: Do corrections on open splines. */
} dk_xspline_t;

#if defined(EXTERN)
#undef EXTERN
#endif
/** Access function in external module. */
#if defined(DK_XSP_C)
#define EXTERN /* nix */
#else
#if DK_HAVE_PROTOTYPES
#define EXTERN /* nix */
#else
#define EXTERN extern
#endif
#endif



#if defined(__cplusplus)
extern "C" {
#endif



/**	Reset all components.
	@param	s	X-spline calculation structure to reset.
*/
EXTERN void
dkxsp_reset DK_PR((dk_xspline_t *s));

/**	Set values for point A.
	@param	s	X-spline calculation structure.
	@param	sk	s-value.
	@param	x	x-value.
	@param	y	y-value.
*/
EXTERN void
dkxsp_setA DK_PR((dk_xspline_t *s, double sk, double x, double y));

/**	Set values for point B.
	@param	s	X-spline calculation structure.
	@param	sk	s-value.
	@param	x	x-value.
	@param	y	y-value.
*/
EXTERN void
dkxsp_setB DK_PR((dk_xspline_t *s, double sk, double x, double y));

/**	Set values for point C.
	@param	s	X-spline calculation structure.
	@param	sk	s-value.
	@param	x	x-value.
	@param	y	y-value.
*/
EXTERN void
dkxsp_setC DK_PR((dk_xspline_t *s, double sk, double x, double y));

/**	Set values for point D.
	@param	s	X-spline calculation structure.
	@param	sk	s-value.
	@param	x	x-value.
	@param	y	y-value.
*/
EXTERN void
dkxsp_setD DK_PR((dk_xspline_t *s, double sk, double x, double y));

/**	Set spline position.
	@param	s	X-spline calculation structure.
	@param	c	Index of current segment (0 is first, m-2 is last).
	@param	m	Number of control points.
	@param	isc	Flag: Closed spline (1) or open spline (0).
*/
EXTERN void
dkxsp_set_pos DK_PR((dk_xspline_t *s, size_t c, size_t m, int isc));

/**	Step 1: Calculations with no t involved.
	- Check where to interpolate or to approximate.
	- Calculate coefficients for control functions.
	@param	s	X-spline calculation structure.
*/
EXTERN void
dkxsp_step1 DK_PR((dk_xspline_t *s));

/**	Step 2: Calculate x, y, dx/dt and dy/dt for a
	given t.
	@param	s	X-spline calculation structure.
	@param	t	t-value (0<=t<=1).
	@return	1 on success, 0 on error (mathmematical error).
*/
EXTERN int
dkxsp_step2 DK_PR((dk_xspline_t *s, double t));
#if defined(__cplusplus)
}
#endif

#endif

