/*****************************************************************************
*   "Irit" - the 3d (not only polygonal) solid modeller.		     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
*   Module to provide the required interfact for the cagd library for the    *
* free form surfaces and curves.					     *
*****************************************************************************/

#include <stdio.h>
#include <math.h>
#include "program.h"
#include "user_lib.h"
#include "geomat3d.h"
#include "mrchcube.h"
#include "freeform.h"

static IPObjectStruct *GetControlTriSrfMesh(IPObjectStruct *PtObjList,
					    int Length,
					    int Order,
					    TrngGeomType GType,
					    char **ErrStr);

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Decomposes a freeform surface into regions, represented as trimmed       M
* surfaces.  Each region has normals that deviate up to a certain amount     M
* from a prescribed viewing direction.                                       M
*                                                                            *
* PARAMETERS:                                                                M
*   SrfObj:        To decompose                                              M
*   Resolution:    Of polygon approximation of SrfObj.                       M
*   ConeSize:      tangent of the angular opening of the cone of normals.    M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  List of trimmed surfaces, each representing a         M
*		       Region that has set of normals inside the same cone.  M
*                                                                            *
* KEYWORDS:                                                                  M
*   VisibConeDecomposition                                                   M
*****************************************************************************/
IPObjectStruct *VisibConeDecomposition(IPObjectStruct *SrfObj,
				       RealType *Resolution,
				       RealType *ConeSize)
{
    int Count = 0;
    IPObjectStruct
	*TrimmedSrfObjs = UserSrfVisibConeDecomp(SrfObj -> U.Srfs,
						 *Resolution,
						 *ConeSize),
	*ListObj = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

    while (TrimmedSrfObjs) {
	IPObjectStruct
	    *TrimmedSrfObj = TrimmedSrfObjs;

	TrimmedSrfObjs = TrimmedSrfObjs -> Pnext;
	TrimmedSrfObj -> Pnext = NULL;
	ListObjectInsert(ListObj, Count++, TrimmedSrfObj);
    }

    ListObjectInsert(ListObj, Count, NULL);
    return ListObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes points that covers the (hemi) sphere as a honeycomb.            M
*                                                                            *
* PARAMETERS:                                                                M
*   Size:    of honeycomb mesh - distance between adjacent points.           M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   The list of points on the hemisphere.                M
*                                                                            *
* KEYWORDS:                                                                  M
*   PointCoverOfSphere                                                       M
*****************************************************************************/
IPObjectStruct *PointCoverOfHemiSphere(RealType *Size)
{
    int Count = 0;
    IPObjectStruct
	*PObj = CGPointCoverOfUnitHemiSphere(*Size),
	*PObjList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);
    IPVertexStruct
	*V = PObj -> U.Pl -> PVertex;

    for ( ; V != NULL; V = V -> Pnext) {
	ListObjectInsert(PObjList, Count++,
			 GenPTObject(&V -> Coord[0],
				     &V -> Coord[1],
				     &V -> Coord[2]));
    }

    IPFreeObject(PObj);

    ListObjectInsert(PObjList, Count, NULL);

    return PObjList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes a distribution of points in the parametric space of the free    M
* form that is statistically uniform.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   FreeFormObj:    To compute the distribution for.                         M
*   RParamUniform:  If TRUE, produces a distribution uniform in parametric   M
*		    space. If FALSE, uniform in Euclidean space.	     M
*   RNumOfPts:      Number of points to place along the freeform object.     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A list of points, each represented as the parameter  M
*		value in the freeform object.				     M
*                                                                            *
* KEYWORDS:                                                                  M
*   FreeformPointDistrib, uniform distribution                               M
*****************************************************************************/
IPObjectStruct *FreeformPointDistrib(IPObjectStruct *FreeFormObj,
				     RealType *RParamUniform,
				     RealType *RNumOfPts)
{
    int i,
	ParamUniform = REAL_PTR_TO_INT(RParamUniform),
	NumOfPts = REAL_PTR_TO_INT(RNumOfPts);
    CagdRType
	Zero = 0.0;
    IPObjectStruct
	*PObjList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

    if (IP_IS_CRV_OBJ(FreeFormObj)) {
	CagdRType
	    *R = SymbUniformAprxPtOnCrvDistrib(FreeFormObj -> U.Crvs,
					       ParamUniform, NumOfPts);

	for (i = 0; i < NumOfPts; i++)
	    ListObjectInsert(PObjList, i, GenPTObject(&R[i], &Zero, &Zero));
	ListObjectInsert(PObjList, i, NULL);

	IritFree((VoidPtr) R);
    }
    else if (IP_IS_SRF_OBJ(FreeFormObj)) {
	CagdUVType
	    *UV = SymbUniformAprxPtOnSrfDistrib(FreeFormObj -> U.Srfs,
						ParamUniform, NumOfPts);

	for (i = 0; i < NumOfPts; i++)
	    ListObjectInsert(PObjList, i,
			     GenPTObject(&UV[i][0], &UV[i][1], &Zero));
	ListObjectInsert(PObjList, i, NULL);

	IritFree((VoidPtr) UV);
    }
    else {
	IritFatalError("FfPtDist: Invalid freeform to have uniform distribution for!");
	return NULL;
    }

    return PObjList;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to copy the control mesh to a triangular surface's control mesh.   *
*   The triangular surface is allocated here as well.			     *
*   Returns the triangular surface if o.k., otherwise NULL.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   PtObjList:  A list object of control points.   	  	             *
*   Length:     Length of triangular surface (edge).                         *
*   Order:      Order of triangular surface.                           	     *
*   GType:      Geometry type - Bezier, Bspline etc.                         *
*   ErrStr:     If an error, detected, this is initialized with description. *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPObjectStruct *:   A triangular surface object if successful, NULL	     *
*		otherwise.						     *
*****************************************************************************/
static IPObjectStruct *GetControlTriSrfMesh(IPObjectStruct *PtObjList,
					    int Length,
					    int Order,
					    TrngGeomType GType,
					    char **ErrStr)
{
    int i, j, PtSize,
        NumVertices = -1;
    CagdRType **r;
    RealType *v;
    IPObjectStruct *TriSrfObj, *PtObj;
    CagdPointType PtType;

    *ErrStr = NULL;

    if (!IP_IS_OLST_OBJ(PtObjList))
	IritFatalError("CURVE: Not object list object!");

    while ((PtObj = ListObjectGet(PtObjList, ++NumVertices)) != NULL) {
	if (!IP_IS_CTLPT_OBJ(PtObj) &&
	    !IP_IS_POINT_OBJ(PtObj) &&
	    !IP_IS_VEC_OBJ(PtObj)) {
	    *ErrStr = "Non point object found in list";
	    return NULL;
	}
    }

    if (NumVertices < 2) {
	*ErrStr = "Less than 2 points";
	return NULL;
    }
    if (TRNG_LENGTH_MESH_SIZE(Length) != NumVertices) {
	*ErrStr = "Mismatch in number of vertices";
	return NULL;
    }

    /* Coerce all points to a common space, in place. */
    if ((PtType = IritPrsrCoercePtsListTo(PtObjList, CAGD_PT_E1_TYPE))
							== CAGD_PT_NONE) {
	*ErrStr = "";
	return NULL;
    }

    switch (GType) {
	case TRNG_TRISRF_BEZIER_TYPE:
	    TriSrfObj = GenTRISRFObject(TrngBzrTriSrfNew(Length,
							 PtType));
	    break;
	case TRNG_TRISRF_BSPLINE_TYPE:
	    TriSrfObj = GenTRISRFObject(TrngBspTriSrfNew(Length, Order,
							 PtType));
	    break;
	default:
	    break;
    }
    AttrSetObjectColor(TriSrfObj, GlblPrimColor);  /* Set its default color. */
    PtSize = CAGD_IS_RATIONAL_PT(PtType) + CAGD_NUM_OF_PT_COORD(PtType);

    for (r = TriSrfObj -> U.TriSrfs -> Points, i = 0; i < NumVertices; i++) {
	IPObjectStruct
	    *VObj = ListObjectGet(PtObjList, i);

	v = VObj -> U.CtlPt.Coords;

	if (CAGD_IS_RATIONAL_PT(PtType))
	    for (j = 0; j < PtSize; j++)
		r[j][i] = *v++;
	else
	    for (j = 1; j <= PtSize; j++)
		r[j][i] = *++v;
    }

    return TriSrfObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to create a Bezier triangular surface geometric object defined   M
*  by a list of control points.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   RLength:     Length of triangular surface (edge).                        M
*   PtObjList: A list object of control points.			             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *: A Bezier triangualr surface object if successful, NULL M
*		otherwise.						     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenBezierTriSrfObject                                                    M
*****************************************************************************/
IPObjectStruct *GenBezierTriSrfObject(RealType *RLength,
				      IPObjectStruct *PtObjList)
{
    int Length = REAL_PTR_TO_INT(RLength);
    char *ErrStr, Line[LINE_LEN];
    IPObjectStruct
	*TriSrfObj = GetControlTriSrfMesh(PtObjList, Length, -1,
					  TRNG_TRISRF_BEZIER_TYPE, &ErrStr);

    if (TriSrfObj == NULL) {
	sprintf(Line, "TSBEZIER: Ctl mesh, %s, empty object result.\n", ErrStr);
	IritNonFatalError(Line);
    }

    return TriSrfObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to create a Bspline triangular surface geometric object defined  M
* by a list of control points.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   RLength:     Length of triangular surface (edge).                        M
*   ROrder:      Order of triangular surface.                                M
*   PtObjList:   A list object of control points.		             M
*   KntObjList:  A list of knots (numeric values).                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *: A Bspline triangular surface object if successful,     M
*		NULL otherwise.						     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenBsplineTriSrfObject                                                   M
*****************************************************************************/
IPObjectStruct *GenBsplineTriSrfObject(RealType *RLength,
				       RealType *ROrder,
				       IPObjectStruct *PtObjList,
				       IPObjectStruct *KntObjList)
{
    int Len,
	Length = REAL_PTR_TO_INT(RLength),
	Order = REAL_PTR_TO_INT(ROrder);
    char *ErrStr, Line[LINE_LEN];
    IPObjectStruct
	*TriSrfObj = GetControlTriSrfMesh(PtObjList, Length, Order,
					  TRNG_TRISRF_BSPLINE_TYPE, &ErrStr);

    if (TriSrfObj == NULL) {
	sprintf(Line, "TSBSPLINE: Ctl mesh, %s, empty object result.\n", ErrStr);
	IritNonFatalError(Line);
	return NULL;
    }

    if (TriSrfObj -> U.TriSrfs -> Length < TriSrfObj -> U.TriSrfs -> Order) {
	IPFreeObject(TriSrfObj);
	IritNonFatalError("TBSPLINE: TriSrf mesh length smaller than order.");
	return NULL;
    }

    IritFree((VoidPtr) TriSrfObj -> U.TriSrfs -> KnotVector);
    TriSrfObj -> U.TriSrfs -> KnotVector = NULL;
    Len = TriSrfObj -> U.TriSrfs -> Length;
    if ((TriSrfObj -> U.TriSrfs -> KnotVector =
	 GetKnotVector(KntObjList, Order, &Len, &ErrStr)) == NULL) {
	sprintf(Line, "TSBSPLINE: Knot vector, %s, empty object result.\n",
		ErrStr);
	IPFreeObject(TriSrfObj);
	IritNonFatalError(Line);
	return NULL;
    }

    if (Len != TriSrfObj -> U.TriSrfs -> Length + Order) {
	IPFreeObject(TriSrfObj);
	IritNonFatalError("Wrong knot vector length");
	return NULL;
    }

    return TriSrfObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluate a triangular surface function, at the prescribed parametric     M
* location.								     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrfObj:    Triangular Surface to evaluate.                            M
*   u, v, w:      Parametric location to evaluate at.                        M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A control point of the same type TriSrf has.          M
*                                                                            *
* KEYWORDS:                                                                  M
*   EvalTriSrfObject                                                         M
*****************************************************************************/
IPObjectStruct *EvalTriSrfObject(IPObjectStruct *TriSrfObj,
				 RealType *u,
				 RealType *v,
				 RealType *w)
{
    CagdRType *Pt;
    IPObjectStruct *CtlPtObj;

    if (!APX_EQ(*u + *v + *w, 1.0)) {
	IritNonFatalError("Barycentric coordinates of triangular surface must sum to one");
	return NULL;
    }

    Pt = TrngTriSrfEval(TriSrfObj -> U.TriSrfs, *u, *v, *w);
    CtlPtObj = GenCTLPTObject(TriSrfObj -> U.TriSrfs -> PType, Pt, NULL);

    return CtlPtObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluate the normal of a point on a triangular surface function, at the  M
* prescribed parametric location.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrfObj:    Triangular Surface to evaluate normal at a point.          M
*   u, v, w:      Parametric location to evaluate at.                        M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A control point of the same type TriSrf has.          M
*                                                                            *
* KEYWORDS:                                                                  M
*   NormalTriSrfObject                                                       M
*****************************************************************************/
IPObjectStruct *NormalTriSrfObject(IPObjectStruct *TriSrfObj,
				   RealType *u,
				   RealType *v,
				   RealType *w)
{
    IPObjectStruct *NormalObj;
    CagdVecStruct *Nrml;

    if (!APX_EQ(*u + *v + *w, 1.0)) {
	IritNonFatalError("Barycentric coordinates of triangular surface must sum to one");
	return NULL;
    }

    Nrml = TrngTriSrfNrml(TriSrfObj -> U.TriSrfs, *u, *v);
    NormalObj = GenVECObject(&Nrml -> Vec[0], &Nrml -> Vec[1],
			     &Nrml -> Vec[2]);

    return NormalObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to differentiate a triangular surface function in Dir of SrfObj.   M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrfObj:    TriSrf to differentiate.                                   M
*   Dir:          Direction of differentiation. Either U or V or W.          M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A differentiated TriSrf.                             M
*                                                                            *
* KEYWORDS:                                                                  M
*   DeriveTriSrfObject                                                       M
*****************************************************************************/
IPObjectStruct *DeriveTriSrfObject(IPObjectStruct *TriSrfObj, RealType *Dir)
{
    TrngTriangSrfStruct
	*DerivTriSrf = TrngTriSrfDerive(TriSrfObj -> U.TriSrfs,
				   (TrngTriSrfDirType) REAL_PTR_TO_INT(Dir));
    IPObjectStruct
	*DerivTriSrfObj = GenTRISRFObject(DerivTriSrf);

    return DerivTriSrfObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes a three dimensional envelope of the offset propagation crom     M
* curve Crv.  The nevelope height (also offset distance) will be set to      M
* Height, and will be approximated within Tolerance accuracy.                M
*                                                                            *
* PARAMETERS:                                                                M
*   CrvObj:        Curve to compute the envelope offset.                     M
*   Height:        Height of enevlope offset.                                M
*   Tolerance:     Accuracy of envelope offset.                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   The evelope offset. One surface object for an open   M
*		curve, two surfaces in a list for a closed curve.	     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CurveEnvelopeOffset, offset                                              M
*****************************************************************************/
IPObjectStruct *CurveEnvelopeOffset(IPObjectStruct *CrvObj,
				    RealType *Height,
				    RealType *Tolerance)
{
    CagdSrfStruct
	*EnvSrf1 = SymbEnvOffsetFromCrv(CrvObj -> U.Crvs, *Height, *Tolerance);

    if (EnvSrf1 == NULL)
        return NULL;
    else if (EnvSrf1 -> Pnext == NULL) {
	return GenSRFObject(EnvSrf1);
    }
    else {
	IPObjectStruct
	    *PObjList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

	ListObjectInsert(PObjList, 0, GenSRFObject(EnvSrf1));
	ListObjectInsert(PObjList, 1, GenSRFObject(EnvSrf1 -> Pnext));
	EnvSrf1 -> Pnext = NULL;
	ListObjectInsert(PObjList, 2, NULL);

	return PObjList;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes the bisector curves for a given freeform curve, to within a     M
* prescribed Tolerance.                                                      M
*                                                                            *
* PARAMETERS:                                                                M
*   CrvObj:         Curve to compute the bisector curves for. Either a       M
*                   single curve (self bisectors) or a list of two curves    M
*		    or a list of a curve and a point.			     M
*   RUseNrmlTan:    0, 1, 2 to use tangent fields, normal fields, or a blend M
*		    of the two, respectively.				     M
*		    -1 for bisector surface of two three space curves, or    M
*		    a space curve and a point.				     M
*   Tolerance:      Accuracy of bisector computation, or scaling of the	     M
*		    ruling direction in the curve/point bisector.	     M
*   RNumerImprove:  If TRUE, numerical improvement is to be applied.	     M
*   RSameNormal:    If TRUE, the bisector should be oriented for inner or    M
*		    outer side of the curves, with respect to their normals. M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   List object of bisector curves.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   CurveBisectorSkel, bisectors, skeleton                                   M
*****************************************************************************/
IPObjectStruct *CurveBisectorSkel(IPObjectStruct *CrvObj,
				  RealType *RUseNrmlTan,
				  RealType *Tolerance,
				  RealType *RNumerImprove,
				  RealType *RSameNormal)
{
    CagdCrvStruct *Bisectors;
    IPObjectStruct *PObjList;
    int i,
	UseNrmlTan = REAL_PTR_TO_INT(RUseNrmlTan),
	NumerImprove = REAL_PTR_TO_INT(RNumerImprove),
	SameNormal = REAL_PTR_TO_INT(RSameNormal);

    if (IP_IS_CRV_OBJ(CrvObj)) {
	if (*Tolerance <= 0.0 || UseNrmlTan == -1)
	    return GenSRFObject(SymbCrvBisectorsSrf(CrvObj -> U.Crvs,
						    UseNrmlTan));

	Bisectors = SymbCrvBisectors(CrvObj -> U.Crvs, UseNrmlTan, *Tolerance,
				     NumerImprove, SameNormal);
    }
    else if (IP_IS_OLST_OBJ(CrvObj)) {
	IPObjectStruct
	    *CrvObj1 = ListObjectGet(CrvObj, 0),
	    *Obj2 = ListObjectGet(CrvObj, 1);

	if (IP_IS_CRV_OBJ(CrvObj1) && IP_IS_CRV_OBJ(Obj2)) {
	    CagdCrvStruct
		*Crv1 = CagdCrvCopy(CrvObj1 -> U.Crvs);
	    CagdSrfStruct *BisectSrf;

	    Crv1 -> Pnext = Obj2 -> U.Crvs;

	    if (UseNrmlTan == -2 &&
		Crv1 -> PType == CAGD_PT_E2_TYPE &&
		Crv1 -> Pnext -> PType == CAGD_PT_E2_TYPE) {
	        BisectSrf = SymbCrvBisectorsSrf2(Crv1);

		CagdCrvFree(Crv1);
		return GenSRFObject(BisectSrf);
	    }
	    else if (*Tolerance <= 0.0 || UseNrmlTan == -1) {
		BisectSrf = SymbCrvBisectorsSrf(Crv1, UseNrmlTan);

		CagdCrvFree(Crv1);
		return GenSRFObject(BisectSrf);
	    }

	    Bisectors = SymbCrvBisectors(Crv1, UseNrmlTan, *Tolerance,
					 NumerImprove, SameNormal);

	    CagdCrvFree(Crv1);
	}
	else if (IP_IS_CRV_OBJ(CrvObj1) && IP_IS_POINT_OBJ(Obj2)) {
	    CagdCrvStruct
		*Crv = CrvObj1 -> U.Crvs;
	    CagdRType
		*Pt = Obj2 -> U.Pt;
	    CagdSrfStruct
		*BisectSrf = SymbCrvPtBisectorSrf3D(Crv, Pt, *Tolerance);

	    return GenSRFObject(BisectSrf);
	}
	else {
	    IritNonFatalError("Expecting a list of two curves");
	    return NULL;
	}
    }
    else {
	IritFatalError("Expecting either a curve or a list of two curves");
	return NULL;
    }

    PObjList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

    i = 0;
    while (Bisectors != NULL) {
	CagdCrvStruct
	    *Crv = Bisectors;

	Bisectors = Bisectors -> Pnext;
	Crv -> Pnext = NULL;

	ListObjectInsert(PObjList, i++, GenCRVObject(Crv));
    }
    ListObjectInsert(PObjList, i, NULL);

    return PObjList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes the bisector surface for a given freeform surface and a point.  M
*                                                                            *
* PARAMETERS:                                                                M
*   SrfObj:     Surface to compute the bisector surface for.		     M
*   Pt:		Point to compute the bisector surface for.		     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   The bisector surface.                                M
*                                                                            *
* KEYWORDS:                                                                  M
*   SurfaceBisectorSkel, bisectors, skeleton                                 M
*****************************************************************************/
IPObjectStruct *SurfaceBisectorSkel(IPObjectStruct *SrfObj, PointType Pt)
{
    CagdSrfStruct
	*BisectSrf = SymbSrfPtBisectorSrf3D(SrfObj -> U.Srfs, Pt);

    if (BisectSrf != NULL)
	return GenSRFObject(BisectSrf);
    else
	return NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes the K-oprthotomics of freeform curves and surfaces.             M
*                                                                            *
* PARAMETERS:                                                                M
*   FreeForm: A curve or a surface to compute its K-orthotomic.              M
*   Pt:	      The points to which the K-orthotomic is computed for FreeForm. M
*   K:        The magnitude of the orthotomic function.                      M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  The K-orthotomic of the freeform relative to point P  M
*                                                                            *
* KEYWORDS:                                                                  M
*   FreeFormOrthotomic                                                       M
*****************************************************************************/
IPObjectStruct *FreeFormOrthotomic(IPObjectStruct *FreeForm,
				   PointType Pt,
				   RealType *K)
{
    IPObjectStruct
	*PObj = NULL;

    if (IP_IS_CRV_OBJ(FreeForm)) {
	PObj = GenCRVObject(SymbCrvOrthotomic(FreeForm -> U.Crvs, Pt, *K));
    }
    else if (IP_IS_SRF_OBJ(FreeForm)) {
	PObj = GenSRFObject(SymbSrfOrthotomic(FreeForm -> U.Srfs, Pt, *K));
    }
    else {
	IritFatalError("FFPoles: Invalid freeform to check for poles!");
	return NULL;
    }

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Returns TRUE if freeform has poles.                                      M
*                                                                            *
* PARAMETERS:                                                                M
*   FreeForm:   To check for poles.                                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  TRUE if FreeForm has poles, FALSE otherwise.          M
*                                                                            *
* KEYWORDS:                                                                  M
*   FreeFormPoles	                                                     M
*****************************************************************************/
IPObjectStruct *FreeFormPoles(IPObjectStruct *FreeForm)
{
    int Length;
    CagdRType **Points;

    if (IP_IS_CRV_OBJ(FreeForm)) {
	Points = FreeForm -> U.Crvs -> Points;
	Length = FreeForm -> U.Crvs -> Length;
    }
    else if (IP_IS_SRF_OBJ(FreeForm)) {
	Points = FreeForm -> U.Srfs -> Points;
	Length = FreeForm -> U.Srfs -> ULength * FreeForm -> U.Srfs -> VLength;
    }
    else if (IP_IS_TRIVAR_OBJ(FreeForm)) {
	Points = FreeForm -> U.Trivars -> Points;
	Length = FreeForm -> U.Trivars -> ULength *
	         FreeForm -> U.Trivars -> VLength *
	         FreeForm -> U.Trivars -> WLength;
    }
    else if (IP_IS_TRIMSRF_OBJ(FreeForm)) {
	Points = FreeForm -> U.TrimSrfs -> Srf -> Points;
	Length = FreeForm -> U.TrimSrfs -> Srf -> ULength *
	         FreeForm -> U.TrimSrfs -> Srf -> VLength;
    }
    else if (IP_IS_TRISRF_OBJ(FreeForm)) {
	Points = FreeForm -> U.TriSrfs -> Points;
	Length = TRNG_TRISRF_MESH_SIZE(FreeForm -> U.TriSrfs);
    }
    else {
	IritFatalError("FFPoles: Invalid freeform to check for poles!");
	return NULL;
    }

    return GenNUMValObject(CagdPointsHasPoles(Points, Length));
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes curvature properties of an iso surface at a given position Pos  M
* for a scalar triavariate function.					     M
* This function is geared toward numerous evaluations.  Hence, an invokation M
* with:									     M
*    Compute == -1 :  Would initialize auxiliary differential vector fields. V
*    Compute == 0  :  Would release all auxiliary data structures.           V
*    Compute == 1  :  Would compute the gradient of the trivariate, at Pos.  V
*    Compute == 2  :  Would compute the Hessian of the trivariate, at Pos.   V
*    Compute == 3  :  Would compute the principal curvatures/directions of   V
*		      the trivariate, at Pos.			             V
*                                                                            *
* PARAMETERS:                                                                M
*   TrivObj:       To compute differential/curvature properties for.         M
*   Pos:	   Where to evaluate the differentail/curvature properties.  M
*   Compute:       What to preprocess/compute/free.                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  TRUE if Compute == -1 or Compute == 0 and successful. M
*               The gradient vector if Compute == 1. The Hessian (list of    M
*		three vectors) if Compute == 2.  A list with two principal   M
*		curvatures and two principal directions if Computer == 3.    M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrivIsoContourCurvature                                                  M
*****************************************************************************/
IPObjectStruct *TrivIsoContourCurvature(IPObjectStruct *TrivObj,
					PointType Pos,
					RealType *RCompute)
{
    int i,
	Compute = REAL_PTR_TO_INT(RCompute);
    CagdRType PCurv1, PCurv2;
    CagdVType PDir1, PDir2, Gradient, Hessian[3];
    IPObjectStruct *PObjList;

    switch (Compute) {
	case -1:
            if (!GenNUMValObject(TrivEvalTVCurvaturePrelude(TrivObj -> U.Trivars))) {
	        WndwInputWindowPutStr("Failed to initialized trivariate's auxiliary differential fields.");
		return NULL;
	    }
	    return GenNUMValObject(TRUE);
	case 0:
	    TrivEvalTVCurvaturePostlude();
	    return GenNUMValObject(TRUE);
	case 1:
	    if (!TrivEvalGradient(Pos, Gradient)) {
	        WndwInputWindowPutStr("Failed to compute gradient (not initialized!?).");

	        return NULL;
	    }
	    return GenVECObject(&Gradient[0], &Gradient[1], &Gradient[2]);
	case 2:
	    if (!TrivEvalHessain(Pos, Hessian)) {
	        WndwInputWindowPutStr("Failed to compute Hessian (not initialized!?).");
	        return NULL;
	    }

	    PObjList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

	    for (i = 0; i < 3; i++)
		ListObjectInsert(PObjList, i,
				 GenVECObject(&Hessian[i][0],
					      &Hessian[i][1],
					      &Hessian[i][2]));
	    ListObjectInsert(PObjList, 3, NULL);
	    return PObjList;
	case 3:
	    if (!TrivEvalCurvature(Pos, &PCurv1, &PCurv2, PDir1, PDir2)) {
	        WndwInputWindowPutStr("Failed to compute Principal curvatures/directions (not initialized!?).");
	        return NULL;
	    }

	    PObjList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

	    ListObjectInsert(PObjList, 0, GenNUMValObject(PCurv1));
	    ListObjectInsert(PObjList, 1,
			     GenVECObject(&PDir1[0], &PDir1[1], &PDir1[2]));
	    ListObjectInsert(PObjList, 2, GenNUMValObject(PCurv2));
	    ListObjectInsert(PObjList, 3,
			     GenVECObject(&PDir2[0], &PDir2[1], &PDir2[2]));
	    ListObjectInsert(PObjList, 4, NULL);
	    return PObjList;
	default:
	    WndwInputWindowPutStr("Wrong curvature property to evaluate.\n");
	    return NULL;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Compute a polygonal iso surface approximation at iso value IsoVal to the M
* given volume specification.                                                M
*                                                                            *
* PARAMETERS:                                                                M
*   VolumeSpec:   Can be a list of one of the following forms:               M
*		1. "list(Trivar, Axis)" - here the volume is a trivariate    M
*		   and the iso surface should be computed with respect to    M
*		   the prescribed Axis (1 for X, 2 for Y, etc.).	     M
*		2. "list(FileName, DataType, Width, Height, Depth)" - here   M
*		   the volume is read from the given file of given three     M
*		   dimensions.  Each scalar value in the file can be an      M
*		   ascii string (DataType = 1), 2 bytes integer (2), 4 bytes M
*		   integer (4), 4 bytes float (5), and 8 bytes double (6).   M
*   CubeDim:    Width, height, and depth of a single cube, in object space   M
*		coordinates.						     M
*   RSkipFactor: Typically 1.  For 2, only every second sample is considered M
*		and for i, only every i'th sample is considered, in all axes.M
*   RIsoVal:    At which to extract the iso-surface.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *: A polygonal approximation of the iso-surface at IsoVal M
*		computed using the marching cubes algorithm.	             M
*                                                                            *
* SEE ALSO:                                                                  M
*   MCThresholdCube, MCExtractIsoSurface, MCExtractIsoSurface2               M
*                                                                            *
* KEYWORDS:                                                                  M
*   MarchCubeVolume                                                          M
*****************************************************************************/
IPObjectStruct *MarchCubeVolume(IPObjectStruct *VolumeSpec,
				PointType CubeDim,
				RealType *RSkipFactor,
				RealType *RIsoVal)
{
    IPObjectStruct *PObj1, *PObj2, *PObj3, *PObj4, *PObj5,
	*RetVal = NULL;

    switch (ListObjectLength(VolumeSpec)) {
	case 3:
	    PObj1 = ListObjectGet(VolumeSpec, 0);
	    PObj2 = ListObjectGet(VolumeSpec, 1);
	    PObj3 = ListObjectGet(VolumeSpec, 2);
	    if (PObj1 && IP_IS_TRIVAR_OBJ(PObj1) &&
		PObj2 && IP_IS_NUM_OBJ(PObj2) &&
		PObj3 && IP_IS_NUM_OBJ(PObj3)) {
	        RetVal = MCExtractIsoSurface2(PObj1 -> U.Trivars,
					      REAL_TO_INT(PObj2 -> U.R),
					      REAL_TO_INT(PObj3 -> U.R),
					      CubeDim,
					      REAL_PTR_TO_INT(RSkipFactor),
					      *RIsoVal);
	    }
	    else
	        IritNonFatalError("Failed to march cube the volume (wrong input!?).");
	    break;
	case 5:
	    PObj1 = ListObjectGet(VolumeSpec, 0);
	    PObj2 = ListObjectGet(VolumeSpec, 1);
	    PObj3 = ListObjectGet(VolumeSpec, 2);
	    PObj4 = ListObjectGet(VolumeSpec, 3);
	    PObj5 = ListObjectGet(VolumeSpec, 4);
	    if (PObj1 && IP_IS_STR_OBJ(PObj1) &&
		PObj2 && IP_IS_NUM_OBJ(PObj2) &&
		PObj3 && IP_IS_NUM_OBJ(PObj3) &&
		PObj4 && IP_IS_NUM_OBJ(PObj4) &&
		PObj5 && IP_IS_NUM_OBJ(PObj5)) {
	        RetVal = MCExtractIsoSurface(PObj1 -> U.Str,
					     REAL_TO_INT(PObj2 -> U.R),
					     CubeDim,
					     REAL_TO_INT(PObj3 -> U.R),
					     REAL_TO_INT(PObj4 -> U.R),
					     REAL_TO_INT(PObj5 -> U.R),
					     REAL_PTR_TO_INT(RSkipFactor),
					     *RIsoVal);
	    }
	    else
	        IritNonFatalError("Failed to march cube the volume (wrong input!?).");
	    break;
	default:
	    IritNonFatalError("Expecting either 3 or 5 entities in volume spec.");
	    break;
    }

    return RetVal;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes a uniform point coverage of a polygonal model.	             M
*                                                                            *
* PARAMETERS:                                                                M
*   PolyObj:   To compute a point coverage for.                              M
*   Rn:        Estimated number of points desired.                           M
*   Dir:       A given direction to compute distribution from, or a zero     M
*	       vector for direction independent Euclidean measure.	     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A set of points covering PolyObj.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   PointCoverPolyObj                                                        M
*****************************************************************************/
IPObjectStruct *PointCoverPolyObj(IPObjectStruct *PolyObj,
				  RealType *Rn,
				  RealType *Dir)
{
    if (PT_APX_EQ_ZERO_EPS(Dir, IRIT_EPS))
	Dir = NULL;

    return CGPointCoverOfPolyObj(PolyObj, REAL_PTR_TO_INT(Rn), Dir);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes curve coverage of a trivariate model, for specific iso surface. M
*                                                                            *
* PARAMETERS:                                                                M
*   TVObj:         To compute a curve based coverage for.                    M
*   RNumSTrokes:   Number of strokes to handle and generate.                 M
*   RStrokeMinMax: A two bits pattern:  Bit zero controls the drawing of     M
*		   a stroke in the minimal curvature's direction.  Bit one   M
*		   the drawing of a stroke in maximal curvature's direction. M
*   MinMaxPwrLen:  Arc length of each stroke (randomized in between).	     M
*		   a triplet of the form (Min, Max, Power) that determines   M
*		   the length of each stroke as:			     M
*			Avg = (Max + Min) / 2,      Dev = (Max - Min) / 2    V
*		        Length = Avg + Dev * Random(0, 1)^ Pwr		     V
*   RStepSize:	   Steps to take in the piecewise linear approximation.      M
*   RIsoVal:       Of iso surface of TV that coverage is to be computed for. M
*   ViewDir:	   direction of view, used for silhouette computation.	     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A set of points covering PolyObj.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IsoCoverTVObj                                                            M
*****************************************************************************/
IPObjectStruct *IsoCoverTVObj(IPObjectStruct *TVObj,
			      RealType *RNumStrokes,
			      RealType *RStrokeType,
			      VectorType MinMaxPwrLen,
			      RealType *RStepSize,
			      RealType *RIsoVal,
			      VectorType ViewDir)
{
    return GenCRVObject(
	   TrivCoverIsoSurfaceUsingStrokes(TVObj -> U.Trivars,
					   REAL_PTR_TO_INT(RNumStrokes),
					   REAL_PTR_TO_INT(RStrokeType),
					   MinMaxPwrLen,
					   *RStepSize,
					   *RIsoVal,
					   ViewDir));
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Loads a volumetric data set as a trivariate function of prescribed       M
* orders.  Uniform open end conditions are created for it.                   M
*                                                                            *
* PARAMETERS:                                                                M
*   FileName:    To load the trivariate data set from.                       M
*   RDataType:   Type of scalar value in volume data file.  Can be one of:   M
*		   1 - Regular ascii (seperated by while spaces.             M
*		   2 - Two bytes short integer.				     M
*		   3 - Four bytes long integer.				     M
*		   4 - One byte (char) integer.				     M
*		   5 - Four bytes float.				     M
*		   6 - Eight bytes double.				     M
*   VolSize:     Dimensions of trivariate voluem.                            M
*   Orders:      Orders of the three axis of the volume (in U, V, and W).    M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A trivariate, or NULL if error.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   LoadVolumeIntoTV                                                         M
*****************************************************************************/
IPObjectStruct *LoadVolumeIntoTV(char *FileName,
				 RealType *RDataType,
				 VectorType VolSize,
				 VectorType Orders)
{
    TrivTVStruct
	*TV = TrivLoadVolumeIntoTV(FileName,
				   REAL_PTR_TO_INT(RDataType),
				   VolSize,
				   Orders);

    return TV == NULL ? NULL : GenTRIVARObject(TV);
}

