/* Copyright (C) 2018-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk4xsp.ctr */ #ifndef DK4XSP_H_INCLUDED /** Avoid multiple inclusions. */ #define DK4XSP_H_INCLUDED 1 #line 9 "dk4xsp.ctr" /** @file dk4xsp.h X-spline segments. @section secxspoverview Overview X-splines were introduced by C. Blanc and C. Schlick on the SIGGRAPH'95, they are described in detail in the paper: "X-Splines: A Spline Model Designed for the End-User". Unfortunately the X-spline implementation in XFig contained a bug for many years, for interpolated splines a wrong coefficient calculation (q=-s instead of q=-0.5s) was used. Probably the resulting unexpected strong curvature and sometimes unwanted oscillations kept people from using interpolated X-splines in XFig. Fixing the bug and introducing the correct calculation would break appearance of existing *.fig files containing interpolated X-splines. So the decision was made to keep the calculation as is. For new interpolated X-splines a factor s=-0.5 is used instead of -1, so the q value does not exceed 0.5. This module contains functions for X-spline calculations, both in correct mode and in XFig compatibility mode. An X-spline is a continuous curve represented by a set of discrete control points. Each control point consists of coordinates (x, y, optionally z) and a shape factor s in range -1 to 1 (positive for approximation points, 0 for corner points, negative for interpolation points). An X-spline segment is the curve range corresponding to two consecutive control points. It is controlled by up to 4 control points: - Control point corresponding to start of segment (index 1), - Control point corresponding to end of segment (index 2), - Neighbour control point "left" from segment start control point (index 0), - Neighbour control point "right" from segment end control point (index 3). For open X-splines there is no left neighbour for the first segment and no right neighbour for the final segment. For closed X-splines the final point is the left neighbour of the first segment and the first point is the right neighbour of the final segment. The t parameter is relative to the segment, it is in the range 0.0<=t<=1.0. @section secxsphighlevel High level API A high level API is available for 2D X-splines using the dk4_xsp_2d_t data type. Before doing any calculation, use dk4xsp2d_reset() to reset the entire structure. Optionally use dk4xsp2d_set_xfig() to set up XFig compatibility mode. For each segment use dk4xsp2d_reset_points() to reset the data in the dk4_xsp_2d_t structure. Now use dk4xsp2d_set_point() with index 0, 1, 2, 3 to set coordinates and shape factors for left neighbour control point of segment, start of segment, end of segment and right neighbour. For the first segment of open X-splines skip index 0 as there is no "left" neighbour. For the final segment of open X-splines skip index 3 as there is no "right" neighbour. To draw an X-spline using polyline/polygon approximation you need to calculate point coordinates, use the dk4xsp2d_calculate_value() function. The t paramater is in the range 0<=t<=1. A pointer to an array of at least 2 elements is required as rp argument, x and y value are stored here. I suggest to use at least 32 subsegments for each X-spline segment. To draw an X-spline using a sequence of Bezier curves you need to calculate point coordinates (x, y) and the first derivatives (dx/dt, dy/dt), use the dk4xsp2d_calculate_value_derivative function. The function stores x, dx/dt, y, dy/dt in the array rp points to. A pointer to an array of at least 4 elements is required as rp argument. I suggest to use at least 4 subsegments for each X-spline segment, 8 subsegments are recommended. @section secxsplowlevel Low level API The low level API calculates values for just one coordinate. Before doing any calculation, use dk4xsp_reset() to reset the entire structure, optionally use dk4xsp_set_xfig() to set up XFig compatibility mode. For each segment use dk4xsp_reset_data() to reset all data components, use dk4xsp_set_point() multiple times with i=(0),1,2,(3) to set shape factors for the control points. Omitted calls with i=0 or i=3 indicate that the neighbour control points are not present. Each point within a segment is represented by a t value in range 0 to 1. For each point use dk4xsp_prepare() first to set up internal coefficients (blending functions values and optionally blending functions derivative values) corresponding to the t value. Next use dk4xsp_calculate() to calculate the coordinate value and optionally the first derivative. After using dk4xsp_prepare() once to set up the segment you can use dk4xsp_calculate() multiple times for different coordinates. The dk4xsp_prepare() function calculates the blending function values and optionally the derivatives value. The dk4xsp_calculate() function applies the blending function values and optionally derivatives to a set of x, y or z coordinates of control points. The same d value must be used in both calls, you can not calculate a derivative value if the structure was not prepared to do so. */ #ifndef DK4ERROR_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4error.h" #else #include #endif #endif /** X-spline coefficients without coordinates. The dk4xsp_set_point() function sets h, s, p, q, dudt. The dk4xsp_prepare() function sets u, f, dfdt. */ typedef struct { double s[4]; /**< Shape factors. */ double p[4]; /**< Coefficients p for blending functions. */ double q[4]; /**< Coefficients q for blending functions. */ double u[4]; /**< Parameter u for blending functions. */ double dudt[4]; /**< Derivative du/dt. */ double f[4]; /**< Blending function results. */ double dfdt[4]; /**< Derivatives df/dt of the blending functions. */ uint8_t h[4]; /**< Availability of coordinates and shape factors. */ uint8_t xfig; /**< Flag: XFig compatibility. */ } dk4_xsp_t; /** X-spline segment in two dimensions. */ typedef struct { double x[4]; /**< X coordinates. */ double y[4]; /**< Y coordinates. */ dk4_xsp_t xsp; /**< Shape factors and coefficients. */ } dk4_xsp_2d_t; #ifdef __cplusplus extern "C" { #endif /* LOW LEVEL API ------------- */ /** Reset X-spline structure including the Xfig compatibility flag. @param xsp Spline structure to reset. */ void dk4xsp_reset(dk4_xsp_t *xsp); /** Reset data components in X-spline structure, leave Xfig compatibility flag unchanged. @param xsp Spline structure to reset. */ void dk4xsp_reset_data(dk4_xsp_t *xsp); /** Set or reset xfig compatibility flag. @param xsp Spline structure to modify. @param val New Xfig compatibility flag value. */ void dk4xsp_set_xfig(dk4_xsp_t *xsp, uint8_t val); /** Set shape factor for one control point, calculate values derived from shape factor. Used 2 to 4 times to set up a segment. @param xsp Spline structure to modify. @param s Shape factor @param i Index of control point: 0=left neighbour, 1=segment start, 2=segment end, 3=right neighbour. */ void dk4xsp_set_point( dk4_xsp_t *xsp, double s, size_t i ); /** Prepare calculations for one t value. @param xsp Spline structure to prepare. @param t Parameter t in range 0 to 1. @param d Prepare to calculate derivative. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if invalid arguments were passed to the function. */ int dk4xsp_prepare( dk4_xsp_t *xsp, double t, int d, dk4_er_t *erp ); /** Calculations for one t value. For d=0 the function just calculates the position, rp is a pointer to one result variable. For other d values the function also calculates the first derivative, rp is a pointer to an array of two elements: position and derivative. @param rp Result variable or array address. @param xsp Spline structure to use. @param x Coordinates values: 4 elements for values at left neighbour, left border, right border and right neighbour. @param d Flag: Calculate derivative too. @param erp Error report for diagnostics. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if invalid arguments were passed to the function, - DK4_E_MATH_OVERFLOW
if a mathematical overflow occured in the calculation. */ int dk4xsp_calculate( double *rp, dk4_xsp_t const *xsp, double const *x, int d, dk4_er_t *erp ); /* HIGH LEVEL API FOR 2D X-SPLINES ------------------------------- */ /** Reset spline structure completely. @param sp Spline structure to reset. */ void dk4xsp2d_reset( dk4_xsp_2d_t *sp ); /** Set or reset XFig compatibility flag. @param sp Spline structure to set up. @param val New flag value. */ void dk4xsp2d_set_xfig( dk4_xsp_2d_t *sp, uint8_t val ); /** Reset spline structure to "all points unset". @param sp Spline structure to reset. */ void dk4xsp2d_reset_points( dk4_xsp_2d_t *sp ); /** Set one point in spline structure. @param sp Spline structure to set up. @param x X coordinate. @param y Y coordinate. @param s Shape factor. @param i Index (0=A, 1=B, 2=C, 3=D). */ void dk4xsp2d_set_point( dk4_xsp_2d_t *sp, double x, double y, double s, size_t i ); /** Calculate just the value at a given point. @param rp Address of results array, 2 elements: rp[0]=x, rp[1]=y. @param sp Spline structure to use. @param t Value t in range 0 to 1. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if invalid arguments were passed to the function, - DK4_E_MATH_OVERFLOW
if a numeric overflow occured in calculation. */ int dk4xsp2d_calculate_value( double *rp, dk4_xsp_2d_t *sp, double t, dk4_er_t *erp ); /** Calculate values and first derivative. @param rp Address of results array, 4 elements: rp[0]=x, rp[1]=dx/dt, rp[2]=y, rp[3]=dy/dt. @param sp Spline structure to use. @param t Value t in range 0 to 1. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if invalid arguments were passed to the function, - DK4_E_MATH_OVERFLOW
if a numeric overflow occured in calculation. */ int dk4xsp2d_calculate_value_derivative( double *rp, dk4_xsp_2d_t *sp, double t, dk4_er_t *erp ); /** Check whether the segment is a line (Shape factor s is 0 for points 1 and 2). This check can be applied after setting the control points for the segment. @param sp Spline segment to check. @return 1 for lines, 0 for curved spline segment. */ int dk4xsp2d_is_line(dk4_xsp_2d_t const *sp); /** Calculate X-spline segment length. @param rp Address of result variable. @param sp Spline segment to calculate length for. @param eps Tolerance to stop iteration. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if invalid arguments were passed to the function, - DK4_E_MATH_OVERFLOW
if a numeric overflow occured in calculation, - DK4_E_NOT_FOUND
if the iteration did not succeed. */ int dk4xsp2d_calculate_length( double *rp, dk4_xsp_2d_t *sp, double eps, dk4_er_t *erp ); /** Calculate partial X-spline segment length from 0 to t_end. @param rp Address of result variable. @param sp Spline segment to calculate length for. @param tend End value for parameter t. @param eps Tolerance to stop iteration. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if invalid arguments were passed to the function, - DK4_E_MATH_OVERFLOW
if a numeric overflow occured in calculation, - DK4_E_NOT_FOUND
if the iteration did not succeed. */ int dk4xsp2d_calculate_partial_length( double *rp, dk4_xsp_2d_t *sp, double tend, double eps, dk4_er_t *erp ); #ifdef __cplusplus } #endif /* vim: set ai sw=4 ts=4 : */ #endif