Metropoli BBS
VIEWER: cbsp_aux.c MODE: TEXT (ASCII)
/******************************************************************************
* CBsp-Aux.c - Bspline curve auxilary routines.				      *
*******************************************************************************
* Written by Gershon Elber, Aug. 90.					      *
******************************************************************************/

#ifdef __MSDOS__
#include <stdlib.h>
#endif /* __MSDOS__ */

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "cagd_loc.h"

/******************************************************************************
* Given a bspline curve - subdivide it into two at the given parametric value.*
* Returns pointer to first curve in a list of two curves (subdivided ones).   *
* The subdivision is achieved by inserting (order-1) knot at the given param. *
* value t and spliting the control polygon and knot vector at that point.     *
******************************************************************************/
CagdCrvStruct *BspCrvSubdivAtParam(CagdCrvStruct *Crv, CagdRType t)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    int j,
	k = Crv -> Order,
	Len = Crv -> Length,
        KVLen = k + Len,
	Index1 = BspKnotLastIndexL(Crv -> KnotVector, KVLen, t),
	Index2 = BspKnotFirstIndexG(Crv -> KnotVector, KVLen, t),
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdCrvStruct
	*RefinedCrv = BspCrvKnotInsertNSame(Crv, t, k - 1),
	*LCrv = BspCrvNew(Index1 + 1, k, Crv -> PType),
	*RCrv = BspCrvNew(Len - Index2 + k, k, Crv -> PType);

    /* Copy Curve into LCrv. */
    for (j = IsNotRational; j <= MaxCoord; j++)
	GEN_COPY(LCrv -> Points[j],
		 RefinedCrv -> Points[j],
                 sizeof(CagdRType) * (Index1 + 1));
    GEN_COPY(LCrv -> KnotVector,
	     RefinedCrv -> KnotVector,
	     sizeof(CagdRType) * (Index1 + k));
    /* Close the knot vector with multiplicity Order: */
    LCrv -> KnotVector[Index1 + k] = LCrv -> KnotVector[Index1 + k - 1];

    /* Copy Curve into RCrv. */
    for (j = IsNotRational; j <= MaxCoord; j++)
	GEN_COPY(RCrv -> Points[j],
		 &RefinedCrv -> Points[j][Index1],
		 sizeof(CagdRType) * (Len - Index2 + k));
    GEN_COPY(&RCrv -> KnotVector[1],
	     &RefinedCrv -> KnotVector[Index1 + 1],
	     sizeof(CagdRType) * (Len - Index2 + k + k - 1));
    /* Make sure knot vector starts with multiplicity Order: */
    RCrv -> KnotVector[0] = RCrv -> KnotVector[1];

    LCrv -> Pnext = RCrv;

    CagdCrvFree(RefinedCrv);

    return LCrv;
}

/******************************************************************************
* Return a new curve, identical to the original but with one degree higher    *
******************************************************************************/
CagdCrvStruct *BspCrvDegreeRaise(CagdCrvStruct *Crv)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    int i, i2, j, RaisedLen,
	Order = Crv -> Order,
	Length = Crv -> Length,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdCrvStruct *RaisedCrv;

    if (Order > 2) {
	FATAL_ERROR(CAGD_ERR_NOT_IMPLEMENTED);
	return NULL;
    }

    /* If curve is linear, degree raising means basically to increase the     */
    /* knot multiplicity of each segment by one and add a middle point for    */
    /* each such segment.						      */
    RaisedLen = Length * 2 - 1;
    RaisedCrv = BspCrvNew(RaisedLen, Order + 1, Crv -> PType);

    /* Update the control polygon; */
    for (j = IsNotRational; j <= MaxCoord; j++)		      /* First point. */
	RaisedCrv -> Points[j][0] = Crv -> Points[j][0];

    for (i = 1, i2 = 1; i < Length; i++, i2 += 2)
	for (j = IsNotRational; j <= MaxCoord; j++) {
	    RaisedCrv -> Points[j][i2] =
		Crv -> Points[j][i-1] * 0.5 + Crv -> Points[j][i] * 0.5;
	    RaisedCrv -> Points[j][i2 + 1] = Crv -> Points[j][i];
	}

    /* Update the knot vector. */
    for (i = 0; i < 3; i++)
	RaisedCrv -> KnotVector[i] = Crv -> KnotVector[0];

    for (i = 2, j = 3; i < Length; i++, j += 2)
	RaisedCrv -> KnotVector[j] = RaisedCrv -> KnotVector[j + 1] = 
	    Crv -> KnotVector[i];

    for (i = j; i < j + 3; i++)
	RaisedCrv -> KnotVector[i] = Crv -> KnotVector[Length];

    return RaisedCrv;
}

/******************************************************************************
* Return a normalized vector, equal to the tangent to Crv at parameter t.     *
* Algorithm: insert (order - 1) knots and return control polygon tangent.     *
******************************************************************************/
CagdVecStruct *BspCrvTangent(CagdCrvStruct *Crv, CagdRType t)
{
    static CagdVecStruct P2;
    CagdVecStruct P1;
    CagdRType TMin, TMax;
    int k = Crv -> Order,
	Len = Crv -> Length,
	Index = BspKnotLastIndexL(Crv -> KnotVector, k + Len, t);
    CagdPointType
	PType = Crv -> PType;
    CagdCrvStruct *RefinedCrv;

    if (!BspKnotParamInDomain(Crv -> KnotVector, Len, k, t))
	FATAL_ERROR(CAGD_ERR_T_NOT_IN_CRV);

    BspCrvDomain(Crv, &TMin, &TMax);

    if (APX_EQ(t, TMin)) {
	/* Use Crv starting tangent direction. */
	CagdCoerceToE3(P1.Vec, Crv -> Points, 0, PType);
	CagdCoerceToE3(P2.Vec, Crv -> Points, 1, PType);
    }
    else if (APX_EQ(t, TMax)) {
	/* Use Crv ending tangent direction. */
	CagdCoerceToE3(P1.Vec, Crv -> Points, Len - 2, PType);
	CagdCoerceToE3(P2.Vec, Crv -> Points, Len - 1, PType);
    }
    else {
	RefinedCrv = BspCrvKnotInsertNSame(Crv, t, k - 1);

	CagdCoerceToE3(P1.Vec, RefinedCrv -> Points, Index, PType);
	CagdCoerceToE3(P2.Vec, RefinedCrv -> Points, Index + 1, PType);

	CagdCrvFree(RefinedCrv);
    }

    CAGD_SUB_VECTOR(P2, P1);

    CAGD_NORMALIZE_VECTOR(P2);			    /* Normalize the vector. */

    return &P2;
}

/******************************************************************************
* Return a normalized vector, equal to the binormal to Crv at parameter t.    *
* Algorithm: insert (order - 1) knots and using 3 consecutive control points  *
* at the refined location (p1, p2, p3), compute to binormal to be the cross   *
* product of the two vectors (p1 - p2) and (p2 - p3).			      *
******************************************************************************/
CagdVecStruct *BspCrvBiNormal(CagdCrvStruct *Crv, CagdRType t)
{
    static CagdVecStruct P3;
    CagdVecStruct P1, P2;
    CagdRType TMin, TMax;
    int k = Crv -> Order,
	Len = Crv -> Length,
	Index = BspKnotLastIndexL(Crv -> KnotVector, k + Len, t);
    CagdPointType
	PType = Crv -> PType;
    CagdCrvStruct *RefinedCrv;

    if (!BspKnotParamInDomain(Crv -> KnotVector, Len, k, t))
	FATAL_ERROR(CAGD_ERR_T_NOT_IN_CRV);

    /* Can not compute for linear curves. */
    if (k <= 2) return NULL;

    BspCrvDomain(Crv, &TMin, &TMax);

    if (APX_EQ(t, TMin)) {
	/* Use Crv starting tangent direction. */
	CagdCoerceToE3(P1.Vec, Crv -> Points, 0, PType);
	CagdCoerceToE3(P2.Vec, Crv -> Points, 1, PType);
	CagdCoerceToE3(P3.Vec, Crv -> Points, 2, PType);
    }
    else if (APX_EQ(t, TMax)) {
	/* Use Crv ending tangent direction. */
	CagdCoerceToE3(P1.Vec, Crv -> Points, Len - 3, PType);
	CagdCoerceToE3(P2.Vec, Crv -> Points, Len - 2, PType);
	CagdCoerceToE3(P3.Vec, Crv -> Points, Len - 1, PType);
    }
    else {
	RefinedCrv = BspCrvKnotInsertNSame(Crv, t, k - 1);

	CagdCoerceToE3(P1.Vec, RefinedCrv -> Points, Index, PType);
	CagdCoerceToE3(P2.Vec, RefinedCrv -> Points, Index + 1, PType);
	CagdCoerceToE3(P3.Vec, RefinedCrv -> Points, Index + 2, PType);

	CagdCrvFree(RefinedCrv);
    }

    CAGD_SUB_VECTOR(P1, P2);
    CAGD_SUB_VECTOR(P2, P3);

    CROSS_PROD(P3.Vec, P1.Vec, P2.Vec);

    if ((t = CAGD_LEN_VECTOR(P3)) < EPSILON)
	return NULL;
    else
	CAGD_DIV_VECTOR(P3, t);			    /* Normalize the vector. */

    return &P3;
}

/******************************************************************************
* Return a normalized vector, equal to the normal to Crv at parameter t.      *
* Algorithm: returns the cross product of the curve tangent and binormal.     *
******************************************************************************/
CagdVecStruct *BspCrvNormal(CagdCrvStruct *Crv, CagdRType t)
{
    static CagdVecStruct N, *T, *B;

    T = BspCrvTangent(Crv, t);
    B = BspCrvBiNormal(Crv, t);

    if (T == NULL || B == NULL) return NULL;

    CROSS_PROD(N.Vec, T -> Vec, B -> Vec);

    CAGD_NORMALIZE_VECTOR(N);			    /* Normalize the vector. */

    return &N;
}

/******************************************************************************
* Return a new curve, equal to the derived curve. If the original curve is    *
* rational, NULL is return (curve must be non-rational for this one).	      *
* Let old control polygon be P(i), i = 0 to k-1, and Q(i) be new one then:    *
* Q(i) = (k - 1) * P(i+1) - P(i), i = 0 to k-2.				      *
******************************************************************************/
CagdCrvStruct *BspCrvDerive(CagdCrvStruct *Crv)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    int i, j,
	k = Crv -> Order,
	Len = Crv -> Length,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdCrvStruct *DerivedCrv;

    if (!IsNotRational || k < 3)
	FATAL_ERROR(CAGD_ERR_RAT_LIN_NO_SUPPORT);

    DerivedCrv = BspCrvNew(Len - 1, k - 1, Crv -> PType);

    for (i = 0; i < Len - 1; i++)
	for (j = IsNotRational; j <= MaxCoord; j++)
	    DerivedCrv -> Points[j][i] =
		(k - 1) * (Crv -> Points[j][i+1] - Crv -> Points[j][i]);

    GEN_COPY(DerivedCrv -> KnotVector,
    	     &Crv -> KnotVector[1],
    	     sizeof(CagdRType) * (k + Len - 2));

    return DerivedCrv;
}
[ RETURN TO DIRECTORY ]