Metropoli BBS
VIEWER: mshplanr.c MODE: TEXT (ASCII)
/******************************************************************************
* MshPlanr.c - Test colinearity of control meshes/polygons.		      *
*******************************************************************************
* Written by Gershon Elber, Sep. 91.					      *
******************************************************************************/

#include "cagd_loc.h"

/*****************************************************************************
* Computes a distance between two control points at given indices Index?.    *
* Only E2 or E3 point types are supported.				     *
*****************************************************************************/
CagdRType CagdDistanceTwoCtlPts(CagdRType **Points, int Index1, int Index2,
							CagdPointType PType)
{
    switch (PType) {
	case CAGD_PT_E2_TYPE:
	    return sqrt(SQR(Points[1][Index1] - Points[1][Index2]) +
			SQR(Points[2][Index1] - Points[2][Index2]));
	case CAGD_PT_E3_TYPE:
	    return sqrt(SQR(Points[1][Index1] - Points[1][Index2]) +
			SQR(Points[2][Index1] - Points[2][Index2]) +
			SQR(Points[3][Index1] - Points[3][Index2]));
	default:
	    FATAL_ERROR(CAGD_ERR_UNSUPPORT_PT);
	    return 0.0;
    }
}

/*****************************************************************************
* Fits a plane into the four points from Points indices Index?. Points may   *
* be either E2 or E3 only.						     *
*   Returns 0.0 if failed to fit a plane, otherwise a measure on the size of *
* the mesh data (distance between points) isreturned.			     *
*****************************************************************************/
CagdRType CagdFitPlaneThruCtlPts(CagdPlaneStruct *Plane, CagdPointType PType,
			         CagdRType **Points,
			         int Index1, int Index2, int Index3, int Index4)
{
    int i, j, Indices[4];
    CagdRType SizeMeasure,
	MaxDist = 0.0;
    CagdVecStruct V1, V2, V3;

    Indices[0] = Index1;
    Indices[1] = Index2;
    Indices[2] = Index3;
    Indices[3] = Index4;

    /* Find out the pair of vertices most seperated: */
    for (i = 0; i < 4; i++)
	for (j = i + 1; j < 4; j++) {
	    CagdRType
		Dist = CagdDistanceTwoCtlPts(Points, Indices[i], Indices[j],
								     PType);
	    if (Dist > MaxDist) {
		MaxDist = Dist;
		Index1 = i;
		Index2 = j;
	    }
	}

    if (MaxDist < EPSILON) return 0.0;
    SizeMeasure = MaxDist;
    MaxDist = 0.0;

    /* Find a third most seperated than the selected two. */
    for (i = 0; i < 4; i++)
	if (i != Index1 && i != Index2) {
	    CagdRType
		Dist1 = CagdDistanceTwoCtlPts(Points, Indices[Index1],
					      Indices[j], PType),
		Dist2 = CagdDistanceTwoCtlPts(Points, Indices[Index2],
					      Indices[j], PType),
		Dist = MIN(Dist1, Dist2);

	    if (Dist > MaxDist) {
		MaxDist = Dist;
		Index3 = i;
	    }
	}
    if (MaxDist < EPSILON) return 0.0;

    /* Now we have the 3 most seperated vertices to fit a plane thru. */

    switch (PType) {
	case CAGD_PT_E2_TYPE:
	    /* This is trivial since the plane must be Z = 0. */
	    Plane -> Plane[0] = 0.0;
	    Plane -> Plane[1] = 0.0;
	    Plane -> Plane[2] = 1.0;
	    Plane -> Plane[3] = 0.0;
	    break;
	case CAGD_PT_E3_TYPE:
	    /* Compute normal as a cross product of two vectors thru pts. */
	    for (i = 0; i < 3; i++) {
		j = i + 1;
		V1.Vec[i] = Points[j][Index2] - Points[j][Index1];
		V2.Vec[i] = Points[j][Index3] - Points[j][Index2];
	    }
	    CROSS_PROD(V3.Vec, V1.Vec, V2.Vec);
	    CAGD_NORMALIZE_VECTOR(V3);
	    for (i = 0; i < 3; i++)
		Plane -> Plane[i] = V3.Vec[i];

	    Plane -> Plane[3] = (-(V3.Vec[0] * Points[1][Index1] +
				   V3.Vec[1] * Points[2][Index1] +
				   V3.Vec[2] * Points[3][Index1]));
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_UNSUPPORT_PT);
	    break;
    }

    return SizeMeasure;
}

/*****************************************************************************
* Computes and returns distance between point Index and given plane which is *
* assumed to be normalized, so that the A B C D plane normal has unit len..  *
* Also assumed the Points are non rational with MaxDim dimension.	     *
*****************************************************************************/
CagdRType CagdDistPtPlane(CagdPlaneStruct *Plane, CagdRType **Points,
						      int Index, int MaxDim)
{
    int i;
    CagdRType
	R = Plane -> Plane[3];

    for (i = 0; i < MaxDim; i++)
	R += Plane -> Plane[i] * Points[i + 1][Index];

    return fabs(R);
}

/*****************************************************************************
* Computes and returns distance between point Index and the line from first  *
* point in direction LineDir (usually the line direction to last the point). *
* LineDir is assumed to be unit length normalized vector.		     *
*****************************************************************************/
static CagdRType CagdDistPtLine(CagdVecStruct *LineDir, CagdRType **Points,
						int Index, int MaxDim)
{
    int i;
    CagdRType R;
    CagdVecStruct V1, V2;

    for (i = 0; i < MaxDim; i++)
	V1.Vec[i] = Points[i+1][Index] - Points[i+1][0];
    if (MaxDim < 3)
	V1.Vec[2] = 0.0;

    /* Let V1 be the vector from point zero to point index. Then the distance */
    /* from point Index the the line is: | (LineDir . V1) LineDir - V1 |.     */
    V2 = *LineDir;
    R = DOT_PROD(V1.Vec, V2.Vec);
    CAGD_MULT_VECTOR(V2, R);
    CAGD_SUB_VECTOR(V2, V1);

    return CAGD_LEN_VECTOR(V2);
}

/*****************************************************************************
* Test polygon colinearity by testing the distance of interior control       *
* points from the line connecting the two polygon end points.		     *
*   Returns a relative ratio of deviation from line relative to its length.  *
*   Zero means all points are colinear.					     *
*   If two end points are same ( no line can be fit ) INFINITY is returned.  *
*****************************************************************************/
CagdRType CagdEstimateCrvColinearity(CagdCrvStruct *Crv)
{
    int i,
	MaxDim = 3,
	Length = Crv -> Length,
	Length1 = Length - 1;
    CagdRType LineLen,
	MaxDist = 0.0,
	**Points = Crv -> Points;
    CagdCrvStruct
	*CoercedCrv = NULL;
    CagdPointType
	PType = Crv ->PType;
    CagdVecStruct LineDir;

    switch (PType) {	      /* Convert the rational cases to non rational. */
	case CAGD_PT_P2_TYPE:
	    CoercedCrv = CagdCoerceCrvTo(Crv, CAGD_PT_E2_TYPE);
	    Points = CoercedCrv -> Points;
	    PType = CoercedCrv -> PType;
	    break;
	case CAGD_PT_P3_TYPE:
	    CoercedCrv = CagdCoerceCrvTo(Crv, CAGD_PT_E3_TYPE);
	    Points = CoercedCrv -> Points;
	    PType = CoercedCrv -> PType;
	    break;
    }

    switch (PType) {
	case CAGD_PT_E2_TYPE:
	    LineDir.Vec[0] = Points[1][Length1] - Points[1][0];
	    LineDir.Vec[1] = Points[2][Length1] - Points[2][0];
	    LineDir.Vec[2] = 0.0;
	    MaxDim = 2;
	    break;
	case CAGD_PT_E3_TYPE:
	    LineDir.Vec[0] = Points[1][Length1] - Points[1][0];
	    LineDir.Vec[1] = Points[2][Length1] - Points[2][0];
	    LineDir.Vec[2] = Points[3][Length1] - Points[3][0];
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_UNSUPPORT_PT);
	    break;
    }

    LineLen = CAGD_LEN_VECTOR(LineDir);
    if (LineLen < EPSILON) {
	if (CoercedCrv != NULL)
	    CagdCrvFree(CoercedCrv);
	return INFINITY;
    }

    CAGD_DIV_VECTOR(LineDir, LineLen);

    for (i = 1; i < Length1; i++) {
	CagdRType
	    Dist = CagdDistPtLine(&LineDir, Points, i, MaxDim);

	if (Dist > MaxDist)
	    MaxDist = Dist;
    }

    if (CoercedCrv != NULL)
	CagdCrvFree(CoercedCrv);

    return MaxDist / LineLen;
}

/*****************************************************************************
* Test mesh colinearity by testing the distance of interior points from the  *
* plane thru 3 corner points.						     *
*   Returns a relative ratio of deviation from plane relative to its size.   *
*   Zero means all points are coplanar.					     *
*   If end points are same ( no plane can be fit ) INFINITY is returned.     *
*****************************************************************************/
CagdRType CagdEstimateSrfPlanarity(CagdSrfStruct *Srf)
{
    int i,
	ULength = Srf -> ULength,
	ULength1 = ULength - 1,
	VLength = Srf -> VLength,
	VLength1 = VLength - 1;
    CagdRType
	PlaneSize = 0.0,
	MaxDist = 0.0,
	**Points = Srf -> Points;
    CagdSrfStruct
	*CoercedSrf = NULL;
    CagdPointType
	PType = Srf ->PType;
    CagdPlaneStruct Plane;

    switch (PType) {	      /* Convert the rational cases to non rational. */
	case CAGD_PT_P2_TYPE:
	case CAGD_PT_E2_TYPE:
	    /* Trivial case - it is planar surface. */
	    return 0.0;
	case CAGD_PT_P3_TYPE:
	    CoercedSrf = CagdCoerceSrfTo(Srf, CAGD_PT_E3_TYPE);
	    Points = CoercedSrf -> Points;
	    PType = CoercedSrf -> PType;
	    break;
    }

    switch (PType) {
	case CAGD_PT_E3_TYPE:
	    PlaneSize = CagdFitPlaneThruCtlPts(&Plane, PType, Points,
					CAGD_MESH_UV(Srf, 0,        0),
					CAGD_MESH_UV(Srf, 0,        VLength1),
					CAGD_MESH_UV(Srf, ULength1, 0),
					CAGD_MESH_UV(Srf, ULength1, VLength1));
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_UNSUPPORT_PT);
	    break;
    }

    if (PlaneSize < EPSILON) {
	if (CoercedSrf != NULL)
	    CagdSrfFree(CoercedSrf);
	return INFINITY;
    }

    for (i = ULength *VLength; i > 0; i--) {
	CagdRType
	    Dist = CagdDistPtPlane(&Plane, Points, i, 3);

	if (Dist > MaxDist)
	    MaxDist = Dist;
    }

    if (CoercedSrf != NULL)
	CagdSrfFree(CoercedSrf);

    return MaxDist / PlaneSize;
}
[ RETURN TO DIRECTORY ]