/****************************************************************************** * BspBoehm.c - Implements Boehm single knot insertion routine. * * Based on: * * "Recursive proof of Boehm's knot insertion technique", by Phillip J Barry * * Ronald N Goldman, CAD, Volume 20 number 4 1988, pp 181-182. * * The original paper by Boehm W. is also sighted there. * ******************************************************************************* * Written by Gershon Elber, Aug. 90. * ******************************************************************************/ #ifdef __MSDOS__ #include #endif /* __MSDOS__ */ #include #include #include #include "cagd_loc.h" /****************************************************************************** * Returns a new curve refined at t (t is inserted as a new knot in Crv). * * If however the multiplicity of t in the current knot vector is equal * * (or greater!?) to the degree or t is not in the curve parametric domain, no * * new knot is insert and NULL is returned instead. * * Control mesh is updated as follows (P is old ctl polygon, Q is new): * * Let Index be the last knot in old knot vector less than t and * * let j be j = Index - order + 1. Also let k be the curve order. * * * * Case 1: Q(i) = P(i), i <= j * * * * t - t(i) t(i+k-1) - t * * case 2: Q(i) = --------------- P(i) + --------------- P(i-1), j KnotVector; int i, j, k = Crv -> Order, Len = Crv -> Length, KVLen = k + Len, Index = BspKnotLastIndexL(KnotVector, KVLen, t), MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType); CagdCrvStruct *RefinedCrv = CagdCrvNew(Crv -> GType, Crv -> PType, Len + 1); CagdRType **Points = Crv -> Points, **NewPoints = RefinedCrv -> Points; if (!BspKnotParamInDomain(KnotVector, Len, k, t)) FATAL_ERROR(CAGD_ERR_T_NOT_IN_CRV); /* Update the rest of the RefinedCrv data structure (easy part). */ RefinedCrv -> Order = k; RefinedCrv -> KnotVector = BspKnotInsertOne(Crv -> KnotVector, k, Len, t); /* Case 1: Copy all points upto (Index - Order + 1) as is. */ for (i = IsNotRational; i <= MaxCoord; i++) GEN_COPY(NewPoints[i], Points[i], sizeof(CagdRType) * (Index - k + 2)); /* Case 2: Convex blend of exactly 2 points. */ for (j = Index - k + 2; j <= Index; j++) for (i = IsNotRational; i <= MaxCoord; i++) NewPoints[i][j] = ((t - KnotVector[j]) * Points[i][j] + (KnotVector[j + k - 1] - t) * Points[i][j - 1]) / (KnotVector[j + k - 1] - KnotVector[j]); /* Case 3: Copy all points upto the end. */ for (i = IsNotRational; i <= MaxCoord; i++) GEN_COPY(&NewPoints[i][Index + 1], &Points[i][Index], sizeof(CagdRType) * (Len - Index)); return RefinedCrv; } /****************************************************************************** * Insert n knot all with the value t. In no case will the multiplicity of * * knot be greater or equal to the curve order. * * Note: Altough works, this is not the optimal way to insert many knot! * ******************************************************************************/ CagdCrvStruct *BspCrvKnotInsertNSame(CagdCrvStruct *Crv, CagdRType t, int n) { int Mult = BspKnotFindMult(Crv -> KnotVector, Crv -> Order, Crv -> Length, t); CagdCrvStruct *RefinedCrv, *TempCrv = Crv; n = MIN(n, Crv -> Order - Mult - 1); if (n > 0) while (n--) { RefinedCrv = BspCrvKnotInsert(TempCrv, t); if (TempCrv != Crv) CagdCrvFree(TempCrv); TempCrv = RefinedCrv; } else RefinedCrv = CagdCrvCopy(Crv); return RefinedCrv; } /****************************************************************************** * Insert n knot with different values as defined by t. If however Replace is * * TRUE, the knot are simply replacing the current ones. * ******************************************************************************/ CagdCrvStruct *BspCrvKnotInsertNDiff(CagdCrvStruct *Crv, CagdBType Replace, CagdRType *t, int n) { int i; CagdCrvStruct *RefinedCrv, *TempCrv = Crv; if (Replace) { if (Crv -> Order + Crv -> Length != n) FATAL_ERROR(CAGD_ERR_NUM_KNOT_MISMATCH); for (i = 1; i < n; i++) if (t[i] < t[i - 1]) FATAL_ERROR(CAGD_ERR_KNOT_NOT_ORDERED); RefinedCrv = CagdCrvCopy(Crv); for (i = 0; i < n; i++) RefinedCrv -> KnotVector[i] = *t++; } else { for (i = 0; i < n; i++) { RefinedCrv = BspCrvKnotInsert(TempCrv, t[i]); if (TempCrv != Crv) CagdCrvFree(TempCrv); TempCrv = RefinedCrv; } } return RefinedCrv; } /****************************************************************************** * Returns a new srf refined at t (t is inserted as a new knot in Crv) in Dir. * ******************************************************************************/ CagdSrfStruct *BspSrfKnotInsert(CagdSrfStruct *BspSrf, CagdSrfDirType Dir, CagdRType t) { int Row, Col, ULength = BspSrf -> ULength, VLength = BspSrf -> VLength, UOrder = BspSrf -> UOrder, VOrder = BspSrf -> VOrder; CagdCrvStruct *Crv, *RefCrv; CagdSrfStruct *RefSrf = NULL; switch (Dir) { case CAGD_CONST_U_DIR: RefSrf = BspSrfNew(ULength + 1, VLength, UOrder, VOrder, BspSrf -> PType); CagdFree((VoidPtr) RefSrf -> UKnotVector); CagdFree((VoidPtr) RefSrf -> VKnotVector); RefSrf -> VKnotVector = BspKnotCopy(BspSrf -> VKnotVector, BspSrf -> VLength + BspSrf -> VOrder); for (Row = 0; Row < VLength; Row++) { Crv = BspSrfCrvFromMesh(BspSrf, Row, CAGD_CONST_V_DIR); RefCrv = BspCrvKnotInsert(Crv, t); if (Row == 0) { /* Figure out refined knot vector. */ RefSrf -> UKnotVector = BspKnotCopy(RefCrv -> KnotVector, RefCrv -> Length + RefCrv -> Order); } CagdCrvToMesh(RefCrv, Row, CAGD_CONST_V_DIR, RefSrf); CagdCrvFree(Crv); CagdCrvFree(RefCrv); } break; case CAGD_CONST_V_DIR: RefSrf = BspSrfNew(ULength, VLength + 1, UOrder, VOrder, BspSrf -> PType); CagdFree((VoidPtr) RefSrf -> UKnotVector); CagdFree((VoidPtr) RefSrf -> VKnotVector); RefSrf -> UKnotVector = BspKnotCopy(BspSrf -> UKnotVector, BspSrf -> ULength + BspSrf -> UOrder); for (Col = 0; Col < ULength; Col++) { Crv = BspSrfCrvFromMesh(BspSrf, Col, CAGD_CONST_U_DIR); RefCrv = BspCrvKnotInsert(Crv, t); if (Col == 0) { /* Figure out refined knot vector. */ RefSrf -> VKnotVector = BspKnotCopy(RefCrv -> KnotVector, RefCrv -> Length + RefCrv -> Order); } CagdCrvToMesh(RefCrv, Col, CAGD_CONST_U_DIR, RefSrf); CagdCrvFree(Crv); CagdCrvFree(RefCrv); } break; default: FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV); break; } return RefSrf; } /****************************************************************************** * Insert n knot all with the value t in direction Dir. In no case will the * * multiplicity of knot be greater or equal to the curve order. * * Note: Altough works, this is not the optimal way to insert many knot! * ******************************************************************************/ CagdSrfStruct *BspSrfKnotInsertNSame(CagdSrfStruct *BspSrf, CagdSrfDirType Dir, CagdRType t, int n) { int Row, Col, ULength = BspSrf -> ULength, VLength = BspSrf -> VLength, UOrder = BspSrf -> UOrder, VOrder = BspSrf -> VOrder; CagdCrvStruct *Crv, *RefCrv; CagdSrfStruct *RefSrf = NULL; switch (Dir) { case CAGD_CONST_U_DIR: RefSrf = BspSrfNew(ULength + n, VLength, UOrder, VOrder, BspSrf -> PType); CagdFree((VoidPtr) RefSrf -> UKnotVector); CagdFree((VoidPtr) RefSrf -> VKnotVector); RefSrf -> VKnotVector = BspKnotCopy(BspSrf -> VKnotVector, BspSrf -> VLength + BspSrf -> VOrder); for (Row = 0; Row < VLength; Row++) { Crv = BspSrfCrvFromMesh(BspSrf, Row, CAGD_CONST_V_DIR); RefCrv = BspCrvKnotInsertNSame(Crv, t, n); if (Row == 0) { /* Figure out refined knot vector. */ RefSrf -> UKnotVector = BspKnotCopy(RefCrv -> KnotVector, RefCrv -> Length + RefCrv -> Order); } CagdCrvToMesh(RefCrv, Row, CAGD_CONST_V_DIR, RefSrf); CagdCrvFree(Crv); CagdCrvFree(RefCrv); } break; case CAGD_CONST_V_DIR: RefSrf = BspSrfNew(ULength, VLength + n, UOrder, VOrder, BspSrf -> PType); CagdFree((VoidPtr) RefSrf -> UKnotVector); CagdFree((VoidPtr) RefSrf -> VKnotVector); RefSrf -> UKnotVector = BspKnotCopy(BspSrf -> UKnotVector, BspSrf -> ULength + BspSrf -> UOrder); for (Col = 0; Col < ULength; Col++) { Crv = BspSrfCrvFromMesh(BspSrf, Col, CAGD_CONST_U_DIR); RefCrv = BspCrvKnotInsertNSame(Crv, t, n); if (Col == 0) { /* Figure out refined knot vector. */ RefSrf -> VKnotVector = BspKnotCopy(RefCrv -> KnotVector, RefCrv -> Length + RefCrv -> Order); } CagdCrvToMesh(RefCrv, Col, CAGD_CONST_U_DIR, RefSrf); CagdCrvFree(Crv); CagdCrvFree(RefCrv); } break; default: FATAL_ERROR(CAGD_ERR_UNDEF_SRF); break; } return RefSrf; } /****************************************************************************** * Insert n knot with different values as defined by t. If however Replace is * * TRUE, the knot are simply replacing the current ones. * ******************************************************************************/ CagdSrfStruct *BspSrfKnotInsertNDiff(CagdSrfStruct *BspSrf, CagdSrfDirType Dir, int Replace, CagdRType *t, int n) { int i, Row, Col, ULength = BspSrf -> ULength, VLength = BspSrf -> VLength, UOrder = BspSrf -> UOrder, VOrder = BspSrf -> VOrder; CagdCrvStruct *Crv, *RefCrv; CagdSrfStruct *RefSrf = NULL; if (Replace) { for (i = 1; i < n; i++) if (t[i] < t[i - 1]) FATAL_ERROR(CAGD_ERR_KNOT_NOT_ORDERED); switch (Dir) { case CAGD_CONST_U_DIR: if (BspSrf -> UOrder + BspSrf -> ULength != n) FATAL_ERROR(CAGD_ERR_NUM_KNOT_MISMATCH); RefSrf = CagdSrfCopy(BspSrf); for (i = 0; i < n; i++) RefSrf -> UKnotVector[i] = *t++; break; case CAGD_CONST_V_DIR: if (BspSrf -> VOrder + BspSrf -> VLength != n) FATAL_ERROR(CAGD_ERR_NUM_KNOT_MISMATCH); RefSrf = CagdSrfCopy(BspSrf); for (i = 0; i < n; i++) RefSrf -> VKnotVector[i] = *t++; break; default: FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV); break; } return RefSrf; } switch (Dir) { case CAGD_CONST_U_DIR: RefSrf = BspSrfNew(ULength + n, VLength, UOrder, VOrder, BspSrf -> PType); CagdFree((VoidPtr) RefSrf -> UKnotVector); CagdFree((VoidPtr) RefSrf -> VKnotVector); RefSrf -> VKnotVector = BspKnotCopy(BspSrf -> VKnotVector, BspSrf -> VLength + BspSrf -> VOrder); for (Row = 0; Row < VLength; Row++) { Crv = BspSrfCrvFromMesh(BspSrf, Row, CAGD_CONST_V_DIR); RefCrv = BspCrvKnotInsertNDiff(Crv, FALSE, t, n); if (Row == 0) { /* Figure out refined knot vector. */ RefSrf -> UKnotVector = BspKnotCopy(RefCrv -> KnotVector, RefCrv -> Length + RefCrv -> Order); } CagdCrvToMesh(RefCrv, Row, CAGD_CONST_V_DIR, RefSrf); CagdCrvFree(Crv); CagdCrvFree(RefCrv); } break; case CAGD_CONST_V_DIR: RefSrf = BspSrfNew(ULength, VLength + n, UOrder, VOrder, BspSrf -> PType); CagdFree((VoidPtr) RefSrf -> UKnotVector); CagdFree((VoidPtr) RefSrf -> VKnotVector); RefSrf -> UKnotVector = BspKnotCopy(BspSrf -> UKnotVector, BspSrf -> ULength + BspSrf -> UOrder); for (Col = 0; Col < ULength; Col++) { Crv = BspSrfCrvFromMesh(BspSrf, Col, CAGD_CONST_U_DIR); RefCrv = BspCrvKnotInsertNDiff(Crv, FALSE, t, n); if (Col == 0) { /* Figure out refined knot vector. */ RefSrf -> VKnotVector = BspKnotCopy(RefCrv -> KnotVector, RefCrv -> Length + RefCrv -> Order); } CagdCrvToMesh(RefCrv, Col, CAGD_CONST_U_DIR, RefSrf); CagdCrvFree(Crv); CagdCrvFree(RefCrv); } break; default: FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV); break; } return RefSrf; }