/****************************************************************************** * CBzr-Aux.c - Bezier curve auxilary routines. * ******************************************************************************* * Written by Gershon Elber, Mar. 90. * ******************************************************************************/ #ifdef __MSDOS__ #include #endif /* __MSDOS__ */ #include #include #include #include "cagd_loc.h" /****************************************************************************** * Given a bezier 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 exact result of evaluating the curve at t using the * * recursive algorithm - the left resulting points are the left curve, and the * * right resulting points are the right curve (left is below t). * ******************************************************************************/ CagdCrvStruct *BzrCrvSubdivAtParam(CagdCrvStruct *Crv, CagdRType t) { CagdBType IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv); int i, j, l, k = Crv -> Length, MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType); CagdRType t1 = 1.0 - t; CagdCrvStruct *RCrv = BzrCrvNew(k, Crv -> PType), *LCrv = BzrCrvNew(k, Crv -> PType); /* Copy Curve into RCrv, so we can apply the recursive algo. to it. */ for (i = 0; i < k; i++) for (j = IsNotRational; j <= MaxCoord; j++) RCrv -> Points[j][i] = Crv -> Points[j][i]; for (j = IsNotRational; j <= MaxCoord; j++) LCrv -> Points[j][0] = Crv -> Points[j][0]; /* Apply the recursive algorithm to RCrv, and update LCrv with the */ /* temporary results. Note we updated the first point of LCrv above. */ for (i = 1; i < k; i++) { for (l = 0; l < k - i; l++) for (j = IsNotRational; j <= MaxCoord; j++) RCrv -> Points[j][l] = RCrv -> Points[j][l] * t1 + RCrv -> Points[j][l+1] * t; /* Copy temporary result to LCrv: */ for (j = IsNotRational; j <= MaxCoord; j++) LCrv -> Points[j][i] = RCrv -> Points[j][0]; } LCrv -> Pnext = RCrv; return LCrv; } /****************************************************************************** * Return a new curve, identical to the original but with one degree higher * * 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 * ******************************************************************************/ CagdCrvStruct *BzrCrvDegreeRaise(CagdCrvStruct *Crv) { CagdBType IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv); int i, j, k = Crv -> Length, MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType); CagdCrvStruct *RaisedCrv = BzrCrvNew(k + 1, Crv -> PType); for (j = IsNotRational; j <= MaxCoord; j++) /* Q(0). */ RaisedCrv -> Points[j][0] = Crv -> Points[j][0]; for (i = 1; i < k; i++) /* Q(i). */ for (j = IsNotRational; j <= MaxCoord; j++) RaisedCrv -> Points[j][i] = Crv -> Points[j][i-1] * (i / ((CagdRType) k)) + Crv -> Points[j][i] * ((k - i) / ((CagdRType) k)); for (j = IsNotRational; j <= MaxCoord; j++) /* Q(k). */ RaisedCrv -> Points[j][k] = Crv -> Points[j][k-1]; return RaisedCrv; } /****************************************************************************** * Return a normalized vector, equal to the tangent to Crv at parameter t. * * Algorithm: pseudo subdivide Crv at t and using control point of subdivided * * curve find the tangent as the difference of the 2 end points. * ******************************************************************************/ CagdVecStruct *BzrCrvTangent(CagdCrvStruct *Crv, CagdRType t) { static CagdVecStruct P2; CagdVecStruct P1; CagdBType IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv); int i, j, l, k = Crv -> Length, MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType); CagdRType t1 = 1.0 - t; CagdCrvStruct *RCrv; if (APX_EQ(t, 0.0)) { /* Use Crv starting tangent direction. */ CagdCoerceToE3(P1.Vec, Crv -> Points, 0, Crv -> PType); CagdCoerceToE3(P2.Vec, Crv -> Points, 1, Crv -> PType); } else if (APX_EQ(t, 1.0)) { /* Use Crv ending tangent direction. */ CagdCoerceToE3(P1.Vec, Crv -> Points, k - 2, Crv -> PType); CagdCoerceToE3(P2.Vec, Crv -> Points, k - 1, Crv -> PType); } else { RCrv = BzrCrvNew(k, Crv -> PType); /* Copy Crv into RCrv, so we can apply the recursive algo. to it. */ for (i = 0; i < k; i++) for (j = IsNotRational; j <= MaxCoord; j++) RCrv -> Points[j][i] = Crv -> Points[j][i]; /* Apply the recursive algorithm to RCrv. */ for (i = 1; i < k; i++) for (l = 0; l < k - i; l++) for (j = IsNotRational; j <= MaxCoord; j++) RCrv -> Points[j][l] = RCrv -> Points[j][l] * t1 + RCrv -> Points[j][l+1] * t; CagdCoerceToE3(P1.Vec, RCrv -> Points, 0, RCrv -> PType); CagdCoerceToE3(P2.Vec, RCrv -> Points, 1, RCrv -> PType); CagdCrvFree(RCrv); } 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: pseudo subdivide Crv at t and using 3 consecutive control point * * (p1, p2, p3) of subdivided curve find the bi-normal as the cross product of * * the difference (p1 - p2) and (p2 - p3). * * Since a curve may have not BiNormal at inflection points or if the 3 * * points are colinear, NULL will be returned at such cases. * ******************************************************************************/ CagdVecStruct *BzrCrvBiNormal(CagdCrvStruct *Crv, CagdRType t) { static CagdVecStruct P3; CagdVecStruct P1, P2; CagdBType IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv); int i, j, l, k = Crv -> Length, MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType); CagdRType t1 = 1.0 - t; CagdCrvStruct *RCrv; /* Can not compute for linear curves. */ if (k <= 2) return NULL; if (APX_EQ(t, 0.0)) { /* Use Crv starting tangent direction. */ CagdCoerceToE3(P1.Vec, Crv -> Points, 0, Crv -> PType); CagdCoerceToE3(P2.Vec, Crv -> Points, 1, Crv -> PType); CagdCoerceToE3(P3.Vec, Crv -> Points, 2, Crv -> PType); } else if (APX_EQ(t, 1.0)) { /* Use Crv ending tangent direction. */ CagdCoerceToE3(P1.Vec, Crv -> Points, k - 3, Crv -> PType); CagdCoerceToE3(P2.Vec, Crv -> Points, k - 2, Crv -> PType); CagdCoerceToE3(P3.Vec, Crv -> Points, k - 1, Crv -> PType); } else { RCrv = BzrCrvNew(k, Crv -> PType); /* Copy Crv into RCrv, so we can apply the recursive algo. to it. */ for (i = 0; i < k; i++) for (j = IsNotRational; j <= MaxCoord; j++) RCrv -> Points[j][i] = Crv -> Points[j][i]; /* Apply the recursive algorithm to RCrv. */ for (i = 1; i < k; i++) for (l = 0; l < k - i; l++) for (j = IsNotRational; j <= MaxCoord; j++) RCrv -> Points[j][l] = RCrv -> Points[j][l] * t1 + RCrv -> Points[j][l+1] * t; CagdCoerceToE3(P1.Vec, RCrv -> Points, 0, RCrv -> PType); CagdCoerceToE3(P2.Vec, RCrv -> Points, 1, RCrv -> PType); CagdCoerceToE3(P3.Vec, RCrv -> Points, 2, RCrv -> PType); CagdCrvFree(RCrv); } 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 *BzrCrvNormal(CagdCrvStruct *Crv, CagdRType t) { static CagdVecStruct N, *T, *B; T = BzrCrvTangent(Crv, t); B = BzrCrvBiNormal(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 *BzrCrvDerive(CagdCrvStruct *Crv) { CagdBType IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv); int i, j, k = 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 = BzrCrvNew(k - 1, Crv -> PType); for (i = 0; i < k - 1; i++) for (j = IsNotRational; j <= MaxCoord; j++) DerivedCrv -> Points[j][i] = (k - 1) * (Crv -> Points[j][i+1] - Crv -> Points[j][i]); return DerivedCrv; } /****************************************************************************** * Convert a Bezier curve into Bspline curve by adding an open knot vector. * ******************************************************************************/ CagdCrvStruct *CnvrtBezier2BsplineCrv(CagdCrvStruct *Crv) { CagdCrvStruct *BspCrv = CagdCrvCopy(Crv); BspCrv -> Order = BspCrv -> Length; BspCrv -> KnotVector = BspKnotUniformOpen(BspCrv -> Length, BspCrv -> Order, NULL); BspCrv -> GType = CAGD_CBSPLINE_TYPE; return BspCrv; }