Metropoli BBS
VIEWER: cagd_aux.c MODE: TEXT (ASCII)
/******************************************************************************
* Cagd_aux.c - auxiliary routine to interface to different free from types.   *
*******************************************************************************
* Written by Gershon Elber, July. 90.					      *
******************************************************************************/

#include "cagd_loc.h"

/******************************************************************************
* Given a crv and parameter value t, evaluate the curve at t.		      *
******************************************************************************/
CagdRType *CagdCrvEval(CagdCrvStruct *Crv, CagdRType t)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    return BzrCrvEvalAtParam(Crv, t);
	case CAGD_CBSPLINE_TYPE:
	    return BspCrvEvalAtParam(Crv, t);
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }
}

/******************************************************************************
* Given a srf and parameter values u,v, evaluate the surface at u,v.	      *
******************************************************************************/
CagdRType *CagdSrfEval(CagdSrfStruct *Srf, CagdRType u, CagdRType v)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    return BzrSrfEvalAtParam(Srf, u, v);
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfEvalAtParam(Srf, u, v);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Given a curve - subdivide it into two at the given parametric value.        *
* Returns pointer to first curve in a list of two curves (subdivided ones).   *
******************************************************************************/
CagdCrvStruct *CagdCrvSubdivAtParam(CagdCrvStruct *Crv, CagdRType t)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    return BzrCrvSubdivAtParam(Crv, t);
	case CAGD_CBSPLINE_TYPE:
	    return BspCrvSubdivAtParam(Crv, t);
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }
}

/******************************************************************************
* Given a curve - returns a sub region within the specified domain.           *
******************************************************************************/
CagdCrvStruct *CagdCrvRegionFromCrv(CagdCrvStruct *Crv, CagdRType t1,
							CagdRType t2)
{
    CagdRType TMin, TMax;
    CagdCrvStruct *Crvs;
    CagdBType
	NewCrv = FALSE;

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    TMin = 0.0;
	    TMax = 1.0;
	    break;
	case CAGD_CBSPLINE_TYPE:
    	    BspCrvDomain(Crv, &TMin, &TMax);
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }

    if (t1 > t2) SWAP(CagdRType, t1, t2);

    if (!APX_EQ(t1, TMin)) {
    	Crvs = CagdCrvSubdivAtParam(Crv, t1);
	Crv = Crvs -> Pnext;
	Crvs -> Pnext = NULL;
	CagdCrvFree(Crvs);			   /* Free the first region. */
	NewCrv = TRUE;
    }

    if (APX_EQ(t2, TMax))
	return NewCrv ? Crv : CagdCrvCopy(Crv);
    else {
	Crvs = CagdCrvSubdivAtParam(Crv, t2);

	if (NewCrv) CagdCrvFree(Crv);

    	CagdCrvFree(Crvs -> Pnext);		  /* Free the second region. */
    	Crvs -> Pnext = NULL;
    	return Crvs;				/* Returns the first region. */
    }
}

/******************************************************************************
* Given a curve - refine it at the given n knots as defined by vector t.      *
* If Replace is TRUE, the values replaces current vector instead.	      *
* Returns pointer to refined crv (Note Bezier will be converted into spline). *
******************************************************************************/
CagdCrvStruct *CagdCrvRefineAtParams(CagdCrvStruct *Crv, CagdBType Replace,
							 CagdRType *t, int n)
{
    CagdCrvStruct *BspCrv, *TCrv;

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
    	    BspCrv = CnvrtBezier2BsplineCrv(Crv);
	    TCrv = BspCrvKnotInsertNDiff(BspCrv, Replace, t, n);
	    CagdCrvFree(BspCrv);
	    return TCrv;
	case CAGD_CBSPLINE_TYPE:
	    return BspCrvKnotInsertNDiff(Crv, Replace, t, n);
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }
}

/******************************************************************************
* Return a new curve reversed by reversing the ctl polygon.                   *
******************************************************************************/
CagdCrvStruct *CagdCrvReverse(CagdCrvStruct *Crv)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    int i, Len, Col,
	Length = Crv -> Length,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdCrvStruct
        *ReversedCrv = CagdCrvCopy(Crv);
    CagdRType *KV,
	**Points = ReversedCrv -> Points;

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	case CAGD_CBSPLINE_TYPE:
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }

    /* Reverse the Ctl Polygon: */
    Len = Length / 2;
    for (Col = 0; Col < Len; Col++)
	for (i = IsNotRational; i <= MaxCoord; i++)
	    SWAP(CagdRType,
		 Points[i][Col],
		 Points[i][Length - Col - 1]);

    /* Reverse the knot vector if it exists: */
    if (Crv -> GType == CAGD_CBSPLINE_TYPE &&
	Crv -> KnotVector != NULL) {
	KV = BspKnotReverse(Crv -> KnotVector, Crv -> Order + Length);
	CagdFree((VoidPtr) ReversedCrv -> KnotVector);
	ReversedCrv -> KnotVector = KV;
    }

    return ReversedCrv;
}

/******************************************************************************
* Return a new curve representing the same curve but with degree raised.      *
******************************************************************************/
CagdCrvStruct *CagdCrvDegreeRaise(CagdCrvStruct *Crv)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    return BzrCrvDegreeRaise(Crv);
	case CAGD_CBSPLINE_TYPE:
	    return BspCrvDegreeRaise(Crv);
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Return a new surface representing the same surface but with degree raised.  *
******************************************************************************/
CagdSrfStruct *CagdSrfDegreeRaise(CagdSrfStruct *Srf, CagdSrfDirType Dir)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    return BzrSrfDegreeRaise(Srf, Dir);
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfDegreeRaise(Srf, Dir);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Extracts an iso curve from the surface as spcified by Dir and t.	      *
******************************************************************************/
CagdCrvStruct *CagdCrvFromSrf(CagdSrfStruct *Srf, CagdRType t,
							CagdSrfDirType Dir)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    return BzrSrfCrvFromSrf(Srf, t, Dir);
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfCrvFromSrf(Srf, t, Dir);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Extracts a curve from the surface as spcified by Dir and Index.	      *
*   The curve is constructed as a single ROW/COL of the original surface.     *
*   Note this curve may be not on the surface!				      *
******************************************************************************/
CagdCrvStruct *CagdCrvFromMesh(CagdSrfStruct *Srf, int Index,
							CagdSrfDirType Dir)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    return BzrSrfCrvFromMesh(Srf, Index, Dir);
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfCrvFromMesh(Srf, Index, Dir);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Substitue a row/col from the given curve into the surface as spcified by    *
* Dir and Index. Curve must have same PtType/Length and the surface row/col.  *
******************************************************************************/
void CagdCrvToMesh(CagdCrvStruct *Crv, int Index,
					CagdSrfDirType Dir, CagdSrfStruct *Srf)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_SRF(Srf);
    int i, j,
	Length = Crv -> Length,
	ULength = Srf -> ULength,
	VLength = Srf -> VLength,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Srf -> PType);
    CagdRType *CrvP, *SrfP;

    if (Crv -> PType != Srf -> PType ||
	Length != (Dir == CAGD_CONST_U_DIR ? VLength : ULength))
	FATAL_ERROR(CAGD_ERR_PT_OR_LEN_MISMATCH);

    switch (Dir) {
	case CAGD_CONST_U_DIR:
	    if (Index + 1 > ULength)
		FATAL_ERROR(CAGD_ERR_INDEX_NOT_IN_MESH);

	    for (i = IsNotRational; i <= MaxCoord; i++) {
		CrvP = Crv -> Points[i];
		SrfP = Srf -> Points[i] + Index * CAGD_NEXT_U(Srf);
		for (j = 0; j < Length; j++) {
		    *SrfP = *CrvP++;
		    SrfP += CAGD_NEXT_V(Srf);
		}
	    }
	    break;
	case CAGD_CONST_V_DIR:
	    if (Index + 1 > VLength)
		FATAL_ERROR(CAGD_ERR_INDEX_NOT_IN_MESH);

	    for (i = IsNotRational; i <= MaxCoord; i++) {
		CrvP = Crv -> Points[i];
		SrfP = Srf -> Points[i] + Index * CAGD_NEXT_V(Srf);;
		for (j = 0; j < Length; j++) {
		    *SrfP = *CrvP++;
		    SrfP += CAGD_NEXT_U(Srf);
		}
	    }
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV);
	    break;
    }
}

/******************************************************************************
* Given a srf - subdivide it into two at given parametric value in given dir. *
* Returns pointer to first srf in a list of two srfs (subdivided ones).       *
******************************************************************************/
CagdSrfStruct *CagdSrfSubdivAtParam(CagdSrfStruct *Srf, CagdRType t,
							    CagdSrfDirType Dir)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    return BzrSrfSubdivAtParam(Srf, t, Dir);
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfSubdivAtParam(Srf, t, Dir);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Given a surface - returns a sub region within the specified domain, dir.    *
******************************************************************************/
CagdSrfStruct *CagdSrfRegionFromSrf(CagdSrfStruct *Srf, CagdRType t1,
					      CagdRType t2, CagdSrfDirType Dir)
{
    CagdRType TMin, TMax, R1, R2;
    CagdSrfStruct *Srfs;
    CagdBType
	NewSrf = FALSE;

    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    TMin = 0.0;
	    TMax = 1.0;
	    break;
	case CAGD_SBSPLINE_TYPE:
    	    if (Dir == CAGD_CONST_U_DIR)
		BspSrfDomain(Srf, &TMin, &TMax, &R1, &R2);
	    else
		BspSrfDomain(Srf, &R1, &R2, &TMin, &TMax);
	    break;
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }

    if (t1 > t2) SWAP(CagdRType, t1, t2);

    if (!APX_EQ(t1, TMin)) {
	Srfs = CagdSrfSubdivAtParam(Srf, t1, Dir);
	Srf = Srfs -> Pnext;
	Srfs -> Pnext = NULL;
	CagdSrfFree(Srfs);			   /* Free the first region. */
	NewSrf = TRUE;
    }

    if (APX_EQ(t2, TMax))
	return NewSrf ? Srf : CagdSrfCopy(Srf);
    else {
	Srfs = CagdSrfSubdivAtParam(Srf, t2, Dir);

	if (NewSrf) CagdSrfFree(Srf);

    	CagdSrfFree(Srfs -> Pnext);		  /* Free the second region. */
    	Srfs -> Pnext = NULL;
	return Srfs;				/* Returns the first region. */
    }
}

/******************************************************************************
* Given a surface - refine it at the given n knots as defined by vector t.    *
* If Replace is TRUE, the values replaces current vector instead.	      *
* Returns pointer to refined srf (Note Bezier will be converted into spline). *
******************************************************************************/
CagdSrfStruct *CagdSrfRefineAtParams(CagdSrfStruct *Srf, CagdSrfDirType Dir,
					CagdBType Replace, CagdRType *t, int n)
{
    CagdSrfStruct *BspSrf, *TSrf;

    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
    	    BspSrf = CnvrtBezier2BsplineSrf(Srf);
	    TSrf = BspSrfKnotInsertNDiff(BspSrf, Dir, Replace, t, n);
	    CagdSrfFree(BspSrf);
	    return TSrf;
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfKnotInsertNDiff(Srf, Dir, Replace, t, n);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Given a curve and a parameter value t, returns the tangent direction at t.  *
******************************************************************************/
CagdVecStruct *CagdCrvTangent(CagdCrvStruct *Crv, CagdRType t)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    return BzrCrvTangent(Crv, t);
	case CAGD_CBSPLINE_TYPE:
	    return BspCrvTangent(Crv, t);
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }
}

/******************************************************************************
* Given a curve and a parameter value t, returns the binormal direction at t. *
******************************************************************************/
CagdVecStruct *CagdCrvBiNormal(CagdCrvStruct *Crv, CagdRType t)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    return BzrCrvBiNormal(Crv, t);
	case CAGD_CBSPLINE_TYPE:
	    return BspCrvBiNormal(Crv, t);
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }
}

/******************************************************************************
* Given a curve and a parameter value t, returns the normal direction at t.   *
******************************************************************************/
CagdVecStruct *CagdCrvNormal(CagdCrvStruct *Crv, CagdRType t)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    return BzrCrvNormal(Crv, t);
	case CAGD_CBSPLINE_TYPE:
	    return BspCrvNormal(Crv, t);
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }
}

/******************************************************************************
* Given a curve and an offset amount Offset, returns an approximation to the  *
* offset curve by offseting the control polygon in the normal direction.      *
******************************************************************************/
CagdCrvStruct *CagdCrvOffset(CagdCrvStruct *Crv, CagdRType OffsetDist)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    int i, j,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType),
	Order = Crv -> Order,
	Length = Crv -> Length;
    CagdBType
	HasNewKV = FALSE;
    CagdVecStruct *N;
    CagdCrvStruct
	*OffsetCrv = CagdCrvCopy(Crv);
    CagdRType *Nodes, *NodePtr,
	**Points = OffsetCrv -> Points,
	*KV = NULL;

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    HasNewKV = TRUE;
	    KV = BspKnotUniformOpen(Length, Order, NULL);
	    break;
	case CAGD_CBSPLINE_TYPE:
	    KV = Crv -> KnotVector;
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }

    Nodes = BspKnotNodes(KV, Length + Order, Order);
    NodePtr = Nodes;

    if (IsNotRational)
	for (j = 0; j < Length; j++) {
	    N = CagdCrvNormal(Crv, *NodePtr++);
	    for (i = 1; i <= MaxCoord; i++)
		Points[i][j] += N -> Vec[i - 1] * OffsetDist;
	}
    else
	for (j = 0; j < Length; j++) {
	    N = CagdCrvNormal(Crv, *NodePtr++);
	    for (i = 1; i <= MaxCoord; i++)
		Points[i][j] = Points[i][j] +
			       N -> Vec[i - 1] * OffsetDist * Points[W][j];
	}

    if (HasNewKV)
	CagdFree((VoidPtr) KV);
    CagdFree((VoidPtr) Nodes);

    return OffsetCrv;
}

/******************************************************************************
* Given a srf and parameter value u,v, returns the tangent direction in Dir.  *
******************************************************************************/
CagdVecStruct *CagdSrfTangent(CagdSrfStruct *Srf, CagdRType u, CagdRType v,
							    CagdSrfDirType Dir)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    return BzrSrfTangent(Srf, u, v, Dir);
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfTangent(Srf, u, v, Dir);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Given a srf and parameter values u,v, returns the surface normal at u,v.    *
******************************************************************************/
CagdVecStruct *CagdSrfNormal(CagdSrfStruct *Srf, CagdRType u, CagdRType v)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    return BzrSrfNormal(Srf, u, v);
	case CAGD_SBSPLINE_TYPE:
	    return BspSrfNormal(Srf, u, v);
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }
}

/******************************************************************************
* Given a surface and an offset amount Offset, returns an approximation to    *
* the offset surface by offseting the control mesh in the normal direction.   *
******************************************************************************/
CagdSrfStruct *CagdSrfOffset(CagdSrfStruct *Srf, CagdRType OffsetDist)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_SRF(Srf);
    int	i, Row, Col,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Srf -> PType),
	UOrder = Srf -> UOrder,
	VOrder = Srf -> VOrder,
	ULength = Srf -> ULength,
	VLength = Srf -> VLength;
    CagdBType
	HasNewKV = FALSE;
    CagdVecStruct *N;
    CagdSrfStruct
	*OffsetSrf = CagdSrfCopy(Srf);
    CagdRType *UNodes, *VNodes, *UNodePtr, *VNodePtr,
	**Points = OffsetSrf -> Points,
	*UKV = NULL,
	*VKV = NULL;

    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    HasNewKV = TRUE;
	    UKV = BspKnotUniformOpen(ULength, UOrder, NULL);
	    VKV = BspKnotUniformOpen(VLength, VOrder, NULL);
	    break;
	case CAGD_SBSPLINE_TYPE:
	    UKV = Srf -> UKnotVector;
	    VKV = Srf -> VKnotVector;
	    break;
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }

    UNodes = BspKnotNodes(UKV, ULength + UOrder, UOrder);
    VNodes = BspKnotNodes(VKV, VLength + VOrder, VOrder);

    if (IsNotRational)
	for (Row = 0, VNodePtr = VNodes; Row < VLength; Row++, VNodePtr++)
	    for (Col = 0, UNodePtr = UNodes; Col < ULength; Col++, UNodePtr++) {
	    	N = CagdSrfNormal(Srf, *UNodePtr, *VNodePtr);
	    	for (i = 1; i <= MaxCoord; i++)
		    Points[i][CAGD_MESH_UV(OffsetSrf, Col, Row)] +=
			N -> Vec[i - 1] * OffsetDist;
	    }
    else
	for (Row = 0, VNodePtr = VNodes; Row < VLength; Row++, VNodePtr++)
	    for (Col = 0, UNodePtr = UNodes; Col < ULength; Col++, UNodePtr++) {
	    	N = CagdSrfNormal(Srf, *UNodePtr, *VNodePtr);
	    	for (i = 1; i <= MaxCoord; i++)
	    	    Points[i][CAGD_MESH_UV(OffsetSrf, Col, Row)] +=
			N -> Vec[i - 1] * OffsetDist *
			    Points[W][CAGD_MESH_UV(OffsetSrf, Col, Row)];
	    }

    if (HasNewKV) {
	CagdFree((VoidPtr) UKV);
	CagdFree((VoidPtr) VKV);
    }

    CagdFree((VoidPtr) UNodes);
    CagdFree((VoidPtr) VNodes);

    return OffsetSrf;
}

/******************************************************************************
* Return a new reversed surface by reversing in U direction the control mesh. *
******************************************************************************/
CagdSrfStruct *CagdSrfReverse(CagdSrfStruct *Srf)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_SRF(Srf);
    int i, Len, Row, Col,
	ULength = Srf -> ULength,
	VLength = Srf -> VLength,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Srf -> PType);
    CagdSrfStruct
	*ReversedSrf = CagdSrfCopy(Srf);
    CagdRType *KV,
	**Points = ReversedSrf -> Points;

    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	case CAGD_SBSPLINE_TYPE:
	    break;
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }

    /* Reverse the Mesh: */
    Len = ULength / 2;
    for (Row = 0; Row < VLength; Row++)
	for (Col = 0; Col < Len; Col++)
	    for (i = IsNotRational; i <= MaxCoord; i++)
		SWAP(CagdRType,
		     Points[i][Row * ULength + Col],
		     Points[i][Row * ULength + ULength - Col - 1]);

    /* Reverse the U knot vector if it exists: */
    if (Srf -> GType == CAGD_SBSPLINE_TYPE &&
	Srf -> UKnotVector != NULL) {
	KV = BspKnotReverse(Srf -> UKnotVector, Srf -> UOrder + ULength);
	CagdFree((VoidPtr) ReversedSrf -> UKnotVector);
	ReversedSrf -> UKnotVector = KV;
    }

    return ReversedSrf;
}

/******************************************************************************
* Return a new reversed surface by flipping the U and V directions.           *
******************************************************************************/
CagdSrfStruct *CagdSrfReverse2(CagdSrfStruct *Srf)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_SRF(Srf);
    int i, Row, Col,
	ULength = Srf -> ULength,
	VLength = Srf -> VLength,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Srf -> PType);
    CagdSrfStruct
	*ReversedSrf = CagdSrfCopy(Srf);
    CagdRType
	**Points = Srf -> Points,
	**RevPoints = ReversedSrf -> Points;

    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	case CAGD_SBSPLINE_TYPE:
	    break;
	case CAGD_SPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    return NULL;
    }

    /* Reverse the Mesh: */
    for (Row = 0; Row < VLength; Row++)
	for (Col = 0; Col < ULength; Col++)
	    for (i = IsNotRational; i <= MaxCoord; i++)
		RevPoints[i][Col * VLength + Row] =
		    Points[i][Row * ULength + Col];

    /* Swap the U and the V knot vectors if the exists: */
    if (Srf -> GType == CAGD_SBSPLINE_TYPE) {
	SWAP(CagdRType *,
	     ReversedSrf -> UKnotVector, ReversedSrf -> VKnotVector);
    }

    /* And swap the orders and lengths. */
    SWAP(int, ReversedSrf -> UOrder, ReversedSrf -> VOrder);
    SWAP(int, ReversedSrf -> ULength, ReversedSrf -> VLength);

    return ReversedSrf;
}
[ RETURN TO DIRECTORY ]