/*****************************************************************************
*   "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 handle the objects list - fetch, insert, delete etc...	     *
*****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "program.h"
#include "allocate.h"
#include "attribut.h"
#include "primitiv.h"
#include "geomat3d.h"
#include "objects.h"
#include "bbox.h"
#include "freeform.h"

#define IS_IRIT_FLOAT_PRINTF_CMD(c) ((c) == 'e' || (c) == 'f' || (c) == 'g' ||\
				     (c) == 'E' || (c) == 'F')
#define IS_PRINTF_CMD(c)  (IS_IRIT_FLOAT_PRINTF_CMD(c) || \
			   (c) == 'd' || (c) == 'i' || (c) == 'u' || \
			   (c) == 'o' || (c) == 'x' || (c) == 'X' || \
			   (c) == 's' || (c) == 'p' || (c) == 'v' || \
			   (c) == 'P' || (c) == 'D')

static IPPolygonStruct *GenAxesObjectPolylines(void);

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to set up all the predefined objects - objects that the system     M
*   must have all the time, like global transformation matrices.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            M
* KEYWORDS:                                                                  M
*   SetUpPredefObjects                                                       M
*****************************************************************************/
void SetUpPredefObjects(void)
{
    RealType R;
    MatrixType Mat1, Mat2;
    IPObjectStruct *PObj;

    /* 90 - 35.2644 = 54.7356 */
    MatGenMatRotX1(DEG2RAD(-54.7356), Mat1); /* Generate default view trans. */
    MatGenMatRotZ1(M_PI+M_PI/4, Mat2);		 /* which is isometric view. */
    MatMultTwo4by4(Mat2, Mat2, Mat1);
    PObj = GenMatObject("VIEW_MAT", Mat2, NULL);
    InsertObject(PObj);

    MatGenUnitMat(Mat1);	      /* Generate default perspective trans. */
    Mat1[2][2] = 0.1;
    Mat1[2][3] = -0.35;
    Mat1[3][2] = 0.35;
    PObj = GenMatObject("PRSP_MAT", Mat1, NULL);
    InsertObject(PObj);

    R = DEFAULT_RESOLUTION;
    PObj = GenNumObject("RESOLUTION", &R, NULL);
    InsertObject(PObj);

    R = DEFAULT_DRAW_CTLPT;
    PObj = GenNumObject("DRAWCTLPT", &R, NULL);
    InsertObject(PObj);

    R = 0;
    PObj = GenNumObject("FLAT4PLY", &R, NULL);
    InsertObject(PObj);

    R = 0;
    PObj = GenNumObject("POLY_APPROX_OPT", &R, NULL);
    InsertObject(PObj);

    R = 0;
    PObj = GenNumObject("POLY_APPROX_UV", &R, NULL);
    InsertObject(PObj);

    R = 0.3;
    PObj = GenNumObject("POLY_APPROX_TOL", &R, NULL);
    InsertObject(PObj);

    R = MACHINE_UNIX;
#if defined(__MSDOS__) || defined(DJGCC)
    R = MACHINE_MSDOS;
#endif
#if defined(sgi)
    R = MACHINE_SGI;
#endif
#if defined(hpbsd) || defined(hpux) || defined(__hpux)
    R = MACHINE_HP;
#endif
#if defined(sun) || defined(SUN4)
    R = MACHINE_SUN;
#endif
#if defined(apollo)
    R = MACHINE_APOLLO;
#endif
#if defined(OS2GCC)
    R = MACHINE_IBMOS2;
#endif
#if defined(WIN32NT)
    R = MACHINE_IBMNT;
#endif
#if defined(AMIGA)
    R = MACHINE_AMIGA;
#endif

    PObj = GenNumObject("MACHINE", &R, NULL);
    InsertObject(PObj);

    PObj = GenPolyObject("AXES", GenAxesObjectPolylines(), NULL);
    IP_SET_POLYLINE_OBJ(PObj);		      /* Mark it as polyline object. */
    InsertObject(PObj);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Sets the color attribute of an object.                                   M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     To set an attribute for.                                       M
*   RColor:   Color to set to.                                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   SetObjectAttrColor                                                       M
*****************************************************************************/
void SetObjectAttrColor(IPObjectStruct *PObj, RealType *RColor)
{
    IPObjectStruct
	*Data = GenNUMObject(RColor);

    SetObjectAttrib(PObj, "color", Data);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Sets the width attribute of an object.                                   M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     To set an attribute for.                                       M
*   RWidth:   Width to set to.                                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   SetObjectAttrWidth                                                       M
*****************************************************************************/
void SetObjectAttrWidth(IPObjectStruct *PObj, RealType *RWidth)
{
    IPObjectStruct
	*Data = GenNUMObject(RWidth);

    SetObjectAttrib(PObj, "width", Data);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Sets the display width attribute of an object.                           M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     To set an attribute for.                                       M
*   RDWidth:  Display width to set to.                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   SetObjectAttrDWidth                                                      M
*****************************************************************************/
void SetObjectAttrDWidth(IPObjectStruct *PObj, RealType *RDWidth)
{
    IPObjectStruct
	*Data = GenNUMObject(RDWidth);

    SetObjectAttrib(PObj, "dwidth", Data);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to set an attribute of an object.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     To set an attribute for.                                       M
*   Name:     Name of attribute.                                             M
*   Data:     new value of attribute                                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   SetObjectAttrib                                                          M
*****************************************************************************/
void SetObjectAttrib(IPObjectStruct *PObj, char *Name, IPObjectStruct *Data)
{
    if (IP_IS_STR_OBJ(Data))
	AttrSetObjectStrAttrib(PObj, Name, Data -> U.Str);
    else if (IP_IS_NUM_OBJ(Data)) {
	RealType
	    r = Data -> U.R;

	if (r == (int) r)
	    AttrSetObjectIntAttrib(PObj, Name, (int) r);
	else
	    AttrSetObjectRealAttrib(PObj, Name, r);
    }
    else
        AttrSetObjectObjAttrib(PObj, Name, Data, TRUE);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to get an attribute of an object.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     To get an attribute from.                                      M
*   Name:     Name of attribute.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetObjectAttrib                                                          M
*****************************************************************************/
IPObjectStruct *GetObjectAttrib(IPObjectStruct *PObj, char *Name)
{
    IPObjectStruct *PAttrObj;
    char *Str;
    RealType R;

    if ((PAttrObj = AttrGetObjectObjAttrib(PObj, Name)) != NULL)
        return CopyObject(NULL, PAttrObj, FALSE);

    if ((Str = AttrGetObjectStrAttrib(PObj, Name)) != NULL)
        return GenSTRObject(IritStrdup(Str));

    if ((R = AttrGetObjectRealAttrib(PObj, Name)) != IP_ATTR_BAD_REAL)
        return GenNUMObject(&R);

    return NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to remove an attribute from an object.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     To remover an attribute from.                                  M
*   Name:     Name of attribute.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   RemoveObjectAttrib                                                       M
*****************************************************************************/
void RemoveObjectAttrib(IPObjectStruct *PObj, char *Name)
{
    AttrFreeOneAttribute(&PObj -> Attrs, Name);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Generate an axis coordinate system with length of 1 on each axis.	     *
*                                                                            *
* PARAMETERS:                                                                *
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPPolygonStruct *:   A polyline representing the XYZ coordinate system.  *
*****************************************************************************/
static IPPolygonStruct *GenAxesObjectPolylines(void)
{
    IPPolygonStruct *Pl, *PlHead;
    IPVertexStruct *V;

    /* X axis. */
    Pl = PlHead = IPAllocPolygon(0, NULL, NULL);
    Pl -> PVertex = V = IPAllocVertex(0, NULL, NULL);
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 1.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 1.0;    V -> Coord[1] = 0.1;   V -> Coord[2] = 0.1;
    AttrSetRGBColor(&Pl -> PVertex -> Attrs, 255, 255, 255);
    for (V = Pl -> PVertex -> Pnext; V != NULL; V = V -> Pnext)
	AttrSetRGBColor(&V -> Attrs, 255, 64, 64);

    Pl -> Pnext = IPAllocPolygon(0, NULL, NULL); Pl = Pl -> Pnext;
    Pl -> PVertex = V = IPAllocVertex(0, NULL, NULL);
    V -> Coord[0] = 1.0;    V -> Coord[1] = 0.1;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 1.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.1;
    for (V = Pl -> PVertex; V != NULL; V = V -> Pnext)
	AttrSetRGBColor(&V -> Attrs, 255, 64, 64);

    /* Y axis.*/
    Pl -> Pnext = IPAllocPolygon(0, NULL, NULL); Pl = Pl -> Pnext;
    Pl -> PVertex = V = IPAllocVertex(0, NULL, NULL);
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.0;    V -> Coord[1] = 1.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.0;    V -> Coord[1] = 1.0;   V -> Coord[2] = 0.06;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.04;   V -> Coord[1] = 1.0;   V -> Coord[2] = 0.1;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.0;    V -> Coord[1] = 1.0;   V -> Coord[2] = 0.06;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] =(-0.04); V -> Coord[1] = 1.0;   V -> Coord[2] = 0.1;
    AttrSetRGBColor(&Pl -> PVertex -> Attrs, 255, 255, 255);
    for (V = Pl -> PVertex -> Pnext; V != NULL; V = V -> Pnext)
	AttrSetRGBColor(&V -> Attrs, 64, 255, 64);

    /* Z axis.*/
    Pl -> Pnext = IPAllocPolygon(0, NULL, NULL); Pl = Pl -> Pnext;
    Pl -> PVertex = V = IPAllocVertex(0, NULL, NULL);
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 1.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.1;    V -> Coord[1] = 0.0;   V -> Coord[2] = 1.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.1;   V -> Coord[2] = 1.0;
    V -> Pnext = IPAllocVertex(0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.1;    V -> Coord[1] = 0.1;   V -> Coord[2] = 1.0;
    AttrSetRGBColor(&Pl -> PVertex -> Attrs, 255, 255, 255);
    for (V = Pl -> PVertex -> Pnext; V != NULL; V = V -> Pnext)
	AttrSetRGBColor(&V -> Attrs, 64, 64, 255);

    return PlHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Constructs a geometry representing the given text in Str, with Spacing   M
* space between character and scaling factor of Scale.			     M
*   This functions preloads the font in iritfont.dat in the directory that   M
* is prescribed by the IRIT_PATH environment variable.	If the font is not   M
* found, NULL is returned. The font file contains the geometries of the      M
* characters as a list ordered according to the ASCII table starting for 32. M
*                                                                            *
* PARAMETERS:                                                                M
*   Str:        The text to convert to geometry.                             M
*   Spacing:    Between individual characters, in X, Y, Z.                   M
*   Scaling:    Relative, with scaling of one generates unit size chars.     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Geometry representing the given text.                M
*                                                                            *
* KEYWORDS:                                                                  M
*   MakeTextGeometry                                                         M
*****************************************************************************/
IPObjectStruct *MakeTextGeometry(char *Str,
				 VectorType Spacing,
				 RealType *Scaling)
{
    static IPObjectStruct
	*Font = NULL;
    int i, j;
    IPObjectStruct *Geom;
    MatrixType Mat1, Mat2;

    if (Font == NULL) {
	char *p, FName[LINE_LEN];
	FILE *f;

	if ((p = getenv("IRIT_PATH")) == NULL) {
	    WndwInputWindowPutStr("IRIT_PATH env. not set. Cannot load irit font.");
	    return NULL;
	}

	/* Sense if we have a compressed dat file here. */
	sprintf(FName, "%siritfont.dat.Z", p);
	if ((f = fopen(FName, "r")) == NULL)
	    sprintf(FName, "%siritfont.dat", p);
	else
	     fclose(f);

	Font = LoadObjectFromFile(FName);

	if (Font == NULL || !IP_IS_OLST_OBJ(Font)) {
	    WndwInputWindowPutStr("Unable to read font or invalid format.");
	    Font = NULL;
	    return NULL;
	}
    }

    MatGenMatUnifScale(*Scaling, Mat1);
    MatGenMatTrans(Spacing[0], Spacing[1], Spacing[2], Mat2);

    Geom = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);
    for (i = j = 0; i < strlen(Str); i++) {
	IPObjectStruct
	    *PTmp = ListObjectGet(Font, Str[i] - 32);

	if (PTmp != NULL && !IP_IS_NUM_OBJ(PTmp)) {
	    PTmp = GMTransformObject(PTmp, Mat1);

	    ListObjectInsert(Geom, j++, PTmp);
	}
	MatMultTwo4by4(Mat1, Mat1, Mat2);
    }
    ListObjectInsert(Geom, j++, NULL);

    return Geom;
}


/*****************************************************************************
* DESCRIPTION:                                                               M
* Returns the type of an object.					     M
*   If object is not found, an undefined type is returned.                   M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:       Of object to query type.                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   double:     Type of object, coerced to double                            M
*                                                                            *
* KEYWORDS:                                                                  M
*   ThisObjectIs                                                             M
*****************************************************************************/
double ThisObjectIs(char *Name)
{
    IPObjectStruct *PObj;

    PObj = GetObject(Name);

    return (double) (PObj == NULL ? IP_OBJ_UNDEF : PObj -> ObjType);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Verifies the consistency of the global variable list.                    M
*                                                                            *
* PARAMETERS:                                                                M
*   None                                                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   IPIsFreeObject                                                           M
*                                                                            *
* KEYWORDS:                                                                  M
*   VerifyGlobalObjectList                                                   M
*****************************************************************************/
void VerifyGlobalObjectList(void)
{
    IPObjectStruct *p;

    IPIsConsistentFreeObjList();

    for (p = GlblObjList; p != NULL; p = p -> Pnext)
        if (IPIsFreeObject(p))
	    IritFatalError("A freed object was found on global object list.");
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* General printf routine, IRIT's style, to stdout.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   CtlStr:     Control string of this printf.                               M
*   PObjLst:    List of object to print.                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IritObjectPrintfStdout                                                   M
*****************************************************************************/
void IritObjectPrintfStdout(char *CtlStr, IPObjectStruct *PObjLst)
{
    char Buffer[LINE_LEN], Line[LINE_LEN_LONG];
    int i, j, k,
	CrntItem = 0,
	NumOfItems = ListObjectLength(PObjLst);
    IPObjectStruct *CrntObj;

    Line[0] = 0;

    for (i = 0; i < strlen(CtlStr); i++) {
	if (CtlStr[i] == '%') {
	    for (j = 0; j < 10 && !IS_PRINTF_CMD(CtlStr[i]); j++, i++)
		Buffer[j] = CtlStr[i];
	    Buffer[j++] = CtlStr[i];
	    Buffer[j--] = 0;

	    if (CrntItem >= NumOfItems) {
		WndwInputWindowPutStr("PRINTF: Not enough objects for printf.");
		return;
	    }
	    CrntObj = ListObjectGet(PObjLst, CrntItem++);

	    switch (Buffer[j]) {
		case 'c':
		    if (IP_IS_NUM_OBJ(CrntObj)) {
			sprintf(&Line[strlen(Line)], Buffer,
				(int) CrntObj -> U.R);
		    }
		    else {
			WndwInputWindowPutStr("PRINTF: Number expected.");
			return;
		    }
		    break;
		case 'd':
		case 'i':
		case 'u':
		case 'o':
		case 'x':
		case 'X':
		    if (IP_IS_NUM_OBJ(CrntObj)) {
			sprintf(&Line[strlen(Line)], Buffer,
				(int) CrntObj -> U.R);
		    }
		    else {
			WndwInputWindowPutStr("PRINTF: Number expected.");
			return;
		    }
		    break;
		case 'e':
		case 'f':
		case 'g':
		case 'E':
		case 'G':
		    if (IP_IS_NUM_OBJ(CrntObj)) {
			sprintf(&Line[strlen(Line)], Buffer,
				CrntObj -> U.R);
		    }
		    else {
			WndwInputWindowPutStr("PRINTF: Number expected.");
			return;
		    }
		    break;
		case 's':
		    if (IP_IS_STR_OBJ(CrntObj)) {
			sprintf(&Line[strlen(Line)], Buffer,
				CrntObj -> U.Str);
		    }
		    else {
			WndwInputWindowPutStr("PRINTF: String expected.");
			return;
		    }
		    break;
		case 'p':
		case 'v':
		    if (!IP_IS_VEC_OBJ(CrntObj) &&
			!IP_IS_POINT_OBJ(CrntObj)) {
			WndwInputWindowPutStr(
			    "PRINTF: Vector or Point expected.");
			return;
		    }
		    Buffer[j] = CtlStr[++i];
		    if (!IS_IRIT_FLOAT_PRINTF_CMD(Buffer[j])) {
			WndwInputWindowPutStr(
			    "PRINTF: Floaing point number command expected.");
			return;
		    }
		    for (k = 0; k < 3; k++) {
			sprintf(&Line[strlen(Line)],
				Buffer, CrntObj -> U.Vec[k]);
			if (k < 2)
			    strcat(Line, ", ");
		    }
		    break;
		case 'P':
		    if (!IP_IS_PLANE_OBJ(CrntObj)) {
			WndwInputWindowPutStr("PRINTF: Plane expected.");
			return;
		    }
		    Buffer[j] = CtlStr[++i];
		    if (!IS_IRIT_FLOAT_PRINTF_CMD(Buffer[j])) {
			WndwInputWindowPutStr(
			    "PRINTF: Floaing point number command expected.");
			return;
		    }
		    for (k = 0; k < 4; k++) {
			sprintf(&Line[strlen(Line)],
				Buffer, CrntObj -> U.Plane[k]);
			if (k < 3)
			    strcat(Line, ", ");
		    }
		    break;
		case 'D':
		    Buffer[j] = CtlStr[++i];
		    IritPrsrSetFloatFormat(Buffer);

		    if (strlen(Line) > 0) {
			WndwInputWindowPutStr(Line);
			Line[0] = 0;
		    }
		    PrintObject(CrntObj);
		    IritPrsrSetFloatFormat(GlblFloatFormat);
		    break;
		default:
		    WndwInputWindowPutStr(
			"PRINTF: Unknown % control to print command.");
		    return;
	    }
	}
	else if (CtlStr[i] == '\\') {
	    k = strlen(Line);

	    switch (CtlStr[++i]) {
		case 't':
		    Line[k] = '\t';
		    break;
		case 'n':
		    Line[k] = '\n';
		    break;
		case '%':
		    Line[k] = '%';
		    break;
	    }
	    Line[++k] = 0;

	}
	else {
	    k = strlen(Line);
	    Line[k++] = CtlStr[i];
	    Line[k] = 0;
	}
    }
    if (strlen(Line) > 0)
	WndwInputWindowPutStr(Line);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Gets the size of an object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Obj:      Object to query size of.                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   double:   Size of object Obj, coerced to double.                         M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetObjectSize                                                            M
*****************************************************************************/
double GetObjectSize(IPObjectStruct *Obj)
{
    if (IP_IS_POLY_OBJ(Obj)) {
	if (Obj -> U.Pl -> Pnext == NULL)
	    return (double) IritPrsrVrtxListLen(Obj -> U.Pl -> PVertex);
	else
	    return (double) IritPrsrPolyListLen(Obj -> U.Pl);
    }
    else if (IP_IS_CRV_OBJ(Obj)) {
	return (double) Obj -> U.Crvs -> Length;
    }
    else if (IP_IS_OLST_OBJ(Obj)) {
	return (double) ListObjectLength(Obj);
    }
    else if (IP_IS_STR_OBJ(Obj)) {
	return (double) strlen(Obj -> U.Str);
    }
    else {
	WndwInputWindowPutStr("Sizeof: cannot compute object size.");
        return 0.0;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Gets the size of a surface mesh.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Obj:    Curve/SurfaceTriavr to query its mesh size.                      M
*   RDir:   Direction to query size.                                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   double:    Size of mesh of Obj in direction RDir.                        M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetMeshSize                                                              M
*****************************************************************************/
double GetMeshSize(IPObjectStruct *Obj, RealType *RDir)
{
    int Dir = REAL_PTR_TO_INT(RDir);

    if (IP_IS_CRV_OBJ(Obj)) {
	return Obj -> U.Crvs -> Length;
    }
    else if (IP_IS_SRF_OBJ(Obj)) {
	switch (Dir)
	{
	    case CAGD_CONST_U_DIR:
	        return (double) Obj -> U.Srfs -> ULength;
	    case CAGD_CONST_V_DIR:
		return (double) Obj -> U.Srfs -> VLength;
	    default:
		WndwInputWindowPutStr("MeshSize: undefined direction.");
		return 0.0;
	}
    }
    else if (IP_IS_TRIVAR_OBJ(Obj)) {
	switch (Dir)
	{
	    case TRIV_CONST_U_DIR:
	        return (double) Obj -> U.Trivars -> ULength;
	    case TRIV_CONST_V_DIR:
		return (double) Obj -> U.Trivars -> VLength;
	    case TRIV_CONST_W_DIR:
		return (double) Obj -> U.Trivars -> WLength;
	    default:
		WndwInputWindowPutStr("MeshSize: undefined direction.");
		return 0.0;
	}
    }
    else if (IP_IS_TRISRF_OBJ(Obj)) {
	return Obj -> U.TriSrfs -> Length;
    }
    else {
	WndwInputWindowPutStr("MeshSize: cannot compute non surface object size.");
        return 0.0;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates an empty list.					     	     M
*                                                                            *
* PARAMETERS:                                                                M
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A  list object with emtpy list.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetNilList                                                               M
*****************************************************************************/
IPObjectStruct *GetNilList(void)
{
    IPObjectStruct
	*PObj = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

    ListObjectInsert(PObj, 0, NULL);

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Gets the nth object in a list.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   ListObj:   List object to query its n'th element.                        M
*   Rn:        The n'th element of ListObj is needed.                        M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  The n'th element of ListObj                           M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetNthList                                                               M
*****************************************************************************/
IPObjectStruct *GetNthList(IPObjectStruct *ListObj, RealType *Rn)
{
    int n = REAL_PTR_TO_INT(Rn);

    IPObjectStruct *PObj;

    if (!IP_IS_OLST_OBJ(ListObj)) {
	WndwInputWindowPutStr("None list object ignored.");
        return NULL;
    }

    if (n < 1 || n > ListObjectLength(ListObj)) {
	WndwInputWindowPutStr("Out of range of list.");
        return NULL;
    }

    PObj = CopyObject(NULL, ListObjectGet(ListObj, n - 1), FALSE);
    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Snoc (Cons to the end of the list, in place) the object to the list in     M
* the second argument.							     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:      To snoc to ListObj.                                           M
*   ListObj:   Where PObj is going to be added to, in place.                 M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   SnocList                                                                 M
*****************************************************************************/
void SnocList(IPObjectStruct *PObj, IPObjectStruct *ListObj)
{
    int i;

    if (!IP_IS_OLST_OBJ(ListObj)) {
	WndwInputWindowPutStr("None list object ignored.");
	return;
    }

    i = ListObjectLength(ListObj);
    ListObjectInsert(ListObj, i, CopyObject(NULL, PObj, FALSE));
    ListObjectInsert(ListObj, i + 1, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Gets an object by its name - scans the object linear list.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   ObjName:      Name of object to search for.                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Object if found, NULL otherwise.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetObject                                                                M
*****************************************************************************/
IPObjectStruct *GetObject(char *ObjName)
{
    return IPGetObjectByName(ObjName, GlblObjList, TRUE);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Extract a single entity out af an obj holding a set of entities at Index.  M
*   For VECTOR, POINT, CTLPT, PLANE, MAT a single numeric data is returned.  M
*   For a POLYGON a single vertex is returned (as VECTOR).		     M
*   For CURVE, and SURFACE a single control point is returned.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:      To query for one of its coordinates.                          M
*   RIndex:    Index of coordinate.                                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  An object holding the Index coordinate of PObj.       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetObjectCoord                                                           M
*****************************************************************************/
IPObjectStruct *GetObjectCoord(IPObjectStruct *PObj, RealType *RIndex)
{
    int Index = REAL_PTR_TO_INT(RIndex);
    IPObjectStruct
	*CoordPObj = NULL;
    CagdCtlPtStruct CtlPt;

    switch (PObj -> ObjType) {
	case IP_OBJ_POLY:
	    if (PObj -> U.Pl == NULL)
		break;
	    if (PObj -> U.Pl -> Pnext) {
		IPPolygonStruct *P;

		/* Extract a single poly from the poly list. */
		for (P = PObj -> U.Pl;
		     P != NULL && Index > 0;
		     P = P -> Pnext, Index--);
		if (P != NULL) {
		    IPPolygonStruct
		        *PTmp = IPAllocPolygon(P -> Tags,
					CopyVertexList(P -> PVertex), NULL);

		    CoordPObj = GenPolyObject("", PTmp, NULL);
		    PLANE_COPY(PTmp -> Plane, P -> Plane);
		    IP_RST_BBOX_POLY(PTmp);
		    CoordPObj -> Attrs = AttrCopyAttributes(PObj -> Attrs);

		    if (IP_IS_POLYGON_OBJ(PObj))
		        IP_SET_POLYGON_OBJ(CoordPObj);
		    else if (IP_IS_POLYLINE_OBJ(PObj))
		        IP_SET_POLYLINE_OBJ(CoordPObj);
		    else if (IP_IS_POINTLIST_OBJ(PObj))
		        IP_SET_POINTLIST_OBJ(CoordPObj);
		}
	    }
	    else {
		IPVertexStruct *V;

		/* Extract a vertex from the poly. */
		for (V = PObj -> U.Pl -> PVertex;
		     V != NULL && Index > 0;
		     V = V -> Pnext, Index--);
		if (V != NULL)
		    CoordPObj = GenVECObject(&V -> Coord[0],
					     &V -> Coord[1],
					     &V -> Coord[2]);
	    }
	    break;
	case IP_OBJ_POINT:
	    if (Index >= 0 && Index < 3)
		CoordPObj = GenNUMValObject(PObj -> U.Pt[Index]);
	    break;
	case IP_OBJ_VECTOR:
	    if (Index >= 0 && Index < 3)
		CoordPObj = GenNUMValObject(PObj -> U.Pt[Index]);
	    break;
	case IP_OBJ_PLANE:
	    if (Index >= 0 && Index < 4)
		CoordPObj = GenNUMValObject(PObj -> U.Pt[Index]);
	    break;
	case IP_OBJ_CTLPT:
	    if (!CAGD_IS_RATIONAL_PT(PObj -> U.CtlPt.PtType) && Index == 0)
		break;
	    if (Index >= 0 &&
		Index <= CAGD_NUM_OF_PT_COORD(PObj -> U.CtlPt.PtType))
		CoordPObj = GenNUMValObject(PObj -> U.CtlPt.Coords[Index]);
	    break;
	case IP_OBJ_MATRIX:
	    if (Index >= 0 && Index < 16)
		CoordPObj =
		    GenNUMValObject((*PObj -> U.Mat)[Index / 4][Index % 4]);
	    break;
	case IP_OBJ_INSTANCE:
	    if (Index >= 0 && Index < 16)
		CoordPObj =
		    GenNUMValObject((PObj -> U.Instance
				              -> Mat)[Index / 4][Index % 4]);
	    break;
	case IP_OBJ_STRING:
	    if (Index >= 0 && Index < strlen(PObj -> U.Str))
		CoordPObj = GenNUMValObject(PObj -> U.Str[Index]);
	    break;
	case IP_OBJ_LIST_OBJ:
	    CoordPObj = GetNthList(PObj, RIndex);
	    break;
	case IP_OBJ_CURVE:
	    if (PObj -> U.Crvs == NULL)
	        break;
	    if (PObj -> U.Crvs -> Pnext != NULL) {
		CagdCrvStruct *Crv;

		/* Extract a single curve from the curve list. */
		for (Crv = PObj -> U.Crvs;
		     Crv != NULL && Index > 0;
		     Crv = Crv -> Pnext, Index--);
		if (Crv != NULL)
		    CoordPObj = GenCRVObject(CagdCrvCopy(Crv));
	    }
	    else {
		/* Extract a ctlpt from the curve. */
		CagdEditSingleCrvPt(PObj -> U.Crvs, &CtlPt, Index, FALSE);
		CoordPObj = GenCTLPTObject(PObj -> U.Crvs -> PType,
					   CtlPt.Coords, NULL);
	    }
	    break;
	case IP_OBJ_SURFACE:
	    if (PObj -> U.Srfs == NULL)
	        break;
	    if (PObj -> U.Srfs -> Pnext != NULL) {
		CagdSrfStruct *Srf;

		/* Extract a single surface from the surface list. */
		for (Srf = PObj -> U.Srfs;
		     Srf != NULL && Index > 0;
		     Srf = Srf -> Pnext, Index--);
		if (Srf != NULL)
		    CoordPObj = GenSRFObject(CagdSrfCopy(Srf));
	    }
	    else {
		/* Extract a ctlpt from the surface. */
		CagdEditSingleSrfPt(PObj -> U.Srfs, &CtlPt,
				    Index % PObj -> U.Srfs -> ULength,
				    Index / PObj -> U.Srfs -> ULength,
				    FALSE);
		CoordPObj = GenCTLPTObject(PObj -> U.Srfs -> PType,
					   CtlPt.Coords, NULL);
	    }
	    break;
	default:
	    break;
    }

   if (CoordPObj == NULL)
       WndwInputWindowPutStr("Coord: Out of range or wrong object type.");

    return CoordPObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes a bounding box for the given object(s).                         M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:      Object(s) to compute bounding boxes for,                      M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A list of 6 numbers - the bbox as XMin/Max, YMin/Max M
*			ZMin/Max.					     M
*                                                                            *
* SEE ALSO:                                                                  M
*   BBComputeBboxObject                                                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   ComputeBBOXObject                                                        M
*****************************************************************************/
IPObjectStruct *ComputeBBOXObject(IPObjectStruct *PObj)
{
    BBBboxStruct
	*BBox = BBComputeBboxObject(PObj);
    IPObjectStruct
	*BObj = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

    ListObjectInsert(BObj, 0, GenNUMValObject(BBox -> Min[0]));
    ListObjectInsert(BObj, 1, GenNUMValObject(BBox -> Max[0]));
    ListObjectInsert(BObj, 2, GenNUMValObject(BBox -> Min[1]));
    ListObjectInsert(BObj, 3, GenNUMValObject(BBox -> Max[1]));
    ListObjectInsert(BObj, 4, GenNUMValObject(BBox -> Min[2]));
    ListObjectInsert(BObj, 5, GenNUMValObject(BBox -> Max[2]));
    ListObjectInsert(BObj, 6, NULL);

    return BObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Generates an instance object out of the given name.                      M
*                                                                            *
* PARAMETERS:                                                                M
*   InstanceName:    Name of object to instantiate.                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    Instance object.                                    M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenerateInstance                                                         M
*****************************************************************************/
IPObjectStruct *GenerateInstance(char *InstanceName)
{
    if (GetObject(InstanceName) != NULL) {
	int i;

	for (i = 0; i < strlen(InstanceName); i++)
	    if (islower(InstanceName[i]))
	        InstanceName[i] = toupper(InstanceName[i]);

	return GenINSTNCObject(InstanceName);
    }
    else {
	WndwInputWindowPutStr("INSTANCE: No object by this name to instantiate.");
	return NULL;
    }
}

