/****************************************************************************** * CBsp-Aux.c - Bspline curve auxilary routines. * ******************************************************************************* * Written by Gershon Elber, Aug. 90. * ******************************************************************************/ #ifdef __MSDOS__ #include #endif /* __MSDOS__ */ #include #include #include #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; }