/****************************************************************************** * Mvar_aux.c - auxiliary routine to interface to multi-variate rep. * ******************************************************************************* * (C) Gershon Elber, Technion, Israel Institute of Technology * ******************************************************************************* * Written by Gershon Elber, May. 97. * ******************************************************************************/ #include "mvar_loc.h" /***************************************************************************** * DESCRIPTION: M * Given a multi-variate, returns its parametric domain. The Min/Max arrays M * are assumed to of sufficiently large enough space to hold all dimensions, M * if Axis == -1. M * * * PARAMETERS: M * MV: Multi variate function to consider. M * Min: Minimum domains of MV will be placed herein. M * Max: Maximum domains of MV will be placed herein. M * Axis: axis to extract or -1 for all axes. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * MvarMVDomain, multi-variates M *****************************************************************************/ void MvarMVDomain(MvarMVStruct *MV, CagdRType *Min, CagdRType *Max, int Axis) { int i; if (Axis >= MV -> Dim) MVAR_FATAL_ERROR(MVAR_ERR_INVALID_AXIS); switch (MV -> GType) { case MVAR_BEZIER_TYPE: case MVAR_POWER_TYPE: if (Axis == -1) { for (i = 0; i < MV -> Dim; i++) { Min[i] = 0.0; Max[i] = 1.0; } } else { *Min = 0.0; *Max = 1.0; } break; case MVAR_BSPLINE_TYPE: if (Axis == -1) { for (i = 0; i < MV -> Dim; i++) { int Order = MV -> Orders[i], Len = MVAR_MVAR_ITH_PT_LST_LEN(MV, i); CagdRType *KV = MV -> KnotVectors[i]; Min[i] = KV[Order - 1]; Max[i] = KV[Len]; } } else { int Order = MV -> Orders[Axis], Len = MVAR_MVAR_ITH_PT_LST_LEN(MV, Axis); CagdRType *KV = MV -> KnotVectors[Axis]; *Min = KV[Order - 1]; *Max = KV[Len]; } break; default: MVAR_FATAL_ERROR(MVAR_ERR_UNDEF_GEOM); break; } } /***************************************************************************** * DESCRIPTION: M * Given a multi-variate and a domain - validate it. M * * * PARAMETERS: M * MV: To make sure t is in its Dir domain. M * t: Parameter value to verify. M * Dir: Direction. Either U or V or W. M * * * RETURN VALUE: M * CagdBType: TRUE if in domain, FALSE otherwise. M * * * KEYWORDS: M * MvarParamInDomain, multi-variates M *****************************************************************************/ CagdBType MvarParamInDomain(MvarMVStruct *MV, CagdRType t, MvarMVDirType Dir) { CagdRType Min, Max; MvarMVDomain(MV, &Min, &Max, Dir); return t >= Min && t <= Max; } /***************************************************************************** * DESCRIPTION: M * Given a multi-variate and a domain - validate it. M * * * PARAMETERS: M * MV: To make sure (u, v, w) is in its domain. M * Params: Array of real valued parameters of size Dim to verify if this M * point is in MV's parametric domain. M * * * RETURN VALUE: M * CagdBType: TRUE if in domain, FALSE otherwise. M * * * KEYWORDS: M * MvarParamsInDomain, multi-variates M *****************************************************************************/ CagdBType MvarParamsInDomain(MvarMVStruct *MV, CagdRType *Params) { int i; switch (MV -> GType) { case MVAR_BEZIER_TYPE: case MVAR_POWER_TYPE: for (i = 0; i < MV -> Dim; i++) { if (Params[i] < 0.0 || Params[i] > 1.0) return FALSE; } break; case MVAR_BSPLINE_TYPE: for (i = 0; i < MV -> Dim; i++) { int Order = MV -> Orders[i], Len = MV -> Lengths[i]; CagdRType *KV = MV -> KnotVectors[i]; if (Params[i] < KV[Order - 1] || Params[i] > KV[Len]) return FALSE; } break; default: MVAR_FATAL_ERROR(MVAR_ERR_UNDEF_GEOM); break; } return TRUE; } /***************************************************************************** * DESCRIPTION: M * Given a multi-variate, returns a sub-region of it. M * * * PARAMETERS: M * MV: To extract a sub-region from. M * t1, t2: Domain to extract from MV, in parametric direction Dir. M * Dir: Direction to extract the sub-region. Either U or V or W. M * * * RETURN VALUE: M * MvarMVStruct *: A sub-region of MV from t1 to t2 in direction Dir. M * * * KEYWORDS: M * MvarMVRegionFromMV, multi-variates M *****************************************************************************/ MvarMVStruct *MvarMVRegionFromMV(MvarMVStruct *MV, CagdRType t1, CagdRType t2, MvarMVDirType Dir) { CagdBType OpenEnd = MvarBspMVIsOpenInDir(MV, Dir); CagdRType TMin, TMax; MvarMVStruct *MVs; CagdBType NewMV = FALSE, BezMV = FALSE; switch (MV -> GType) { case MVAR_BEZIER_TYPE: BezMV = TRUE; break; case MVAR_BSPLINE_TYPE: /* Might want to check for openend conditions here. */ break; default: MVAR_FATAL_ERROR(MVAR_ERR_UNDEF_MVAR); return NULL; } MvarMVDomain(MV, &TMin, &TMax, Dir); if (t1 > t2) SWAP(CagdRType, t1, t2); if (!APX_EQ(t1, TMin) || !OpenEnd) { MVs = MvarMVSubdivAtParam(MV, t1, Dir); MV = MVs -> Pnext; MVs -> Pnext = NULL; MvarMVFree(MVs); /* Free the first region. */ NewMV = TRUE; } if (APX_EQ(t2, TMax) && OpenEnd) return NewMV ? MV : MvarMVCopy(MV); else { if (BezMV) t2 = (t2 - t1) / (TMax - t1); MVs = MvarMVSubdivAtParam(MV, t2, Dir); if (NewMV) MvarMVFree(MV); MvarMVFree(MVs -> Pnext); /* Free the second region. */ MVs -> Pnext = NULL; return MVs; /* Returns the first region. */ } } /***************************************************************************** * DESCRIPTION: M * Computes a bounding box for a multi-variate freeform function. M * * * PARAMETERS: M * MV: To compute a bounding box for. M * BBox: Where bounding information is to be saved. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * MvarMVBBox, bbox, bounding box M *****************************************************************************/ void MvarMVBBox(MvarMVStruct *MV, CagdBBoxStruct *BBox) { CagdPointsBBox(MV -> Points, MVAR_CTL_MESH_LENGTH(MV), BBox); } /***************************************************************************** * DESCRIPTION: M * Computes a bounding box for a list of multi-variate freeform function. M * * * PARAMETERS: M * MVs: To compute a bounding box for. M * BBox: Where bounding information is to be saved. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * MvarMVListBBox, bbox, bounding box M *****************************************************************************/ void MvarMVListBBox(MvarMVStruct *MVs, CagdBBoxStruct *BBox) { CAGD_RESET_BBOX(BBox); for ( ; MVs != NULL; MVs = MVs -> Pnext) { CagdBBoxStruct TmpBBox; MvarMVBBox(MVs, &TmpBBox); CagdMergeBBox(BBox, &TmpBBox); } } /***************************************************************************** * DESCRIPTION: M * Increment the index of the control mesh of the multivariate function M * by one. M * * * PARAMETERS: M * MV: To increment Indices to its control mesh. M * Indices: To increment one step. M * * * RETURN VALUE: M * int: TRUE if Indices are in domain, FALSE if done. M * * * SEE ALSO: M * MvarIncrementMeshIndices2 M * * * KEYWORDS: M * MvarIncrementMeshIndices M *****************************************************************************/ int MvarIncrementMeshIndices(MvarMVStruct *MV, int *Indices) { int i; /* Unroll the for-loop below - this first case is very common. */ if (++(*Indices) < MV -> Lengths[0]) return TRUE; *Indices++ = 0; for (i = 0; ++i < MV -> Dim; ) { if (++(*Indices) < MV -> Lengths[i]) return TRUE; *Indices++ = 0; } return FALSE; } /***************************************************************************** * DESCRIPTION: M * Increment the index of the control mesh of the multivariate function M * by one. M * * * PARAMETERS: M * MV: To increment Indices to its control mesh. M * Indices: To increment one step. M * Index: The total current index to be incremented as well, or zero M * if we wrapped around all incides. M * * * RETURN VALUE: M * int: The non zero advanced index if indices are in domain, zero M * if done (out of domain). M * * * SEE ALSO: M * MvarIncrementMeshIndices M * * * KEYWORDS: M * MvarIncrementMeshIndices2 M *****************************************************************************/ int MvarIncrementMeshIndices2(MvarMVStruct *MV, int *Indices, int *Index) { int i; /* Unroll the for-loop below - this first case is very common. */ if (++(*Indices) < MV -> Lengths[0]) { return ++(*Index); } *Indices++ = 0; for (i = 0; ++i < MV -> Dim; ) { if (++(*Indices) < MV -> Lengths[i]) { return ++(*Index); } *Indices++ = 0; } return *Index = 0; } /***************************************************************************** * DESCRIPTION: M * Increment the index of the control mesh of the multivariate function M * by one, skipping axis Dir. M * * * PARAMETERS: M * MV: To increment Indices to its control mesh. M * Indices: To increment one step. M * Dir: To skip in the incrementation. M * * * RETURN VALUE: M * int: TRUE if Indices are in domain, FALSE if done. M * * * SEE ALSO: M * MvarIncSkipMeshIndices2 M * * * KEYWORDS: M * MvarIncSkipMeshIndices M *****************************************************************************/ int MvarIncSkipMeshIndices(MvarMVStruct *MV, int *Indices, int Dir) { int i; for (i = Dir == 0; i < MV -> Dim; ++i == Dir ? i++ : i) { if (++(Indices[i]) < MV -> Lengths[i]) return TRUE; Indices[i] = 0; } return FALSE; } /***************************************************************************** * DESCRIPTION: M * Increment the index of the control mesh of the multivariate function M * by one, skipping axis Dir. M * * * PARAMETERS: M * MV: To increment Indices to its control mesh. M * Indices: To increment one step. M * Dir: To skip in the incrementation. M * Index: The total current index to be incremented as well, or zero M * if we wrapped around all incides. M * * * RETURN VALUE: M * int: Current non negative Index if Indices are in domain, zero M * (FALSE) if done - out of the domain. M * * * SEE ALSO: M * MvarIncSkipMeshIndices M * * * KEYWORDS: M * MvarIncSkipMeshIndices2 M *****************************************************************************/ int MvarIncSkipMeshIndices2(MvarMVStruct *MV, int *Indices, int Dir, int *Index) { int i; for (i = Dir == 0; i < MV -> Dim; ++i == Dir ? i++ : i) { if (++(Indices[i]) < MV -> Lengths[i]) return (*Index += MVAR_NEXT_DIM(MV, i)); Indices[i] = 0; *Index -= (MV -> Lengths[i] - 1) * MVAR_NEXT_DIM(MV, i); } return *Index = 0; } /***************************************************************************** * DESCRIPTION: M * Increment the index of the control mesh of the multivariate function M * by one, with given lower and upper bounds: LowerBound <= Idx < UpperBound. M * * * PARAMETERS: M * MV: To increment Indices to its control mesh. M * Indices: To increment one step. M * LowerBound: Minimal values to assume. M * UpperBound: One above the maximal values to assume. M * * * RETURN VALUE: M * int: TRUE if Indices are in domain, FALSE if done. M * * * SEE ALSO: M * MvarIncBoundMeshIndices2 M * * * KEYWORDS: M * MvarIncBoundMeshIndices M *****************************************************************************/ int MvarIncBoundMeshIndices(MvarMVStruct *MV, int *Indices, int *LowerBound, int *UpperBound) { int i; for (i = -1; ++i < MV -> Dim; ) { if (++(*Indices) < *UpperBound++) return TRUE; *Indices++ = *LowerBound++; } return FALSE; } /***************************************************************************** * DESCRIPTION: M * Increment the index of the control mesh of the multivariate function M * by one, with given lower and upper bounds: LowerBound <= Idx < UpperBound. M * * * PARAMETERS: M * MV: To increment Indices to its control mesh. M * Indices: To increment one step. M * LowerBound: Minimal values to assume. M * UpperBound: One above the maximal values to assume. M * Index: The total current index to be incremented as well, or zero M * if we wrapped around all incides. M * * * RETURN VALUE: M * int: Current non negative Index if Indices are in domain, zero M * (FALSE) if done - out of the domain. M * * * SEE ALSO: M * MvarIncBoundMeshIndices M * * * KEYWORDS: M * MvarIncBoundMeshIndices2 M *****************************************************************************/ int MvarIncBoundMeshIndices2(MvarMVStruct *MV, int *Indices, int *LowerBound, int *UpperBound, int *Index) { int i; for (i = -1; ++i < MV -> Dim; ) { if (++(*Indices) < *UpperBound) return (*Index += MVAR_NEXT_DIM(MV, i)); *Indices++ = *LowerBound; /* Note UpperBound should be larger than LowerBound so for an empty */ /* dimension UpperBound should be 1, but just in case if it is 0... */ *Index -= (*UpperBound == 0 ? *UpperBound++ - *LowerBound++ : *UpperBound++ - *LowerBound++ - 1) * MVAR_NEXT_DIM(MV, i); } return *Index = 0; } /***************************************************************************** * DESCRIPTION: M * Given indices into the control mesh, return the index in the vector M * representation Points of that single point. M * * * PARAMETERS: M * MV: Whose indices are for. M * Indices: To compute the exact point location in MV -> Points M * * * RETURN VALUE: M * int: Index of point whose indices are Indices in MV -> Points. M * * * SEE ALSO: M * MvarMeshIndicesFromIndex M * * * KEYWORDS: M * MvarGetPointsMeshIndices M *****************************************************************************/ int MvarGetPointsMeshIndices(MvarMVStruct *MV, int *Indices) { int i, Index, *SubSpaces = MV -> SubSpaces; switch (MV -> Dim) { case 1: return *SubSpaces * *Indices; case 2: return SubSpaces[0] * Indices[0] + SubSpaces[1] * Indices[1]; case 3: return SubSpaces[0] * Indices[0] + SubSpaces[1] * Indices[1] + SubSpaces[2] * Indices[2]; case 4: return SubSpaces[0] * Indices[0] + SubSpaces[1] * Indices[1] + SubSpaces[2] * Indices[2] + SubSpaces[3] * Indices[3]; case 5: return SubSpaces[0] * Indices[0] + SubSpaces[1] * Indices[1] + SubSpaces[2] * Indices[2] + SubSpaces[3] * Indices[3] + SubSpaces[4] * Indices[4]; default: Index = 0; for (i = 0; i < MV -> Dim; i++) Index += *SubSpaces++ * *Indices++; return Index; } } /***************************************************************************** * DESCRIPTION: M * Given a linear Index into the vector of control points, compute the M * indices of the multivariates in all dimensions. M * * * PARAMETERS: M * Index: To decompose into the different axes of the multivariate. M * MV: Whose indices are for. M * Indices: To compute the exact point location in MV -> Points M * * * RETURN VALUE: M * int: TRUE if Index in range, false otherwise. M * * * SEE ALSO: M * MvarGetPointsMeshIndices M * * * KEYWORDS: M * MvarMeshIndicesFromIndex M *****************************************************************************/ int MvarMeshIndicesFromIndex(int Index, MvarMVStruct *MV, int *Indices) { int i; for (i = MV -> Dim - 1; i >= 0; i--) { Indices[i] = Index / MV -> SubSpaces[i]; Index -= Indices[i] * MV -> SubSpaces[i]; if (Index < 0 || Indices[i] >= MV -> Lengths[i]) return FALSE; } return TRUE; } /***************************************************************************** * DESCRIPTION: M * Merges two multivariates in the requested direction Dir. M * It is assumed that last edge of MV1 is identical to first edge of MV2. M * It is assumed that both MVs have open end conditions and share the same M * orders and knot sequences in all axes, but the merged axes which can have M * different knots. M * * * PARAMETERS: M * MV1: To connect to MV2's starting boundary at its end. M * MV2: To connect to MV1's end boundary at its start. M * Dir: Direction the merge should take place. M * Discont: If TRUE, assumes the merged "edge" is discontinuous. M * * * RETURN VALUE: M * MvarMVStruct *: The merged multivariate. M * * * SEE ALSO: M * CagdMergeSrfSrf M * * * KEYWORDS: M * MvarMergeMVMV, merge, multivariate M *****************************************************************************/ MvarMVStruct *MvarMergeMVMV(MvarMVStruct *MV1, MvarMVStruct *MV2, MvarMVDirType Dir, CagdBType Discont) { CagdBType IsNotRational, MergedEdgeDiscont = Discont || MV1 -> Orders[Dir] == 1 || MV2 -> Orders[Dir] == 1; int i, MaxCoord, *Lengths, *MergedIndices, Index1, Index2, MergedIndex, *LowerBound, *UpperBound, IsScalar; CagdRType **MergedPoints, **Points1, **Points2; MvarMVStruct *MergedMV; if (MV1 -> Dim != MV2 -> Dim || MV1 -> GType != MV2 -> GType || MV1 -> PType != MV2 -> PType) { MVAR_FATAL_ERROR(MVAR_ERR_FAIL_CMPT); return NULL; } /* Verify multivariate geometric types. */ switch (MV1 -> GType) { case MVAR_BEZIER_TYPE: MV1 = MvarCnvrtBezier2BsplineMV(MV1); MV2 = MvarCnvrtBezier2BsplineMV(MV2); break; case MVAR_BSPLINE_TYPE: MV1 = MvarMVCopy(MV1); MV2 = MvarMVCopy(MV2); break; default: MVAR_FATAL_ERROR(MVAR_ERR_UNDEF_GEOM); return NULL; } IsNotRational = !MVAR_IS_RATIONAL_MV(MV1); MaxCoord = CAGD_NUM_OF_PT_COORD(MV1 -> PType); IsScalar = IsNotRational && MaxCoord == 1; Lengths = (int *) IritMalloc(sizeof(int) * MV1 -> Dim); for (i = 0; i < MV1 -> Dim; i++) { if (i == Dir) Lengths[i] = MV1 -> Lengths[i] + MV2 -> Lengths[i] - 1 + MergedEdgeDiscont; else if (MV1 -> Lengths[i] == MV2 -> Lengths[i]) Lengths[i] = MV1 -> Lengths[i]; else { MvarMVFree(MV1); MvarMVFree(MV2); MVAR_FATAL_ERROR(MVAR_ERR_MVS_INCOMPATIBLE); return NULL; } } MergedMV = MvarBspMVNew(MV1 -> Dim, Lengths, MV1 -> Orders, MV1 -> PType); IritFree(Lengths); /* Update knot vectors. We assume open end condition here... */ for (i = 0; i < MV1 -> Dim; i++) { CAGD_GEN_COPY(MergedMV -> KnotVectors[i], MV1 -> KnotVectors[i], (MV1 -> Lengths[i] + MV1 -> Orders[i]) * sizeof(CagdRType)); if (i == Dir) { /* Append the second knot vector and affine transform so it */ /* directly continues the first with Degree knots at connection. */ CAGD_GEN_COPY(&MergedMV -> KnotVectors[i][MV1 -> Lengths[i] + MV1 -> Orders[i] - 1 + MergedEdgeDiscont], &MV2 -> KnotVectors[i][MV2 -> Orders[i]], MV2 -> Lengths[i] * sizeof(CagdRType)); BspKnotAffineTrans(&MergedMV -> KnotVectors[i][MV1 -> Lengths[i] + MV1 -> Orders[i] - 1], MV2 -> Lengths[i], MergedMV -> KnotVectors[i][MV1 -> Lengths[i] + MV1 -> Orders[i] - 2] - MV2 -> KnotVectors[i][0], 1.0); } } MergedPoints = MergedMV -> Points; Points1 = MV1 -> Points; Points2 = MV2 -> Points; MergedIndices = (int *) IritMalloc(sizeof(int) * MergedMV -> Dim); LowerBound = (int *) IritMalloc(sizeof(int) * MergedMV -> Dim); UpperBound = (int *) IritMalloc(sizeof(int) * MergedMV -> Dim); ZAP_MEM(LowerBound, sizeof(int) * MergedMV -> Dim); CAGD_GEN_COPY(UpperBound, MergedMV -> Lengths, MergedMV -> Dim * sizeof(int)); /* Copy the first control mesh into the merged multivariate. */ UpperBound[Dir] = MV1 -> Lengths[Dir]; ZAP_MEM(MergedIndices, sizeof(int) * MergedMV -> Dim); Index1 = MergedIndex = 0; if (IsScalar) { do { MergedPoints[1][MergedIndex] = Points1[1][Index1]; MvarIncBoundMeshIndices2(MergedMV, MergedIndices, LowerBound, UpperBound, &MergedIndex); } while (++Index1 < MVAR_CTL_MESH_LENGTH(MV1)); } else { do { for (i = IsNotRational; i <= MaxCoord; i++) MergedPoints[i][MergedIndex] = Points1[i][Index1]; MvarIncBoundMeshIndices2(MergedMV, MergedIndices, LowerBound, UpperBound, &MergedIndex); } while (++Index1 < MVAR_CTL_MESH_LENGTH(MV1)); } /* Copy the second control mesh into the merged multivariate. */ LowerBound[Dir] = MV1 -> Lengths[Dir] - 1 + MergedEdgeDiscont; UpperBound[Dir] = MergedMV -> Lengths[Dir]; Index2 = 0; CAGD_GEN_COPY(MergedIndices, LowerBound, sizeof(int) * MergedMV -> Dim); MergedIndex = MvarGetPointsMeshIndices(MergedMV, MergedIndices); if (IsScalar) { do { MergedPoints[1][MergedIndex] = Points2[1][Index2]; MvarIncBoundMeshIndices2(MergedMV, MergedIndices, LowerBound, UpperBound, &MergedIndex); } while (++Index2 < MVAR_CTL_MESH_LENGTH(MV2)); } else { do { for (i = IsNotRational; i <= MaxCoord; i++) MergedPoints[i][MergedIndex] = Points2[i][Index2]; MvarIncBoundMeshIndices2(MergedMV, MergedIndices, LowerBound, UpperBound, &MergedIndex); } while (++Index2 < MVAR_CTL_MESH_LENGTH(MV2)); } MvarMVFree(MV1); MvarMVFree(MV2); IritFree(MergedIndices); IritFree(LowerBound); IritFree(UpperBound); return MergedMV; } /***************************************************************************** * DESCRIPTION: M * Converts a Bspline multivariate into a Bspline multivariate with floating M * end conditions. M * * * PARAMETERS: M * MV: Bspline multivariate to convert to floating end conditions. M * Assume MV is either periodic or has floating end condition. M * * * RETURN VALUE: M * MvarMVStruct *: A Bspline multivariate with floating end conditions, M * representing the same geometry as MV. M * * * SEE ALSO: M * CnvrtPeriodic2FloatMV, MvarCnvrtFloat2OpenMV M * * * KEYWORDS: M * MvarCnvrtPeriodic2FloatMV, conversion M *****************************************************************************/ MvarMVStruct *MvarCnvrtPeriodic2FloatMV(MvarMVStruct *MV) { int i, NewIdx, *Lengths, *Indices, *NewIndices, Dim = MV -> Dim, MaxAxis = CAGD_NUM_OF_PT_COORD(MV -> PType); MvarMVStruct *NewMV; if (!MVAR_IS_BSPLINE_MV(MV)) { MVAR_FATAL_ERROR(MVAR_ERR_BSPLINE_EXPECTED); return NULL; } for (i = 0; i < Dim; i++) if (MVAR_IS_ITH_PERIODIC_MVAR(MV, i)) break; if (i >= MV -> Dim) return MvarMVCopy(MV); Lengths = (int *) IritMalloc(Dim * sizeof(int)); for (i = 0; i < Dim; i++) Lengths[i] = MVAR_MVAR_ITH_PT_LST_LEN(MV, i); NewMV = MvarBspMVNew(Dim, Lengths, MV -> Orders, MV -> PType); IritFree(Lengths); for (i = 0; i < Dim; i++) CAGD_GEN_COPY(NewMV -> KnotVectors[i], MV -> KnotVectors[i], sizeof(CagdRType) * (MVAR_MVAR_ITH_PT_LST_LEN(MV, i) + MV -> Orders[i])); Indices = (int *) IritMalloc(Dim * sizeof(int)); NewIndices = (int *) IritMalloc(Dim * sizeof(int)); NewIdx = 0; ZAP_MEM(NewIndices, sizeof(int) * Dim); do { int Idx; for (i = 0; i < Dim; i++) Indices[i] = NewIndices[i] % MV -> Lengths[i]; Idx = MvarGetPointsMeshIndices(MV, Indices); for (i = !CAGD_IS_RATIONAL_PT(MV -> PType); i <= MaxAxis; i++) NewMV -> Points[i][NewIdx] = MV -> Points[i][Idx]; } while (MvarIncrementMeshIndices2(NewMV, NewIndices, &NewIdx)); IritFree(NewIndices); IritFree(Indices); for (i = MaxAxis + 1; i <= CAGD_MAX_PT_COORD; i++) NewMV -> Points[i] = NULL; CAGD_PROPAGATE_ATTR(NewMV, MV); return NewMV; } /***************************************************************************** * DESCRIPTION: M * Converts a float Bspline multivariate to a Bspline multivariate with open M * end conditions. M * * * PARAMETERS: M * MV: Bspline multivariate to convert to open end conditions. M * * * RETURN VALUE: M * MvarMVStruct *: A Bspline multivariate with open end conditions, M * representing the same geometry as MV. M * * * SEE ALSO: M * MvarCnvrtPeriodic2FloatMV, CnvrtFloat2OpenMV M * * * KEYWORDS: M * MvarCnvrtFloat2OpenMV, conversion M *****************************************************************************/ MvarMVStruct *MvarCnvrtFloat2OpenMV(MvarMVStruct *MV) { int i, Dim = MV -> Dim; MvarMVStruct *NewMV = MvarMVCopy(MV); if (MvarBspMVIsOpen(NewMV)) return NewMV; if (!MVAR_IS_BSPLINE_MV(MV)) { MVAR_FATAL_ERROR(MVAR_ERR_BSPLINE_EXPECTED); return NULL; } for (i = 0; i < Dim; i++) { if (!MvarBspMVIsOpenInDir(NewMV, i)) { CagdRType Min, Max; MvarMVStruct *TmpMV; MvarMVDomain(NewMV, &Min, &Max, i); TmpMV = MvarMVRegionFromMV(NewMV, Min, Max, i); MvarMVFree(NewMV); NewMV = TmpMV; } } CAGD_PROPAGATE_ATTR(NewMV, MV); return NewMV; } /***************************************************************************** * DESCRIPTION: M * Returns TRUE iff the given Bspline multivariate has open end coditions in M * the specified direction Dir. M * * * PARAMETERS: M * MV: To check for open end conditions. M * Dir: Direction to test for open end conditions. M * * * RETURN VALUE: M * CagdBType: TRUE, if MV has open end conditions in Dir, FALSE otherwise. M * * * SEE ALSO: M * BspCrvHasOpenEC, MvarBspMVIsOpen, MvarBspMVIsPeriodic, M * MvarBspMVIsPeriodicInDir M * * * KEYWORDS: M * MvarBspMVIsOpenInDir, open end conditions M *****************************************************************************/ CagdBType MvarBspMVIsOpenInDir(MvarMVStruct *MV, MvarMVDirType Dir) { if (MVAR_IS_BEZIER_MV(MV)) return TRUE; return BspKnotHasOpenEC(MV -> KnotVectors[Dir], MV -> Lengths[Dir], MV -> Orders[Dir]); } /***************************************************************************** * DESCRIPTION: M * Returns TRUE iff the given Bspline multivariate has open end coditions in M * all direction directions. M * * * PARAMETERS: M * MV: To check for open end conditions. M * * * RETURN VALUE: M * CagdBType: TRUE, if MV has open end conditions in all directions, FALSE M * otherwise. M * * * SEE ALSO: M * BspCrvHasOpenEC, MvarBspMVIsOpenInDir, MvarBspMVIsOpenInDir M * * * KEYWORDS: M * MvarBspMVIsOpen, open end conditions M *****************************************************************************/ CagdBType MvarBspMVIsOpen(MvarMVStruct *MV) { CagdBType Open = TRUE; int i; if (MVAR_IS_BEZIER_MV(MV)) return TRUE; for (i = 0; i < MV -> Dim; i++) Open = (Open && BspKnotHasOpenEC(MV -> KnotVectors[i], MV -> Lengths[i], MV -> Orders[i])); return Open; } /***************************************************************************** * DESCRIPTION: M * Returns TRUE iff the given Bspline multivariate has periodic end coditions M * in the specified direction Dir. M * * * PARAMETERS: M * MV: To check for periodic end conditions. M * Dir: Direction to test for periodic end conditions. M * * * RETURN VALUE: M * CagdBType: TRUE, if MV has periodic end conditions in Dir, FALSE M * otherwise. M * * * SEE ALSO: M * BspCrvHasOpenEC, MvarBspMVIsOpen, MvarBspMVIsOpenInDir, M * MvarBspMVIsPeriodic M * * * KEYWORDS: M * MvarBspMVIsPeriodicInDir, periodic end conditions M *****************************************************************************/ CagdBType MvarBspMVIsPeriodicInDir(MvarMVStruct *MV, MvarMVDirType Dir) { return MV -> Periodic[Dir]; } /***************************************************************************** * DESCRIPTION: M * Returns TRUE iff the given Bspline multivariate has periodic end coditions M * in at least one direction. M * * * PARAMETERS: M * MV: To check for periodic end conditions. M * * * RETURN VALUE: M * CagdBType: TRUE, if MV has periodic end conditions in some Dir, FALSE M * otherwise. M * * * SEE ALSO: M * BspCrvHasOpenEC, MvarBspMVIsOpen, MvarBspMVIsOpenInDir, M * MvarBspMVIsPeriodicInDir M * * * KEYWORDS: M * MvarBspMVIsPeriodic, periodic end conditions M *****************************************************************************/ CagdBType MvarBspMVIsPeriodic(MvarMVStruct *MV) { CagdBType Periodic = FALSE; int i; for (i = 0; i < MV -> Dim; i++) Periodic = (Periodic || MV -> Periodic[i]); return Periodic; }