/****************************************************************************** * SBzr-Aux.c - Bezier surface auxilary routines. * ******************************************************************************* * Written by Gershon Elber, July. 90. * ******************************************************************************/ #ifdef __MSDOS__ #include #endif /* __MSDOS__ */ #include #include #include #include "cagd_loc.h" /* Define some marcos to make some of the routines below look better. They */ /* calculate the index of the U, V point of the control mesh in Points. */ #define DERIVED_SRF(U, V) CAGD_MESH_UV(DerivedSrf, U, V) #define RAISED_SRF(U, V) CAGD_MESH_UV(RaisedSrf, U, V) #define SRF(U, V) CAGD_MESH_UV(Srf, U, V) /****************************************************************************** * Given a bezier surface - subdivide it into two at given parametric value. * * Returns pointer to first surface in a list of two srfs (subdivided ones). * * The subdivision is exact result of subdivising the surface one row/col at a * * time, using the Bezier curve subdivision. * ******************************************************************************/ CagdSrfStruct *BzrSrfSubdivAtParam(CagdSrfStruct *Srf, CagdRType t, CagdSrfDirType Dir) { int Row, Col, ULength = Srf -> ULength, VLength = Srf -> VLength; CagdCrvStruct *Crv, *LCrv, *RCrv; CagdSrfStruct *RSrf = BzrSrfNew(ULength, VLength, Srf ->PType), *LSrf = BzrSrfNew(ULength, VLength, Srf ->PType); switch (Dir) { case CAGD_CONST_U_DIR: for (Row = 0; Row < VLength; Row++) { Crv = BzrSrfCrvFromMesh(Srf, Row, CAGD_CONST_V_DIR); LCrv = BzrCrvSubdivAtParam(Crv, t); RCrv = LCrv -> Pnext; CagdCrvToMesh(LCrv, Row, CAGD_CONST_V_DIR, LSrf); CagdCrvToMesh(RCrv, Row, CAGD_CONST_V_DIR, RSrf); CagdCrvFree(Crv); CagdCrvFree(LCrv); CagdCrvFree(RCrv); } break; case CAGD_CONST_V_DIR: for (Col = 0; Col < ULength; Col++) { Crv = BzrSrfCrvFromMesh(Srf, Col, CAGD_CONST_U_DIR); LCrv = BzrCrvSubdivAtParam(Crv, t); RCrv = LCrv -> Pnext; CagdCrvToMesh(LCrv, Col, CAGD_CONST_U_DIR, LSrf); CagdCrvToMesh(RCrv, Col, CAGD_CONST_U_DIR, RSrf); CagdCrvFree(Crv); CagdCrvFree(LCrv); CagdCrvFree(RCrv); } break; default: FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV); break; } LSrf -> Pnext = RSrf; return LSrf; } /****************************************************************************** * Return a new surface, identical to the original but with one degree higher * * in the given direction. * * Let old control polygon be P(i), i = 0 to k-1, and Q(i) be new one then: * * i k-i * * Q(0) = P(0), Q(i) = --- P(i-1) + (---) P(i), Q(k) = P(k-1). * * k k * * This is applied to all rows/cols of the surface. * ******************************************************************************/ CagdSrfStruct *BzrSrfDegreeRaise(CagdSrfStruct *Srf, CagdSrfDirType Dir) { CagdBType IsNotRational = !CAGD_IS_RATIONAL_SRF(Srf); int i, j, Row, Col, ULength = Srf -> ULength, VLength = Srf -> VLength, MaxCoord = CAGD_NUM_OF_PT_COORD(Srf -> PType); CagdSrfStruct *RaisedSrf = NULL; switch (Dir) { case CAGD_CONST_U_DIR: RaisedSrf = BzrSrfNew(ULength, VLength + 1, Srf -> PType); for (Col = 0; Col < ULength; Col++) { for (j = IsNotRational; j <= MaxCoord; j++) /* Q(0). */ RaisedSrf -> Points[j][RAISED_SRF(Col, 0)] = Srf -> Points[j][SRF(Col, 0)]; for (i = 1; i < VLength; i++) /* Q(i). */ for (j = IsNotRational; j <= MaxCoord; j++) RaisedSrf -> Points[j][RAISED_SRF(Col, i)] = Srf -> Points[j][SRF(Col, i - 1)] * (i / ((CagdRType) VLength)) + Srf -> Points[j][SRF(Col, i)] * ((VLength - i) / ((CagdRType) VLength)); for (j = IsNotRational; j <= MaxCoord; j++) /* Q(k). */ RaisedSrf -> Points[j][RAISED_SRF(Col, VLength)] = Srf -> Points[j][SRF(Col, VLength - 1)]; } break; case CAGD_CONST_V_DIR: RaisedSrf = BzrSrfNew(ULength + 1, VLength, Srf -> PType); for (Row = 0; Row < VLength; Row++) { for (j = IsNotRational; j <= MaxCoord; j++) /* Q(0). */ RaisedSrf -> Points[j][RAISED_SRF(0, Row)] = Srf -> Points[j][SRF(0, Row)]; for (i = 1; i < ULength; i++) /* Q(i). */ for (j = IsNotRational; j <= MaxCoord; j++) RaisedSrf -> Points[j][RAISED_SRF(i, Row)] = Srf -> Points[j][SRF(i - 1, Row)] * (i / ((CagdRType) ULength)) + Srf -> Points[j][SRF(i, Row)] * ((ULength - i) / ((CagdRType) ULength)); for (j = IsNotRational; j <= MaxCoord; j++) /* Q(k). */ RaisedSrf -> Points[j][RAISED_SRF(ULength, Row)] = Srf -> Points[j][SRF(ULength - 1, Row)]; } break; default: FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV); break; } return RaisedSrf; } /****************************************************************************** * Return a new surface equal to the derived surface in the direction Dir. * * A test is made to make sure the original surface is not rational. * * 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. * * This is applied to all rows/cols of the surface. * ******************************************************************************/ CagdSrfStruct *BzrSrfDerive(CagdSrfStruct *Srf, CagdSrfDirType Dir) { CagdBType IsNotRational = !CAGD_IS_RATIONAL_SRF(Srf); int i, j, Row, Col, ULength = Srf -> ULength, VLength = Srf -> VLength, MaxCoord = CAGD_NUM_OF_PT_COORD(Srf -> PType); CagdSrfStruct *DerivedSrf = NULL; switch (Dir) { case CAGD_CONST_U_DIR: if (!IsNotRational || VLength < 3) FATAL_ERROR(CAGD_ERR_RAT_LIN_NO_SUPPORT); DerivedSrf = BzrSrfNew(ULength, VLength - 1, Srf -> PType); for (Col = 0; Col < ULength; Col++) for (i = 0; i < VLength - 1; i++) for (j = IsNotRational; j <= MaxCoord; j++) DerivedSrf -> Points[j][DERIVED_SRF(Col, i)] = (VLength - 1) * (Srf -> Points[j][SRF(Col, i + 1)] - Srf -> Points[j][SRF(Col, i)]); break; case CAGD_CONST_V_DIR: if (!IsNotRational || ULength < 3) FATAL_ERROR(CAGD_ERR_RAT_LIN_NO_SUPPORT); DerivedSrf = BzrSrfNew(ULength - 1, VLength, Srf -> PType); for (Row = 0; Row < VLength; Row++) for (i = 0; i < ULength - 1; i++) for (j = IsNotRational; j <= MaxCoord; j++) DerivedSrf -> Points[j][DERIVED_SRF(i, Row)] = (ULength - 1) * (Srf -> Points[j][SRF(i + 1, Row)] - Srf -> Points[j][SRF(i, Row)]); break; default: FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV); break; } return DerivedSrf; } /****************************************************************************** * Evaluate the tangent to a surface at a given point and given direction. * ******************************************************************************/ CagdVecStruct *BzrSrfTangent(CagdSrfStruct *Srf, CagdRType u, CagdRType v, CagdSrfDirType Dir) { CagdVecStruct *Tangent = NULL; CagdCrvStruct *Crv; switch (Dir) { case CAGD_CONST_V_DIR: Crv = BzrSrfCrvFromSrf(Srf, v, Dir); Tangent = BzrCrvTangent(Crv, u); CagdCrvFree(Crv); break; case CAGD_CONST_U_DIR: Crv = BzrSrfCrvFromSrf(Srf, u, Dir); Tangent = BzrCrvTangent(Crv, v); CagdCrvFree(Crv); break; default: FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV); break; } return Tangent; } /****************************************************************************** * Evaluate the normal of a surface at a given point. * ******************************************************************************/ CagdVecStruct *BzrSrfNormal(CagdSrfStruct *Srf, CagdRType u, CagdRType v) { static CagdVecStruct Normal; CagdVecStruct *V, T1, T2; V = BzrSrfTangent(Srf, u, v, CAGD_CONST_U_DIR); CAGD_COPY_VECTOR(T1, *V); V = BzrSrfTangent(Srf, u, v, CAGD_CONST_V_DIR); CAGD_COPY_VECTOR(T2, *V); /* The normal is the cross product of T1 and T2: */ Normal.Vec[0] = T1.Vec[1] * T2.Vec[2] - T1.Vec[2] * T2.Vec[1]; Normal.Vec[1] = T1.Vec[2] * T2.Vec[0] - T1.Vec[0] * T2.Vec[2]; Normal.Vec[2] = T1.Vec[0] * T2.Vec[1] - T1.Vec[1] * T2.Vec[0]; CAGD_NORMALIZE_VECTOR(Normal); /* Normalize the vector. */ return &Normal; } /****************************************************************************** * Convert a Bezier srf into Bspline srf by adding two open knot vectors. * ******************************************************************************/ CagdSrfStruct *CnvrtBezier2BsplineSrf(CagdSrfStruct *Srf) { CagdSrfStruct *BspSrf = CagdSrfCopy(Srf); BspSrf -> UOrder = BspSrf -> ULength; BspSrf -> VOrder = BspSrf -> VLength; BspSrf -> UKnotVector = BspKnotUniformOpen(BspSrf -> ULength, BspSrf -> UOrder, NULL); BspSrf -> VKnotVector = BspKnotUniformOpen(BspSrf -> VLength, BspSrf -> VOrder, NULL); BspSrf -> GType = CAGD_SBSPLINE_TYPE; return BspSrf; }