/*****************************************************************************
*   "Irit" - the 3d (not only polygonal) solid modeller.		     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
******************************************************************************
*   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 "freeform.h"
#include "windows.h"

#define IS_FLOAT_PRINTF_CMD(c)	((c) == 'e' || (c) == 'f' || (c) == 'g' || \
				 (c) == 'E' || (c) == 'F')
#define IS_PRINTF_CMD(c)  (IS_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)
    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
* 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 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, 0, NULL, NULL);
    Pl -> PVertex = V = IPAllocVertex(0, 0, NULL, NULL);
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, 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, 0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 1.0;    V -> Coord[1] = 0.1;   V -> Coord[2] = 0.1;

    Pl -> Pnext = IPAllocPolygon(0, 0, NULL, NULL); Pl = Pl -> Pnext;
    Pl -> PVertex = V = IPAllocVertex(0, 0, NULL, NULL);
    V -> Coord[0] = 1.0;    V -> Coord[1] = 0.1;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 1.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.1;

    /* Y axis.*/
    Pl -> Pnext = IPAllocPolygon(0, 0, NULL, NULL); Pl = Pl -> Pnext;
    Pl -> PVertex = V = IPAllocVertex(0, 0, NULL, NULL);
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, 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, 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, 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, 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, 0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] =(-0.04); V -> Coord[1] = 1.0;   V -> Coord[2] = 0.1;

    /* Z axis.*/
    Pl -> Pnext = IPAllocPolygon(0, 0, NULL, NULL); Pl = Pl -> Pnext;
    Pl -> PVertex = V = IPAllocVertex(0, 0, NULL, NULL);
    V -> Coord[0] = 0.0;    V -> Coord[1] = 0.0;   V -> Coord[2] = 0.0;
    V -> Pnext = IPAllocVertex(0, 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, 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, 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, 0, NULL, NULL); V = V -> Pnext;
    V -> Coord[0] = 0.1;    V -> Coord[1] = 0.1;   V -> Coord[2] = 1.0;

    return PlHead;
}

/*****************************************************************************
* 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)
{
    int i;
    IPObjectStruct *PObj;

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

    PObj = GetObject(Name);

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

/*****************************************************************************
* 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)
{
    IritObjectPrintf(stdout, CtlStr, PObjLst);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* General printf routine, IRIT's style.				     	     M
*                                                                            *
* PARAMETERS:                                                                M
*   File:       File descriptor of where this all goes.                      M
*   CtlStr:     Control string of this printf.                               M
*   PObjLst:    List of object to print.                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IritObjectPrintf                                                         M
*****************************************************************************/
void IritObjectPrintf(FILE *File, 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_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_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 {
	WndwInputWindowPutStr("Sizeof: cannot compute object size.");
        return 0.0;
    }
}

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

    if (IP_IS_SRF_OBJ(SrfObj)) {
	return (double) (Dir ? SrfObj -> U.Srfs -> ULength
			     : SrfObj -> U.Srfs -> VLength);
    }
    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
* Appends two lists.                                                         M
*                                                                            *
* PARAMETERS:                                                                M
*   ListObj1, ListObj2:  The two list objects to append.                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A combined list.                                    M
*                                                                            *
* KEYWORDS:                                                                  M
*   AppendLists                                                              M
*****************************************************************************/
IPObjectStruct *AppendLists(IPObjectStruct *ListObj1, IPObjectStruct *ListObj2)
{
    int i, j;
    IPObjectStruct *PObj, *PObjTmp;

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

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

    for (i = 0; (PObjTmp = ListObjectGet(ListObj1, i)) != NULL; i++) {
	ListObjectInsert(PObj, i, PObjTmp);
	PObjTmp -> Count++;
    }

    for (j = 0; (PObjTmp = ListObjectGet(ListObj2, j)) != NULL; i++, j++) {
	ListObjectInsert(PObj, i, PObjTmp);
	PObjTmp -> Count++;
    }

    ListObjectInsert(PObj, i, NULL);

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Reverses a list.                                                           M
*                                                                            *
* PARAMETERS:                                                                M
*   ListObj:    List object to reverses its entries.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Reversed list object.                                M
*                                                                            *
* KEYWORDS:                                                                  M
*   ReverseListObj                                                           M
*****************************************************************************/
IPObjectStruct *ReverseListObj(IPObjectStruct *ListObj)
{
    int i, j;
    IPObjectStruct *PObj, *PObjTmp;

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

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

    for (i = ListObjectLength(ListObj) - 1, j = 0; i >= 0; i--) {
	PObjTmp = ListObjectGet(ListObj, i);
	ListObjectInsert(PObj, j++, PObjTmp);
	PObjTmp -> Count++;
    }

    ListObjectInsert(PObj, j, NULL);

    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;
    IPObjectStruct *PObjTmp;

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

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Gets an object by its name - scans the object linear list.		     M
*  The termination is also on 1000 objects (simple debugging aid in case     M
* the Object list became circular), and a fatal error is produced.	     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)
{
    int i = 0;
    IPObjectStruct
	*PObj = GlblObjList;

    while (PObj) {
	if (strcmp(PObj -> Name, ObjName) == 0) {
	    return PObj;
	}
	PObj = PObj -> Pnext;
	if (i++ >= 1000)
	    IritFatalError("GetObject: Global Object list too big (>1000)");
    }
    return NULL;
}

/*****************************************************************************
* 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(1, 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_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;
}
