Ejemplo n.º 1
0
/*****************************************************************************
* DESCRIPTION:                                                               M
*   Apply Bezier subdivision to the given curve at parameter value t, and    M
* save the result in data LPoints/RPoints.  Note this function could also be M
* called from a B-spline curve with a Bezier knot sequence.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Points:            To subdivide at parametr value t.                     M
*   LPoints, RPoints:  Where the results are kept.			     M
*   Length:	       Of this Bezier curve.				     M
*   PType:	       Points types we have here.			     M
*   t:                 Parameter value to subdivide curve at.                M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   BzrCrvSubdivAtParam, BspCrvSubdivCtlPoly, BzrCrvSubdivCtlPolyStep        M
*                                                                            *
* KEYWORDS:                                                                  M
*   BzrCrvSubdivCtlPoly                                                      M
*****************************************************************************/
void BzrCrvSubdivCtlPoly(CagdRType * const *Points,
			 CagdRType **LPoints,
			 CagdRType **RPoints,
			 int Length,
			 CagdPointType PType,
			 CagdRType t)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_PT(PType);
    int i, j, l,
	MaxCoord = CAGD_NUM_OF_PT_COORD(PType);
    CagdRType
	t1 = 1.0 - t;

    /* Copy Points into RPoints, so we can apply the recursive algo. to it.  */
    for (j = IsNotRational; j <= MaxCoord; j++)
        IRIT_GEN_COPY(RPoints[j], Points[j], Length * sizeof(CagdRType));

    for (j = IsNotRational; j <= MaxCoord; j++)
	LPoints[j][0] = Points[j][0];

    /* Apply the recursive algorithm to RPoints, and update LPoints with the */
    /* temporary results. Note we updated the first point of LPoints above.  */
    for (i = 1; i < Length; i++) {
	for (l = 0; l < Length - i; l++)
	    for (j = IsNotRational; j <= MaxCoord; j++)
		RPoints[j][l] = RPoints[j][l] * t1 + RPoints[j][l + 1] * t;

	/* Copy temporary result to LPoints: */
	for (j = IsNotRational; j <= MaxCoord; j++)
	    LPoints[j][i] = RPoints[j][0];
    }
}
Ejemplo n.º 2
0
/*****************************************************************************
* DESCRIPTION:                                                               *
*   Finds the tangent vector to the curve at each parameter.                 *
*                                                                            *
* PARAMETERS:                                                                *
*   Crv:   The input curve.                                                  *
*   TangentsVector:   An array for the tangent at each parameter.            *
*   CrvEval:   The value of the curve at each parameter.                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   CagdBType:   TRUE for Sucssess.                                          *
*****************************************************************************/
static CagdBType FindTangentsVec(
			      const CagdCrvStruct *Crv,
			      CagdVType TangentsVector[CAGD_CM_MAX_SAMPLE_NUM],
			      CagdVType CrvEval[CAGD_CM_MAX_SAMPLE_NUM])

{
    int i;
    CagdRType StartCrvPar, EndCrvPar, Par, *Pt, DPt[CAGD_MAX_PT_SIZE], DPar;
    CagdCrvStruct
	*TanCrv = CagdCrvDeriveScalar(Crv);
    CagdPointType
	PType = TanCrv -> PType;

    CagdCrvDomain(Crv, &StartCrvPar, &EndCrvPar);

    DPar = (EndCrvPar -  StartCrvPar) / (GlblNumberOfSamples - 1);
    for (i = 0, Par = StartCrvPar;
	 i < GlblNumberOfSamples;
	 i++, Par += DPar) { 
	if (Par > EndCrvPar)      /* Due to floating point roundoff errors. */
	    Par = EndCrvPar;

	Pt = CagdCrvEval(TanCrv, Par);
	IRIT_GEN_COPY(DPt, Pt, sizeof(CagdRType) * CAGD_MAX_PT_SIZE);

	Pt = CagdCrvEval(Crv , Par);
	CagdCoerceToE3(CrvEval[i], &Pt, -1, TanCrv -> PType);

	if (CAGD_IS_RATIONAL_CRV(TanCrv)) {
	    int j;

	    for (j = 1; j <= IRIT_MIN(CAGD_NUM_OF_PT_COORD(PType), 3); j++) {
		if (Pt[0] == 0)
		    TangentsVector[i][j - 1] = 0.0;
		else
		    TangentsVector[i][j - 1] =
		        (DPt[j] * Pt[0] - Pt[j] * DPt[0]) / IRIT_SQR(Pt[0]);
	    }
	}
	else {
	    Pt = DPt;
	    CagdCoerceToE3(TangentsVector[i], &Pt, -1, PType);
	}

	IRIT_PT_NORMALIZE(TangentsVector[i]);
    }

    CagdCrvFree(TanCrv);

    return TRUE;
}
Ejemplo n.º 3
0
/*****************************************************************************
* DESCRIPTION:                                                               *
* Main module of skeleton - Read command line and do what is needed...	     *
*                                                                            *
* PARAMETERS:                                                                *
*   FileNames:  Files to open and read, as a vector of strings.              *
*   NumFiles:   Length of the FileNames vector.								 *
*                                                                            *
* RETURN VALUE:                                                              *
*   bool:		false - fail, true - success.                                *
*****************************************************************************/
bool CGSkelProcessIritDataFiles(CString &FileNames, int NumFiles, std::vector<PolygonalObject>& outObjects, int polygonFineness)
{
	IPObjectStruct *PObjects;
	IrtHmgnMatType CrntViewMat;

	/* Get the data files: */
	IPSetFlattenObjects(FALSE);
	// Boris' patch: convert FileNames to an array of size 1
	// then convert it from wide char to char
	LPCTSTR* tmp1 = (LPCTSTR*)&FileNames;
	char tmp2[201];
	char* tmp3[1] = { tmp2 };
	wcstombs(tmp2, *tmp1, 200);
	if ((PObjects = IPGetDataFiles(tmp3, 1/*NumFiles*/, TRUE, FALSE)) == NULL)
		return false;
	// End of patch
	PObjects = IPResolveInstances(PObjects);

	if (IPWasPrspMat)
		MatMultTwo4by4(CrntViewMat, IPViewMat, IPPrspMat);
	else
		IRIT_GEN_COPY(CrntViewMat, IPViewMat, sizeof(IrtHmgnMatType));

	/* Here some useful parameters to play with in tesselating freeforms: */
	CGSkelFFCState.FineNess = polygonFineness;   /* Res. of tesselation, larger is finer. */
	CGSkelFFCState.ComputeUV = TRUE;   /* Wants UV coordinates for textures. */
	CGSkelFFCState.FourPerFlat = TRUE;/* 4 poly per ~flat patch, 2 otherwise.*/
	CGSkelFFCState.LinearOnePolyFlag = TRUE;    /* Linear srf gen. one poly. */

	/* Traverse ALL the parsed data, recursively. */
	IPTraverseObjListHierarchy(PObjects, CrntViewMat, 
		CGSkelDumpOneTraversedObject);

	// Convert to our data structure:
	outObjects = IritAdapter::Convert(PObjects);
	// Finished converting

	return true;
}
Ejemplo n.º 4
0
/*****************************************************************************
* DESCRIPTION:                                                               M
* Main module of irit2xfg - Read command line and do what is needed...	     M
*                                                                            *
* PARAMETERS:                                                                M
*   argc, argv:  Command line.                                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:    Return code.                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   main                                                                     M
*****************************************************************************/
int main(int argc, char **argv)
{
    int Error,
	HasTime = FALSE,
	PrintSizeFlag = FALSE,
	NumOfIsolinesFlag = FALSE,
	CrvOptimalPolyFlag = FALSE,
	SrfOptimalPolyFlag = FALSE,
	VerFlag = FALSE,
	OutFileFlag = FALSE,
	TranslateFlag = FALSE,
	NumFiles = 0;
    char
        *StrNumOfIsolines = NULL,
	**FileNames = NULL;
    IrtRType CurrentTime;
    IPObjectStruct *PObjects;
    IrtHmgnMatType CrntViewMat;

#ifdef DEBUG_IRIT_MALLOC
    IritInitTestDynMemory();
#endif /* DEBUG_IRIT_MALLOC */

    if ((Error = GAGetArgs (argc, argv, CtrlStr,
			    &PrintSizeFlag, &GlblPrintSize,
			    &TranslateFlag, &GlblXTranslate, &GlblYTranslate,
			    &NumOfIsolinesFlag, &StrNumOfIsolines,
			    &CrvOptimalPolyFlag, &IPFFCState.CrvApproxMethod,
			    &IPFFCState.CrvApproxTolSamples,
			    &SrfOptimalPolyFlag, &IPFFCState.OptimalPolygons,
			    &IPFFCState.FineNess,
			    &IPFFCState.DrawFFMesh, &IPFFCState.DrawFFGeom,
			    &IPFFCState.Talkative, &HasTime, &CurrentTime,
			    &IPFFCState.ShowInternal, &OutFileFlag, &OutFileName,
			    &VerFlag, &NumFiles, &FileNames)) != 0) {
	GAPrintErrMsg(Error);
	GAPrintHowTo(CtrlStr);
	Irit2XfgExit(1);
    }

    if (VerFlag) {
	IRIT_INFO_MSG_PRINTF("\n%s\n\n", VersionStr);
	GAPrintHowTo(CtrlStr);
	Irit2XfgExit(0);
    }

    if (!NumFiles) {
	IRIT_WARNING_MSG("No data file names were given, exit.\n");
	GAPrintHowTo(CtrlStr);
	Irit2XfgExit(1);
    }

    IPFFCState.DumpObjsAsPolylines = !SrfOptimalPolyFlag;
    IPFFCState.ComputeNrml = FALSE;        /* No need for normals of vertices. */

    if (NumOfIsolinesFlag && StrNumOfIsolines != NULL) {
	if (sscanf(StrNumOfIsolines, "%d:%d:%d",
		   &IPFFCState.NumOfIsolines[0],
		   &IPFFCState.NumOfIsolines[1],
		   &IPFFCState.NumOfIsolines[2]) != 3) {
	    if (sscanf(StrNumOfIsolines, "%d:%d",
		       &IPFFCState.NumOfIsolines[0],
		       &IPFFCState.NumOfIsolines[1]) != 2) {
		if (sscanf(StrNumOfIsolines, "%d",
			   &IPFFCState.NumOfIsolines[1]) != 1) {
		    IRIT_WARNING_MSG(
			    "Number(s) of isolines (-I) cannot be parsed.\n");
		    GAPrintHowTo(CtrlStr);
		    Irit2XfgExit(1);
		}
		else {
		    IPFFCState.NumOfIsolines[2] =
			IPFFCState.NumOfIsolines[1] =
			    IPFFCState.NumOfIsolines[0];
		}
	    }
	    else {
		IPFFCState.NumOfIsolines[2] = IPFFCState.NumOfIsolines[0];
	    }

	}
    }

    /* Get the data files: */
    IPSetFlattenObjects(FALSE);
    if ((PObjects = IPGetDataFiles((const char **) FileNames,
				   NumFiles, TRUE, FALSE)) == NULL)
	Irit2XfgExit(1);
    PObjects = IPResolveInstances(PObjects);
    if (HasTime)
	GMAnimEvalAnimationList(CurrentTime, PObjects);
    else
        GMAnimEvalAnimationList(GM_ANIM_NO_DEFAULT_TIME, PObjects);

    if (IPWasPrspMat)
	MatMultTwo4by4(CrntViewMat, IPViewMat, IPPrspMat);
    else
	IRIT_GEN_COPY(CrntViewMat, IPViewMat, sizeof(IrtHmgnMatType));

    IPTraverseObjListHierarchy(PObjects, CrntViewMat, IPMapObjectInPlace);

    DumpDataForFIG(OutFileFlag ? OutFileName : NULL, PObjects);

    Irit2XfgExit(0);

    return 0;
}
Ejemplo n.º 5
0
/*****************************************************************************
* DESCRIPTION:                                                               M
*   This function is a variation BspSrfInterpScatPts function that is less   M
* accurate/stable but is faster.					     M
*   The difference is that we solve a LSQ problem as A'*A*Vertices=A'*points M
* where A' is the transpose matrix of A.                                     M
*   This method is also refered to as pseudo inverse.                        M
*   The SVD decomposition is still used to calculate the above equation set. M
*   Given a set of scattered points, PtList, the function computes a Bspline M
* surface of order UOrder by VOrder that interpolates or least square        M
* approximates the M given set of scattered points.                          M
*   PtList is a NULL terminated lists of CagdPtStruct structs, with each     M
* point holding (u, v, x [, y[, z]]).  That is, E3 points create an E1       M
* scalar surface and E5 points create an E3 surface,           	             M
*                                                                            *
* PARAMETERS:                                                                M
*   PtList:      A NULL terminating array of linked list of points.          M
*   UOrder:      Of the to be created surface.                               M
*   VOrder:      Of the to be created surface.                               M
*   USize:       U size of the to be created surface.                        M
*   VSize:       V size of the to be created surface.                        M
*   UKV:	 Expected knot vector in U direction, NULL for uniform open. M
*   VKV:	 Expected knot vector in V direction, NULL for uniform open. M
*   MatrixCondition: address of a IrtRType to return SVD matrix              M
*                    condition number to. if NULL, this option is ignored    M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdSrfStruct *:   Constructed interpolating/approximating surface.      M
*                                                                            *
* KEYWORDS:                                                                  M
*   BspSrfInterpScatPts2, interpolation, least square approximation          M
*****************************************************************************/
CagdSrfStruct *BspSrfInterpScatPts2(const CagdCtlPtStruct *PtList,
				    int UOrder,
				    int VOrder,
				    int USize,
				    int VSize,
				    CagdRType *UKV,
				    CagdRType *VKV,
				    CagdRType *MatrixCondition)
{
    int Row, i, j,
	NumCoords = CAGD_NUM_OF_PT_COORD(PtList -> PtType),
	PtListLen = CagdListLength(PtList),
	Size = USize * VSize;
    CagdBType
	NewUKV = FALSE,
	NewVKV = FALSE;
    CagdRType *MultMat, TempMatConditionNumber, *R, *P, *InterpPts, *RightSide,
	*ULine = (CagdRType *) IritMalloc(sizeof(CagdRType) * UOrder);
    CagdSparseMatStruct *Mat, *MatTranspose;
    CagdSparseCellStruct *SparseCell;
    const CagdCtlPtStruct *Pt;
    CagdSrfStruct *Srf;

    Mat = CagdSparseMatNew(IRIT_MAX(Size, PtListLen),Size,TRUE);	

    if (NumCoords < 3) {
	CAGD_FATAL_ERROR(CAGD_ERR_PT_OR_LEN_MISMATCH);
	return NULL;
    }

    if (UKV == NULL) {
	UKV = BspKnotUniformOpen(USize, UOrder, NULL);
	BspKnotAffineTrans2(UKV, USize + UOrder, 0.0, 1.0);
	NewUKV = TRUE;
    }
    if (VKV == NULL) {
	VKV = BspKnotUniformOpen(VSize, VOrder, NULL);
	BspKnotAffineTrans2(VKV, VSize + VOrder, 0.0, 1.0);
	NewVKV = TRUE;
    }

    for (Pt = PtList, Row = 0; Pt != NULL; Pt = Pt -> Pnext, Row++) {
        int UIndex, VIndex;
        CagdRType *VLine;

        if (NumCoords != CAGD_NUM_OF_PT_COORD(Pt -> PtType)) {
            CAGD_FATAL_ERROR(CAGD_ERR_PT_OR_LEN_MISMATCH);
            IritFree(ULine);
            IritFree(Mat);
            return NULL;
        }

        VLine = BspCrvCoxDeBoorBasis(UKV, UOrder, USize, FALSE,
            Pt -> Coords[1], &UIndex);
        IRIT_GEN_COPY(ULine, VLine, sizeof(CagdRType) * UOrder);
        VLine = BspCrvCoxDeBoorBasis(VKV, VOrder, VSize, FALSE,
            Pt -> Coords[2], &VIndex);

        for (j = VIndex; j < VIndex + VOrder; j++)
            for (i = UIndex; i < UIndex + UOrder; i++)
		CagdSparseMatNewCell(Mat, Row, (j * USize + i), 
				     ULine[i - UIndex] *
				         VLine[j - VIndex]);
    }
    IritFree(ULine);


    /* The LSQ problem may be solved using the following equation:           */
    /* A' * A * V = A' * P,  where,					     */
    /* A  - the matrix previously calculated				     */
    /* A' - is the tranpost of A					     */
    /* V - vertices							     */
    /* P - points to approximate					     */

    /* Calculate the tranpose matrix. */
    MatTranspose=CagdSparseMatTranspose(Mat, FALSE);

    /* Solve for the coefficients of all the coordinates of the curve. */
    InterpPts = (CagdRType *) IritMalloc(sizeof(CagdRType) * PtListLen);

    /* Calculate the right side of the equation. */
	
    /* Allocate Size * 3 (for easch component x, y, x). */
    RightSide = (CagdRType *) IritMalloc(sizeof(CagdRType) * Size * 3); 

    P = RightSide;

    /* Multiply A' * points and save result in vector for a later use. */
    for (i = 3; i <= NumCoords; i++) {
        for (Pt = PtList, R = InterpPts; Pt != NULL; Pt = Pt -> Pnext)
            *R++ = Pt -> Coords[i];

        for (j = 0; j < Size; j++, P++){
	    SparseCell = MatTranspose->RowStart[j];			
			
            *P = 0.0;
            while (SparseCell != NULL) {
                *P += SparseCell -> CellValue * InterpPts[SparseCell->CellCol];
                SparseCell = SparseCell -> NextCol;
            }
        }
    }

    IritFree(InterpPts);

    /* Calculate A' * A. */
    MultMat = CagdSparseMatMultNonSparseResult(MatTranspose,Mat);

    /* We don't need them anymore. */
    CagdSparseMatFree(Mat); 
    CagdSparseMatFree(MatTranspose);

    /* Compute SVD decomposition for Mat. */
    TempMatConditionNumber = IRIT_FABS(SvdLeastSqr(MultMat, NULL, NULL,
					      Size, Size));

    /* Return the matrix condition number. */
    if (MatrixCondition != NULL)
	*MatrixCondition = TempMatConditionNumber;

    if (TempMatConditionNumber < IRIT_UEPS && Size <= PtListLen) {
	CAGD_FATAL_ERROR(CAGD_ERR_NO_SOLUTION);

	IritFree(MultMat);
	return NULL;
    }

    IritFree(MultMat);

    /* Construct the Bspline surface and copy its knot vectors. */
    Srf = BspSrfNew(USize, VSize, UOrder, VOrder,
		    CAGD_MAKE_PT_TYPE(FALSE, NumCoords - 2));
    CAGD_GEN_COPY(Srf -> UKnotVector, UKV,
		  (CAGD_SRF_UPT_LST_LEN(Srf) + UOrder) * sizeof(CagdRType));
    CAGD_GEN_COPY(Srf -> VKnotVector, VKV,
		  (CAGD_SRF_VPT_LST_LEN(Srf) + VOrder) * sizeof(CagdRType));
    
    for ( i = 0; i < NumCoords-2; i++){
        SvdLeastSqr(NULL, Srf -> Points[i+1], RightSide+(i*Size), Size, Size);
    }

    IritFree(RightSide);

    if (NewUKV)
	IritFree(UKV);
    if (NewVKV)
	IritFree(VKV);

    return Srf;
}
Ejemplo n.º 6
0
/*****************************************************************************
* DESCRIPTION:                                                               M
* Given a set of scattered points, PtList, computes a Bspline surface of     M
* order UOrder by VOrder that interpolates or least square approximates the  M
* given set of scattered points.                                             M
*   PtList is a NULL terminated lists of CagdPtStruct structs, with each     M
* point holding (u, v, x [, y[, z]]).  That is, E3 points create an E1       M
* scalar surface and E5 points create an E3 surface,           	             M
*                                                                            *
* PARAMETERS:                                                                M
*   PtList:      A NULL terminating array of linked list of points.          M
*   UOrder:      Of the to be created surface.                               M
*   VOrder:      Of the to be created surface.                               M
*   USize:       U size of the to be created surface.                        M
*   VSize:       V size of the to be created surface.                        M
*   UKV:	 Expected knot vector in U direction, NULL for uniform open. M
*   VKV:	 Expected knot vector in V direction, NULL for uniform open. M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdSrfStruct *:   Constructed interpolating/approximating surface.      M
*                                                                            *
* KEYWORDS:                                                                  M
*   BspSrfInterpScatPts, interpolation, least square approximation           M
*****************************************************************************/
CagdSrfStruct *BspSrfInterpScatPts(const CagdCtlPtStruct *PtList,
				   int UOrder,
				   int VOrder,
				   int USize,
				   int VSize,
				   CagdRType *UKV,
				   CagdRType *VKV)
{
    int i, j,
	NumCoords = CAGD_NUM_OF_PT_COORD(PtList -> PtType),
	PtListLen = CagdListLength(PtList),
	Size = USize * VSize;
    CagdBType
	NewUKV = FALSE,
	NewVKV = FALSE;
    CagdRType *M, *R, *InterpPts,
	*ULine = (CagdRType *) IritMalloc(sizeof(CagdRType) * UOrder),
	*Mat = (CagdRType *) IritMalloc(sizeof(CagdRType) * Size *
					IRIT_MAX(Size, PtListLen));
    const CagdCtlPtStruct *Pt;
    CagdSrfStruct *Srf;

    if (NumCoords < 3) {
	CAGD_FATAL_ERROR(CAGD_ERR_PT_OR_LEN_MISMATCH);
	return NULL;
    }

    IRIT_ZAP_MEM(Mat, sizeof(CagdRType) * Size * IRIT_MAX(Size, PtListLen));

    if (UKV == NULL) {
	UKV = BspKnotUniformOpen(USize, UOrder, NULL);
	BspKnotAffineTrans2(UKV, USize + UOrder, 0.0, 1.0);
	NewUKV = TRUE;
    }
    if (VKV == NULL) {
	VKV = BspKnotUniformOpen(VSize, VOrder, NULL);
	BspKnotAffineTrans2(VKV, VSize + VOrder, 0.0, 1.0);
	NewVKV = TRUE;
    }

    for (Pt = PtList, M = Mat; Pt != NULL; Pt = Pt -> Pnext, M += Size) {
	int UIndex, VIndex;
	CagdRType *VLine;

	if (NumCoords != CAGD_NUM_OF_PT_COORD(Pt -> PtType)) {
	    CAGD_FATAL_ERROR(CAGD_ERR_PT_OR_LEN_MISMATCH);
	    IritFree(ULine);
	    IritFree(Mat);
	    return NULL;
	}

	VLine = BspCrvCoxDeBoorBasis(UKV, UOrder, USize, FALSE,
				     Pt -> Coords[1], &UIndex);
	IRIT_GEN_COPY(ULine, VLine, sizeof(CagdRType) * UOrder);
	VLine = BspCrvCoxDeBoorBasis(VKV, VOrder, VSize, FALSE,
				     Pt -> Coords[2], &VIndex);

	for (j = VIndex; j < VIndex + VOrder; j++)
	    for (i = UIndex; i < UIndex + UOrder; i++)
		M[j * USize + i] = ULine[i - UIndex] * VLine[j - VIndex];
    }
    IritFree(ULine);

#   ifdef DEBUG
    {
        IRIT_SET_IF_DEBUG_ON_PARAMETER(_DebugPrintInputSvd, FALSE) {
	    for (i = 0; i < PtListLen; i++) {
	        IRIT_INFO_MSG("[");
		for (j = 0; j < Size; j++) {
		    IRIT_INFO_MSG_PRINTF("%7.4f ", Mat[i * Size + j]);
		}
		IRIT_INFO_MSG("]\n");
	    }
	}
    }
#   endif /* DEBUG */

    /* Compute SVD decomposition for Mat. */
    if (IRIT_FABS(SvdLeastSqr(Mat, NULL, NULL,
			 IRIT_MAX(Size, PtListLen), Size)) < IRIT_UEPS &&
	Size <= PtListLen) {
	CAGD_FATAL_ERROR(CAGD_ERR_NO_SOLUTION);

	IritFree(Mat);
	return NULL;
    }
    IritFree(Mat);

    /* Construct the Bspline surface and copy its knot vectors. */
    Srf = BspSrfNew(USize, VSize, UOrder, VOrder,
		    CAGD_MAKE_PT_TYPE(FALSE, NumCoords - 2));
    CAGD_GEN_COPY(Srf -> UKnotVector, UKV,
		  (CAGD_SRF_UPT_LST_LEN(Srf) + UOrder) * sizeof(CagdRType));
    CAGD_GEN_COPY(Srf -> VKnotVector, VKV,
		  (CAGD_SRF_VPT_LST_LEN(Srf) + VOrder) * sizeof(CagdRType));

    /* Solve for the coefficients of all the coordinates of the curve. */
    InterpPts = (CagdRType *) IritMalloc(sizeof(CagdRType) *
					 IRIT_MAX(Size, PtListLen));
    for (i = 3; i <= NumCoords; i++) {
	for (Pt = PtList, R = InterpPts; Pt != NULL; Pt = Pt -> Pnext)
	    *R++ = Pt -> Coords[i];

	SvdLeastSqr(NULL, Srf -> Points[i - 2], InterpPts, PtListLen, Size);
    }
    SvdLeastSqr(NULL, NULL, NULL, 0, 0);			/* Clean up. */
    IritFree(InterpPts);

    if (NewUKV)
	IritFree(UKV);
    if (NewVKV)
	IritFree(VKV);

    return Srf;
}