/****************************************************************************** * 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; }