Metropoli BBS
VIEWER: cagdcmrg.c MODE: TEXT (ASCII)
/******************************************************************************
* CagdCMrg.c - Curve/Point merging routines.				      *
*******************************************************************************
* Written by Gershon Elber, May 91.					      *
******************************************************************************/

#include "string.h"
#include "cagd_loc.h"

static void CopyCrvOnCrv(CagdCrvStruct *DestCrv, int Index,
			 CagdCrvStruct *SrcCrv);
static void InterpolateLinearSeg(CagdCrvStruct *Crv, int Index1, int Index2);

/******************************************************************************
* Merge two curves.							      *
******************************************************************************/
CagdCrvStruct *CagdMergeCrvCrv(CagdCrvStruct *Crv1, CagdCrvStruct *Crv2)
{
    CagdBType CrvsSharePt,
	Crv1New = FALSE,
	Crv2New = FALSE,
	IsRational1 = CAGD_IS_RATIONAL_CRV(Crv1),
	IsRational2 = CAGD_IS_RATIONAL_CRV(Crv2);
    int Length, Order,
	Order1 = Crv1 -> Order,
	Order2 = Crv2 -> Order,
	Len1 = Crv1 -> Length,
	Len2 = Crv2 -> Length,
	MaxCoord1 = CAGD_NUM_OF_PT_COORD(Crv1 -> PType),
	MaxCoord2 = CAGD_NUM_OF_PT_COORD(Crv2 -> PType);
    CagdRType E3Pt1[3], E3Pt2[3];
    CagdPointType CrvPType = CAGD_PT_E2_TYPE;
    CagdCrvStruct *Crv;

    /* Make orders compatible: */
    if (Order1 < Order2) {
	for (; Order1 < Order2; Order1++) {
	    Crv = CagdCrvDegreeRaise(Crv1);
	    if (Crv1New)
		CagdCrvFree(Crv1);
	    Crv1 = Crv;
	    Len1 = Crv1 -> Length;
	    Crv1New = TRUE;
	}
    }
    else if (Order2 < Order1) {
	for (; Order2 < Order1; Order2++) {
	    Crv = CagdCrvDegreeRaise(Crv2);
	    if (Crv2New)
		CagdCrvFree(Crv2);
	    Crv2 = Crv;
	    Len2 = Crv2 -> Length;
	    Crv2New = TRUE;
	}
    }
    Order = Order1;

    /* Verify curve geometric types. */
    switch (Crv1 -> GType) {
	case CAGD_CBEZIER_TYPE:
	    Crv = CnvrtBezier2BsplineCrv(Crv1);
	    if (Crv1New)
		CagdCrvFree(Crv1);
	    Crv1 = Crv;
	    Crv1New = TRUE;
	    break;
	case CAGD_CBSPLINE_TYPE:
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    break;
    }

    switch (Crv2 -> GType) {
	case CAGD_CBEZIER_TYPE:
	    Crv = CnvrtBezier2BsplineCrv(Crv2);
	    if (Crv2New)
		CagdCrvFree(Crv2);
	    Crv2 = Crv;
	    Crv2New = TRUE;
	    break;
	case CAGD_CBSPLINE_TYPE:
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    break;
    }

    /* Compute curve point types. */
    CrvPType = CAGD_MAKE_PT_TYPE(IsRational1 || IsRational2,
				 MAX(MaxCoord1, MaxCoord2));


    /* Figure out if end point of Crv1 is equal to start point of Crv2 and   */
    /* Compute the length of the resulting curve accordingly.		     */
    /* If the same point, then the result can omit one copy and therefore    */
    /* has Len1 + Len2 - 1 Ctl points. If however a linear segment should be */
    /* introduced between the two curves, it should hold Order colinear pts  */
    /* including 2 end points shared with curves or Order - 2 new pts.       */
    CagdCoerceToE3(E3Pt1, Crv1 -> Points, Len1 - 1, Crv1 -> PType);
    CagdCoerceToE3(E3Pt2, Crv2 -> Points, 0, Crv2 -> PType);
    CrvsSharePt = APX_EQ(E3Pt1[0], E3Pt2[0]) &&
		  APX_EQ(E3Pt1[1], E3Pt2[1]) &&
		  APX_EQ(E3Pt1[2], E3Pt2[2]);
    Length = CrvsSharePt ? Len1 + Len2 - 1 : Len1 + Len2 + Order - 2;

    Crv = BspCrvNew(Length, Order, CrvPType);
    CopyCrvOnCrv(Crv, 0, Crv1);
    CopyCrvOnCrv(Crv, Length - Len2, Crv2);
    InterpolateLinearSeg(Crv, Len1 - 1, Length - Len2);

    /* Update the knot vector. We assume open end condition here... */
    GEN_COPY(Crv -> KnotVector, Crv1 -> KnotVector,
	     (Len1 + Order1 - 1) * sizeof(CagdRType));
    if (CrvsSharePt) {
	GEN_COPY(&Crv -> KnotVector[Len1 + Order1 - 1],
		 &Crv2 -> KnotVector[Order2], Len2 * sizeof(CagdRType));
	BspKnotAffineTrans(&Crv -> KnotVector[Len1 + Order1 - 1],
			   Len2,
			   Crv -> KnotVector[Len1 + Order1 - 2] -
			   Crv2 -> KnotVector[0],
			   1.0);
    }
    else {
	GEN_COPY(&Crv -> KnotVector[Len1 + Order1 - 1],
		 &Crv2 -> KnotVector[1],
		 (Len2 + Order2 - 1) * sizeof(CagdRType));
	BspKnotAffineTrans(&Crv -> KnotVector[Len1 + Order1 - 1],
			   Len2 + Order2 - 1,
			   Crv -> KnotVector[Len1 + Order1 - 2] -
			   Crv -> KnotVector[Len1 + Order1 - 1] + 1.0,
			   1.0);
    }

    if (Crv1New)
	CagdCrvFree(Crv1);
    if (Crv2New)
	CagdCrvFree(Crv2);

    return Crv;
}

/******************************************************************************
* Merge a curve and a point.						      *
******************************************************************************/
CagdCrvStruct *CagdMergeCrvPt(CagdCrvStruct *Crv, CagdPtStruct *Pt)
{
    CagdBType
	CrvNew = FALSE,
	IsRational = CAGD_IS_RATIONAL_CRV(Crv);
    int i, NewLen, NewMaxCoord,
	Order = Crv -> Order,
	Len = Crv -> Length,
	PtMaxCoord = APX_EQ(Pt -> Pt[2], 0.0) ? 2 : 3,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdPointType
	CrvPType = CAGD_PT_E2_TYPE;
    CagdRType t, **Points;
    CagdCrvStruct *NewCrv;

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    Crv = CnvrtBezier2BsplineCrv(Crv);
	    CrvNew = TRUE;
	case CAGD_CBSPLINE_TYPE:
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    break;
    }

    /* Compute curve point types. */
    NewMaxCoord = MAX(PtMaxCoord, MaxCoord);
    CrvPType = CAGD_MAKE_PT_TYPE(IsRational, NewMaxCoord);

    /* A linear segment is added at the end with Order colinear pts.        */
    /* However since first point is curve last point, only Order - 1 new.   */
    NewLen = Len + Order - 1;

    NewCrv = BspCrvNew(NewLen, Order, CrvPType);
    Points = NewCrv -> Points;

    CopyCrvOnCrv(NewCrv, 0, Crv);
    for (i = 1; i <= NewMaxCoord; i++) Points[i][NewLen - 1] = Pt -> Pt[i - 1];
    if (IsRational) Points[W][NewLen - 1] = 1.0;
    InterpolateLinearSeg(NewCrv, Len - 1, NewLen - 1);

    /* Update the knot vector. We assume open end condition here... */
    GEN_COPY(NewCrv -> KnotVector, Crv -> KnotVector,
	     (Len + Order - 1) * sizeof(CagdRType));
    t = Crv -> KnotVector[Len + Order - 1] + 1.0;
    for (i = Len + Order - 1; i < NewLen + Order; i++)
	NewCrv -> KnotVector[i] = t;

    if (CrvNew)
	CagdCrvFree(Crv);

    return NewCrv;
}

/******************************************************************************
* Merge a point and a curve.						      *
******************************************************************************/
CagdCrvStruct *CagdMergePtCrv(CagdPtStruct *Pt, CagdCrvStruct *Crv)
{
    CagdBType
	CrvNew = FALSE,
	IsRational = CAGD_IS_RATIONAL_CRV(Crv);
    int i, NewLen, NewMaxCoord,
	Order = Crv -> Order,
	Len = Crv -> Length,
	PtMaxCoord = APX_EQ(Pt -> Pt[2], 0.0) ? 2 : 3,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdPointType
	CrvPType = CAGD_PT_E2_TYPE;
    CagdRType t, **Points;
    CagdCrvStruct *NewCrv;

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    Crv = CnvrtBezier2BsplineCrv(Crv);
	    CrvNew = TRUE;
	    break;
	case CAGD_CBSPLINE_TYPE:
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    break;
    }

    /* Compute curve point types. */
    NewMaxCoord = MAX(PtMaxCoord, MaxCoord);
    CrvPType = CAGD_MAKE_PT_TYPE(IsRational, NewMaxCoord);

    /* A linear segment is added at the end with Order colinear pts.        */
    /* However since first point is curve last point, only Order - 1 new.   */
    NewLen = Len + Order - 1;

    NewCrv = BspCrvNew(NewLen, Order, CrvPType);
    Points = NewCrv -> Points;

    CopyCrvOnCrv(NewCrv, Order - 1, Crv);
    for (i = 1; i <= NewMaxCoord; i++) Points[i][0] = Pt -> Pt[i - 1];
    if (IsRational) Points[W][0] = 1.0;
    InterpolateLinearSeg(NewCrv, 0, Order - 1);

    /* Update the knot vector. We assume open end condition here... */
    GEN_COPY(&NewCrv -> KnotVector[Order], &Crv -> KnotVector[1],
	     (Len + Order - 1) * sizeof(CagdRType));
    t = Crv -> KnotVector[0] - 1.0;
    for (i = 0; i < Order; i++)
	NewCrv -> KnotVector[i] = t;

    if (CrvNew)
	CagdCrvFree(Crv);

    return NewCrv;
}

/******************************************************************************
* Merge two points into a linear Bezier curve.				      *
******************************************************************************/
CagdCrvStruct *CagdMergePtPt(CagdPtStruct *Pt1, CagdPtStruct *Pt2)
{
    CagdPointType
	CrvPType = APX_EQ(Pt1 -> Pt[2], 0.0) && APX_EQ(Pt2 -> Pt[2], 0.0) ?
					CAGD_PT_E2_TYPE : CAGD_PT_E3_TYPE;
    CagdCrvStruct
	*Crv = BzrCrvNew(2, CrvPType);
    CagdRType
	**Points = Crv -> Points;

    Points[X][0] = Pt1 -> Pt[0];
    Points[X][1] = Pt2 -> Pt[0];
    Points[Y][0] = Pt1 -> Pt[1];
    Points[Y][1] = Pt2 -> Pt[1];
    if (CrvPType == CAGD_PT_E3_TYPE) {
    	Points[Z][0] = Pt1 -> Pt[2];
    	Points[Z][1] = Pt2 -> Pt[2];
    }

    return Crv;
}

/******************************************************************************
* Copy SrcCrv into DestCrv at point index Index.			      *
* DestCrv PType is assumed to hold Src PType.				      *
******************************************************************************/
static void CopyCrvOnCrv(CagdCrvStruct *DestCrv, int Index,
			 CagdCrvStruct *SrcCrv)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(SrcCrv);
    int i, j,
	Len = SrcCrv -> Length,
	MaxCoord = CAGD_NUM_OF_PT_COORD(SrcCrv -> PType);
    CagdRType
	**SrcPoints = SrcCrv -> Points,
	**DestPoints = DestCrv -> Points;

    for (i = IsNotRational; i <= MaxCoord; i++)
	GEN_COPY(&DestPoints[i][Index], SrcPoints[i],
		 Len * sizeof(CagdRType));

    /* Fix the weights if source did not have them. */
    if (IsNotRational && CAGD_IS_RATIONAL_CRV(DestCrv))
	for (i = Index; i < Index + Len; i++)
	    DestPoints[W][i] = 1.0;

    /* Fix the higher coordinates (by coercing them to zero. */
    for (i = MaxCoord + 1; i < CAGD_NUM_OF_PT_COORD(DestCrv -> PType); i++)
	for (j = Index; j < Index + Len; j++)
	    DestPoints[i][j] = 0.0;

}

/******************************************************************************
* Linearly interpolate between the Crv points indices Index1 and Index2       *
******************************************************************************/
static void InterpolateLinearSeg(CagdCrvStruct *Crv, int Index1, int Index2)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    int i, j,
	DIndex = Index2 - Index1,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdRType
	**Points = Crv -> Points;

    if (DIndex < 2) return;		     /* No middle points to interp. */

    for (i = Index1 + 1; i < Index2; i++) {
	CagdRType
	    t1 = ((CagdRType) (i - Index1)) / DIndex,
	    t2 = 1.0 - t1;

	for (j = IsNotRational; j <= MaxCoord; j++)
	    Points[j][i] = t2 * Points[j][Index1] + t1 * Points[j][Index2];
    }
}
[ RETURN TO DIRECTORY ]