/*****************************************************************************
*   Dynamic allocation module of "Irit" - the 3d polygonal solid modeller.   *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
*****************************************************************************/

#include <stdio.h>
#include <string.h>
#include "irit_sm.h"
#include "iritprsr.h"
#include "allocate.h"
#include "attribut.h"
#include "imalloc.h"

/* #define DEBUG1		    Print more messages in free/allocating. */

#define ALLOCATE_NUM	100	   /* Number of objects to allocate at once. */

typedef enum {
    ALLOC_OTHER,
    ALLOC_VERTEX,
    ALLOC_POLYGON,
    ALLOC_OBJECT
} AllocateStructType;

/* Used for fast reallocation of most common object types: */
static IPVertexStruct
    *VertexFreedList = NULL;
static IPPolygonStruct
    *PolygonFreedList = NULL;
static IPObjectStruct
    *ObjectFreedList = NULL;
static int ComputedAllocateNumObj,
    AllocateNumObj = ALLOCATE_NUM;

static void IPFreeObjectSlots(IPObjectStruct *PObj);
static void ListObjectRealloc(IPObjectStruct *PObj);
static void IPMallocObjectSlots(IPObjectStruct *PObj);

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to free the slots of a given object.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:    To be freed.                                                    *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void IPFreeObjectSlots(IPObjectStruct *PObj)
{
    int Index;
    char Line[LINE_LEN];
    IPObjectStruct *PObjTmp;

    if (PObj == NULL)
	return;

    switch (PObj -> ObjType) {
	case IP_OBJ_UNDEF:
	    break;
	case IP_OBJ_POLY:		   /* Free the polygon list. */
	    IPFreePolygonList(PObj -> U.Pl);
	    break;
	case IP_OBJ_NUMERIC:
	case IP_OBJ_POINT:
	case IP_OBJ_VECTOR:
	case IP_OBJ_PLANE:
	case IP_OBJ_CTLPT:
	    break;
	case IP_OBJ_MATRIX:
	    IritFree((VoidPtr) PObj -> U.Mat);
	    break;
	case IP_OBJ_STRING:
	    IritFree((VoidPtr) PObj -> U.Str);
	    break;
	case IP_OBJ_LIST_OBJ: /* Need to dereference list elements. */
	    for (Index = 0;
		 (PObjTmp = ListObjectGet(PObj, Index)) != NULL;
		 Index++) {
		if (PObjTmp -> Count-- == 1)
		    IPFreeObject(PObjTmp);
	    }
	    IritFree((VoidPtr) PObj -> U.Lst.PObjList);
	    break;
	case IP_OBJ_CURVE:
	    CagdCrvFreeList(PObj -> U.Crvs);
	    break;
	case IP_OBJ_SURFACE:
	    CagdSrfFreeList(PObj -> U.Srfs);
	    break;
	case IP_OBJ_TRIMSRF:
	    TrimSrfFreeList(PObj -> U.TrimSrfs);
	    break;
	case IP_OBJ_TRIVAR:
	    TrivTVFreeList(PObj -> U.Trivars);
	    break;
	default:  	   /* Kill the program - something is WRONG! */
	    sprintf(Line,
		    "IPFree: Attempt to free undefined Object type %d",
						PObj -> ObjType);
	    IritPrsrFatalError(Line);
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates one Vertex Structure. 				             M
*                                                                            *
* PARAMETERS:                                                                M
*   Count:     Entry into new vertex structure.                              M
*   Tags:      Entry into new vertex structure.                              M
*   PAdj:      Entry into new vertex structure.                              M
*   Pnext:     Entry into new vertex structure.                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPVertexStruct *:  A new allocated vertex structure.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPAllocVertex, allocation                                                M
*****************************************************************************/
IPVertexStruct *IPAllocVertex(ByteType Count,
			      ByteType Tags,
			      IPPolygonStruct *PAdj,
			      IPVertexStruct *Pnext)
{
    IPVertexStruct *p;

    if (VertexFreedList != NULL) {
	p = VertexFreedList;
	VertexFreedList = VertexFreedList -> Pnext;
    }
    else {
	int i;
	IPVertexStruct *V;

	/* Allocate AllocateNumObj objects, returns first one as new   */
	/* and chain together the rest of them into the free list.     */
	if (!ComputedAllocateNumObj)
	    AllocateNumObj = getenv("IRIT_MALLOC") ? 1 : ALLOCATE_NUM;
	if ((V = (IPVertexStruct *) IritMalloc(sizeof(IPVertexStruct)
					       * AllocateNumObj)) != NULL) {
	    for (i = 1; i < AllocateNumObj - 1; i++)
		V[i].Pnext = &V[i + 1];
	    V[AllocateNumObj - 1].Pnext = NULL;
	    if (AllocateNumObj > 1)
		VertexFreedList = &V[1];
	}
	p = V;
    }

    ZAP_MEM(p, sizeof(IPVertexStruct));
    p -> Count = Count;
    p -> Tags = Tags;
    p -> PAdj = PAdj;
    p -> Pnext = Pnext;

    AttrResetAttributes(&p -> Attrs);		   /* Initialize attributes. */

    return p;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates one Polygon Structure.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Count:     Entry into new vertex structure.                              M
*   Tags:      Entry into new vertex structure.                              M
*   V:         Entry into new vertex structure.                              M
*   Pnext:     Entry into new vertex structure.                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPPolygonStruct *:  A new allocated polygon structure.                   M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPAllacPolygon, allocation                                               M
*****************************************************************************/
IPPolygonStruct *IPAllocPolygon(ByteType Count,
				ByteType Tags,
				IPVertexStruct *V,
				IPPolygonStruct *Pnext)
{
    IPPolygonStruct *p;

    if (PolygonFreedList != NULL) {
	p = PolygonFreedList;
	PolygonFreedList = PolygonFreedList -> Pnext;
    }
    else {
	int i;
	IPPolygonStruct *P;

	/* Allocate AllocateNumObj objects, returns first one as new   */
	/* and chain together the rest of them into the free list.     */
	if (!ComputedAllocateNumObj)
	    AllocateNumObj = getenv("IRIT_MALLOC") ? 1 : ALLOCATE_NUM;
	if ((P = (IPPolygonStruct *) IritMalloc(sizeof(IPPolygonStruct)
					        * AllocateNumObj)) != NULL) {
	    for (i = 1; i < AllocateNumObj - 1; i++)
		P[i].Pnext = &P[i + 1];
	    P[AllocateNumObj - 1].Pnext = NULL;
	    if (AllocateNumObj > 1)
		PolygonFreedList = &P[1];
	}
	p = P;
    }

    ZAP_MEM(p, sizeof(IPPolygonStruct));
    p -> Count = Count;
    p -> Tags = Tags;
    p -> PVertex = V;
    p -> Pnext = Pnext;

    AttrResetAttributes(&p -> Attrs);		   /* Initialize attributes. */

    return p;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates one Object Structure.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of newly allocated object.                                M
*   ObjType:  Object type of newly allocated object.                         M
*   Pnext:    Entry into new object structure.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A new allocated object structure.                    M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPAllocObject, allocation                                                M
*****************************************************************************/
IPObjectStruct *IPAllocObject(char *Name,
			      IPObjStructType ObjType,
			      IPObjectStruct *Pnext)
{
    IPObjectStruct *p;

    if (ObjectFreedList != NULL) {
	p = ObjectFreedList;
	ObjectFreedList = ObjectFreedList -> Pnext;
    }
    else {
	int i;
	IPObjectStruct *O;

	/* Allocate AllocateNumObj objects, returns first one as new   */
	/* and chain together the rest of them into the free list.     */
	if (!ComputedAllocateNumObj)
	    AllocateNumObj = getenv("IRIT_MALLOC") ? 1 : ALLOCATE_NUM;
	if ((O = (IPObjectStruct *) IritMalloc(sizeof(IPObjectStruct)
					       * AllocateNumObj)) != NULL) {
	    for (i = 1; i < AllocateNumObj - 1; i++)
		O[i].Pnext = &O[i + 1];
	    O[AllocateNumObj - 1].Pnext = NULL;
	    if (AllocateNumObj > 1)
		ObjectFreedList = &O[1];
	}
	p = O;
    }

    ZAP_MEM(p, sizeof(IPObjectStruct));
    strcpy(p -> Name, Name);
    p -> ObjType = ObjType;
    p -> Count = 1;
    p -> Pnext = Pnext;

    IPMallocObjectSlots(p);
    AttrResetAttributes(&p -> Attrs);		   /* Initialize attributes. */

    return p;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Frees one Vertex Structure.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   V:        To free.                                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPFreeVertex, allocation                                                 M
*****************************************************************************/
void IPFreeVertex(IPVertexStruct *V)
{
    if (V != NULL) {
	V ->Pnext = NULL;
	IPFreeVertexList(V);
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Frees one Polygon Structure.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   P:        To free.                                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPFreePolygon, allocation                                                M
*****************************************************************************/
void IPFreePolygon(IPPolygonStruct *P)
{
    if (P != NULL) {
	P -> Pnext = NULL;
	IPFreePolygonList(P);
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Frees one Object Structure.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   O:        To free.                                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPFreeObject, allocation                                                 M
*****************************************************************************/
void IPFreeObject(IPObjectStruct *O)
{
    if (O != NULL) {
	if (O -> Count > 1) {
	    /* Do not free object - just decrease its reference count. */
	    O -> Count--;
	}
	else {
	    AttrFreeAttributes(&O -> Attrs);
	    IPFreeObjectSlots(O);

	    /* Add it to global freed object list: */
	    O -> Pnext = ObjectFreedList;
	    ObjectFreedList = O;
	}
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Free a, possibly circular, list of Vertex structures.                      M
*                                                                            *
* PARAMETERS:                                                                M
*   VFirst:   To free.                                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPFreeVertexList, allocation                                             M
*****************************************************************************/
void IPFreeVertexList(IPVertexStruct *VFirst)
{
    if (VFirst != NULL) {
	IPVertexStruct *Vtemp,
	    *V = VFirst;

	/* Handle both circular or NULL terminated. */
	do {
	    Vtemp = V;
	    V = V -> Pnext;
	}
	while (V != NULL && V != VFirst);

	/* Now chain this new list to the global freed vertex list: */
	Vtemp -> Pnext = VertexFreedList;
	VertexFreedList = VFirst;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Free a list of Polygon structures.			                     M
*                                                                            *
* PARAMETERS:                                                                M
*   PFirst:   To free.                                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPFreePolygonList, allocation                                            M
*****************************************************************************/
void IPFreePolygonList(IPPolygonStruct *PFirst)
{
    if (PFirst != NULL) {
	IPPolygonStruct
	    *Ptemp = NULL,
	    *P = PFirst;

	while (P != NULL) {
	    IPFreeVertexList(P -> PVertex);

	    Ptemp = P;
	    P = P -> Pnext;
	}

	/* Now chain this new list to the global freed polygon list: */
	Ptemp -> Pnext = PolygonFreedList;
	PolygonFreedList = PFirst;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Free a list of Object structures.			                     M
*                                                                            *
* PARAMETERS:                                                                M
*   OFirst:   To free.                                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IPFreeObjectList, allocation                                             M
*****************************************************************************/
void IPFreeObjectList(IPObjectStruct *OFirst)
{
    while (OFirst != NULL) {
	IPObjectStruct
	    *NextO = OFirst -> Pnext;

	IPFreeObject(OFirst);
	OFirst = NextO;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Returns the length of a list, given a list of objects.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:      A list of objects to find its length.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:       Resulting length of list PObj.                                M
*                                                                            *
* KEYWORDS:                                                                  M
*   ListObjectLength, linked lists, length                                   M
*****************************************************************************/
int ListObjectLength(IPObjectStruct *PObj)
{
    int i;
    IPObjectStruct **PObjList;

    if (!IP_IS_OLST_OBJ(PObj))
	IritPrsrFatalError("List object expected");

    for (i = 0, PObjList = PObj -> U.Lst.PObjList; *PObjList++ != NULL; i++)
	if (i >= PObj -> U.Lst.ListMaxLen)
	    break;

    return i;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Returns TRUE if PObj is an object in list PObjList or in a sublist of      M
* PObjList, recursively.                                                     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObjList:  To search for PObj in.                                        M
*   PObj:      The element to search in PObjList.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:       TRUE if PObj was found in PObjList, FALSE otherwise.          M
*                                                                            *
* KEYWORDS:                                                                  M
*   ListObjectFind, linked lists, find                                       M
*****************************************************************************/
int ListObjectFind(IPObjectStruct *PObjList, IPObjectStruct *PObj)
{
    IPObjectStruct **PObjSubList;

    if (PObjList == PObj)
	return TRUE;

    if (!IP_IS_OLST_OBJ(PObjList))
	return FALSE;

    for (PObjSubList = PObjList -> U.Lst.PObjList;
	 *PObjSubList != NULL;
	 PObjSubList++)
	if (ListObjectFind(*PObjSubList, PObj))
	    return TRUE;

    return FALSE;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Insert an object PObjItem at index Index into a list of object,PObj.       M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:       A list of objects to insert PObjItem into.                   M
*   Index:      Index where PObjItem should enter PObj.                      M
*   PObjItem:   Eleent to insert into the list PObj.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   ListObjectInsert, lists, insert                                          M
*****************************************************************************/
void ListObjectInsert(IPObjectStruct *PObj,
		      int Index,
		      IPObjectStruct *PObjItem)
{
    if (!IP_IS_OLST_OBJ(PObj))
	IritPrsrFatalError("List object expected");

    if (PObj -> U.Lst.ListMaxLen <= Index)
	ListObjectRealloc(PObj);

    PObj -> U.Lst.PObjList[Index] = PObjItem;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Returns the object number Index in list of PObjList object.		     M
*                                                                            M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     A list object to extract one object from.                      M
*   Index:    Index of object to extractfrom PObj.                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  Index object in list PObj, or NULL if no such thing.  M
*                                                                            *
* KEYWORDS:                                                                  M
*   ListObjectGet, lists, find                                               M
*****************************************************************************/
IPObjectStruct *ListObjectGet(IPObjectStruct *PObj, int Index)
{
    if (!IP_IS_OLST_OBJ(PObj))
	IritPrsrFatalError("List object expected");

    return PObj -> U.Lst.ListMaxLen > Index ? PObj -> U.Lst.PObjList[Index]
					    : NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Reallocate a list Object to twice the previous list size		     *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:      A list object to reallocate.                                  *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void ListObjectRealloc(IPObjectStruct *PObj)
{
    IPObjectStruct
	**PObjList = IritMalloc(sizeof(IPObjectStruct *) *
				PObj -> U.Lst.ListMaxLen * 2);

    GEN_COPY(PObjList, PObj -> U.Lst.PObjList,
	     PObj -> U.Lst.ListMaxLen * sizeof(IPObjectStruct *));
    PObj -> U.Lst.ListMaxLen *= 2;
    IritFree((VoidPtr) PObj -> U.Lst.PObjList);
    PObj -> U.Lst.PObjList = PObjList;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to initialize the slots of a given object.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:     Allocated object to initialize.                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void IPMallocObjectSlots(IPObjectStruct *PObj)
{
    switch (PObj -> ObjType) {
	case IP_OBJ_MATRIX:
	    PObj -> U.Mat = (MatrixType *) IritMalloc(sizeof(MatrixType));
	    break;
	case IP_OBJ_STRING:
	    PObj -> U.Str = (char *) IritMalloc(LINE_LEN);
	    PObj -> U.Str[0] = 0;
	    break;
	case IP_OBJ_LIST_OBJ:
	    PObj -> U.Lst.PObjList = (IPObjectStruct **)
		IritMalloc(sizeof(IPObjectStruct *) * MAX_OBJ_LIST);
	    PObj -> U.Lst.PObjList[0] = NULL;
	    PObj -> U.Lst.ListMaxLen = MAX_OBJ_LIST;
	    break;
	default:
	    PObj -> U.VPtr = NULL;
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one polygonal object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of polygonal object.                                      M
*   Pl:       Polygon(s) to place in object.                                 M
*   Pnext:    Entry into the object structure.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created polygonal object.                    M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenPolyObject, allocation                                                M
*****************************************************************************/
IPObjectStruct *GenPolyObject(char *Name,
			      IPPolygonStruct *Pl,
			      IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_POLY, Pnext);
    IP_SET_POLYGON_OBJ(PObj);		   /* Default - not polyline object. */

    PObj -> U.Pl = Pl;			     /* Link the union part of it... */

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one polygonal object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Pl:       Polygon(s) to place in object.                                 M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created polygonal object.                    M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenPOLYObject, allocation                                                M
*****************************************************************************/
IPObjectStruct *GenPOLYObject(IPPolygonStruct *Pl)
{
    return GenPolyObject("", Pl, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one curve object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of polygonal object.                                      M
*   Crv:      Curves to place in object.                                     M
*   Pnext:    Entry into the object structure.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created curve object.                        M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenCrvObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenCrvObject(char *Name,
			     CagdCrvStruct *Crv,
			     IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_CURVE, Pnext);

    PObj -> U.Crvs = Crv;		     /* Link the union part of it... */

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one curve object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:      Curves to place in object.                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created curve object.                        M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenCRVObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenCRVObject(CagdCrvStruct *Crv)
{
    return GenCrvObject("", Crv, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one surface object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of polygonal object.                                      M
*   Srf:      Surfaces to place in object.                                   M
*   Pnext:    Entry into the object structure.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created surface object.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenSrfObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenSrfObject(char *Name,
			     CagdSrfStruct *Srf,
			     IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_SURFACE, Pnext);

    PObj -> U.Srfs = Srf;		     /* Link the union part of it... */

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one surface object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Srf:      Surfaces to place in object.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created surface object.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenSRFObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenSRFObject(CagdSrfStruct *Srf)
{
    return GenSrfObject("", Srf, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one surface object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of polygonal object.                                      M
*   TrimSrf:  Trimmed surfaces to place in object.                           M
*   Pnext:    Entry into the object structure.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created trimmed surface object.              M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenTrimSrfObject, allocation                                             M
*****************************************************************************/
IPObjectStruct *GenTrimSrfObject(char *Name,
				 TrimSrfStruct *TrimSrf,
				 IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_TRIMSRF, Pnext);

    PObj -> U.TrimSrfs = TrimSrf;	    /* Link the union part of it... */

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one surface object.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   TrimSrf:      Trimmed surfaces to place in object.                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created trimmed surface object.              M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenTRIMSRFObject, allocation                                             M
*****************************************************************************/
IPObjectStruct *GenTRIMSRFObject(TrimSrfStruct *TrimSrf)
{
    return GenTrimSrfObject("", TrimSrf, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one trivariate object.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of polygonal object.                                      M
*   Triv:     Trivariates to place in object.                                M
*   Pnext:    Entry into the object structure.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created trivariate object.                   M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenTrivarObject, allocation                                              M
*****************************************************************************/
IPObjectStruct *GenTrivarObject(char *Name,
				TrivTVStruct *Triv,
				IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_TRIVAR, Pnext);

    PObj -> U.Trivars = Triv;		     /* Link the union part of it... */

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one trivariate object.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Triv:      Trivariates to place in object.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created trivariate object.                   M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenTRIVARObject, allocation                                              M
*****************************************************************************/
IPObjectStruct *GenTRIVARObject(TrivTVStruct *Triv)
{
    return GenTrivarObject("", Triv, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one control point object.					     M
*   Only one of CagdCoords/Coords should be specified.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:        Name of polygonal object.                                   M
*   PtType:      Point type of created control point (E2, P3, etc.).         M
*   CagdCoords:  If specified,  used as coefficients of new control point.   M
*   Coords:      If specified,  used as coefficients of new control point.   M
*   Pnext:       Entry into the object structure.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:     A newly created control point object.              M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenCtlPtObject, allocation                                               M
*****************************************************************************/
IPObjectStruct *GenCtlPtObject(char *Name,
			       CagdPointType PtType,
			       CagdRType *CagdCoords,
			       RealType *Coords,
			       IPObjectStruct *Pnext)
{
    int i;
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_PT(PtType);
    IPObjectStruct *PObj;
    RealType *t;

    PObj = IPAllocObject(Name, IP_OBJ_CTLPT, Pnext);

    PObj -> U.CtlPt.PtType = PtType;
    t = PObj -> U.CtlPt.Coords;

    if (CagdCoords != NULL)
	for (i = IsNotRational; i <= CAGD_NUM_OF_PT_COORD(PtType); i++)
	    t[i] = CagdCoords[i];
    else
	for (i = IsNotRational; i <= CAGD_NUM_OF_PT_COORD(PtType); i++)
	    t[i] = Coords[i];

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one control point object.					     M
*   Only one of CagdCoords/Coords should be specified.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   PtType:      Point type of created control point (E2, P3, etc.).         M
*   CagdCoords:  If specified,  used as coefficients of new control point.   M
*   Coords:      If specified,  used as coefficients of new control point.   M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:     A newly created control point object.              M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenCTLPTObject, allocation                                               M
*****************************************************************************/
IPObjectStruct *GenCTLPTObject(CagdPointType PtType,
			       CagdRType *CagdCoords,
			       RealType *Coords)
{
    return GenCtlPtObject("", PtType, CagdCoords, Coords, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one numeric object.                                                M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of polygonal object.                                      M
*   R:        Numeric value to place in object.                              M
*   Pnext:    Entry into the object structure.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created numeric object.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenNumObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenNumObject(char *Name, RealType *R, IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_NUMERIC, Pnext);

    PObj -> U.R = *R;			     /* Link the union part of it... */

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one numeric object.                                                M
*                                                                            *
* PARAMETERS:                                                                M
*   R:        Numeric value to place in object.                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created numeric object.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenNUMObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenNUMObject(RealType *R)
{
    return GenNumObject("", R, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one numeric object.                                                M
*                                                                            *
* PARAMETERS:                                                                M
*   R:        Numeric value to place in object.                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created numeric object.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenNUMValObject, allocation                                              M
*****************************************************************************/
IPObjectStruct *GenNUMValObject(RealType R)
{
    return GenNumObject("", &R, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one point object.                                                  M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:           Name of polygonal object.                                M
*   Pt0, Pt1, Pt2:  Coefficients of point.                                   M
*   Pnext:          Entry into the object structure.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created point object.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenPtObject, allocation                                                  M
*****************************************************************************/
IPObjectStruct *GenPtObject(char *Name,
			    RealType *Pt0,
			    RealType *Pt1,
			    RealType *Pt2,
			    IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_POINT, Pnext);

    PObj -> U.Pt[0] = *Pt0;		     /* Link the union part of it... */
    PObj -> U.Pt[1] = *Pt1;
    PObj -> U.Pt[2] = *Pt2;

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one point object.                                                  M
*                                                                            *
* PARAMETERS:                                                                M
*   Pt0, Pt1, Pt2:  Coefficients of point.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created point object.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenPTObject, allocation                                                  M
*****************************************************************************/
IPObjectStruct *GenPTObject(RealType *Pt0, RealType *Pt1, RealType *Pt2)
{
    return GenPtObject("", Pt0, Pt1, Pt2, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one vector object.                                                 M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:              Name of polygonal object.                             M
*   Vec0, Vec1, Vec2:  Coefficients of vector.                               M
*   Pnext:             Entry into the object structure.                      M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created vector object.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenVecObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenVecObject(char *Name,
			     RealType *Vec0,
			     RealType *Vec1,
			     RealType *Vec2,
			     IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_VECTOR, Pnext);

    PObj -> U.Vec[0] = *Vec0;		     /* Link the union part of it... */
    PObj -> U.Vec[1] = *Vec1;
    PObj -> U.Vec[2] = *Vec2;

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one vector object.                                                 M
*                                                                            *
* PARAMETERS:                                                                M
*   Vec0, Vec1, Vec2:  Coefficients of vector.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created vector object.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenVECObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenVECObject(RealType *Vec0, RealType *Vec1, RealType *Vec2)
{
    return GenVecObject("", Vec0, Vec1, Vec2, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one string object.                                                 M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:              Name of string object.                                M
*   Str:	The string.                                                  M
*   Pnext:             Entry into the object structure.                      M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created strtor object.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenStrObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenStrObject(char *Name, char *Str, IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_STRING, Pnext);

    PObj -> U.Str = strdup(Str);	     /* Link the union part of it... */

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one string object.                                                 M
*                                                                            *
* PARAMETERS:                                                                M
*   Str:	The string.                                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created strtor object.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenSTRObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenSTRObject(char *Str)
{
    return GenStrObject("", Str, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one plane object.                                                  M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:                            Name of polygonal object.               M
*   Plane0, Plane1, Plane2, Plane3:  Coefficients of point.                  M
*   Pnext:                           Entry into the object structure.        M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created plane object.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenPlaneObject, allocation                                               M
*****************************************************************************/
IPObjectStruct *GenPlaneObject(char *Name,
			       RealType *Plane0,
			       RealType *Plane1,
			       RealType *Plane2,
			       RealType *Plane3,
			       IPObjectStruct *Pnext)
{
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_PLANE, Pnext);

    PObj -> U.Plane[0] = *Plane0;	    /* Link the union part of it... */
    PObj -> U.Plane[1] = *Plane1;
    PObj -> U.Plane[2] = *Plane2;
    PObj -> U.Plane[3] = *Plane3;

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one plane object.                                                  M
*                                                                            *
* PARAMETERS:                                                                M
*   Plane0, Plane1, Plane2, Plane3:  Coefficients of point.                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A newly created plane object.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenPLANEObject, allocation                                               M
*****************************************************************************/
IPObjectStruct *GenPLANEObject(RealType *Plane0,
			       RealType *Plane1,
			       RealType *Plane2,
			       RealType *Plane3)
{
    return GenPlaneObject("", Plane0, Plane1, Plane2, Plane3, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one matrix object.                                                 M
*                                                                            *
* PARAMETERS:                                                                M
*   Name:     Name of polygonal object.    	                             M
*   Mat:      Matrix to initialize with.				     M
*   Pnext:    Entry into the object structure.                    	     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created matrix object.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenMatObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenMatObject(char *Name, MatrixType Mat, IPObjectStruct *Pnext)
{
    int i, j;
    IPObjectStruct *PObj;

    PObj = IPAllocObject(Name, IP_OBJ_MATRIX, Pnext);

    for (i = 0; i < 4; i++)		     /* Link the union part of it... */
	for (j = 0; j < 4; j++)
	    (*PObj -> U.Mat)[i][j] = Mat[i][j];

    return PObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Creates one matrix object.                                                 M
*                                                                            *
* PARAMETERS:                                                                M
*   Mat:      Matrix to initialize with.				     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A newly created matrix object.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenMATObject, allocation                                                 M
*****************************************************************************/
IPObjectStruct *GenMATObject(MatrixType Mat)
{
    return GenMatObject("", Mat, NULL);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to reallocate as necessary and object to a new object type.        M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:       Object to reallocated as a new object of type ObjType.       M
*   ObjType:    New type for object PObj.                                    M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   ReallocNewTypeObject, allocation                                         M
*****************************************************************************/
void ReallocNewTypeObject(IPObjectStruct *PObj, IPObjStructType ObjType)
{
    if (PObj -> ObjType == ObjType)
        return;
    IPFreeObjectSlots(PObj);
    PObj -> ObjType = ObjType;
    IPMallocObjectSlots(PObj);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to create a whole new copy of an object Src into Dest.	     M
*   If Dest is NULL, new object is allocated, otherwise Dest itself is       M
* updated to hold the new copy.                                              M
*   If CopyAll then all the record is copied, otherwise, only its invariant  M
* elements arebeen copied (i.e. no Name/Pnext copying).			     M
*                                                                            *
* PARAMETERS:                                                                M
*   Dest:      Destination object, possibly NULL.                            M
*   Src:       Source object.                                                M
*   CopyAll:   Do we want a complete identical copy?                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Duplicate of Src, same as Dest if Dest != NULL.      M
*                                                                            *
* KEYWORDS:                                                                  M
*   CopyObject, copy                                                         M
*****************************************************************************/
IPObjectStruct *CopyObject(IPObjectStruct *Dest,
			   IPObjectStruct *Src,
			   int CopyAll)
{
    int Index;
    char Line[LINE_LEN];
    IPObjectStruct *PObjTmp;

    if (Dest == Src)
	return Dest;			/* Called with same object - ignore. */
    else if (Dest == NULL)
	Dest = IPAllocObject("", Src -> ObjType, NULL);
    else {
	IPFreeObjectSlots(Dest);
	Dest -> ObjType = Src -> ObjType;
	IPMallocObjectSlots(Dest);
	AttrFreeAttributes(&Dest -> Attrs);
    }

    if (CopyAll) {
	strcpy(Dest -> Name, Src -> Name);
	Dest -> Pnext = Src -> Pnext;	 /* Maybe assigning NULL is better!? */
    }

    Dest -> Attrs = AttrCopyAttributes(Src -> Attrs);

    switch (Src -> ObjType) {
	case IP_OBJ_UNDEF:
	    break;
	case IP_OBJ_POLY:
	    Dest -> U.Pl = CopyPolygonList(Src -> U.Pl);
	    if (IP_IS_POLYGON_OBJ(Src))
	        IP_SET_POLYGON_OBJ(Dest);
	    else if (IP_IS_POLYLINE_OBJ(Src))
	        IP_SET_POLYLINE_OBJ(Dest);
	    else if (IP_IS_POINTLIST_OBJ(Src))
	        IP_SET_POINTLIST_OBJ(Dest);
	    break;
	case IP_OBJ_NUMERIC:
	    Dest -> U.R = Src -> U.R;
	    break;
	case IP_OBJ_POINT:
	    PT_COPY(Dest -> U.Pt, Src -> U.Pt);
	    break;
	case IP_OBJ_VECTOR:
	    PT_COPY(Dest -> U.Vec, Src -> U.Vec);
	    break;
	case IP_OBJ_PLANE:
	    PLANE_COPY(Dest -> U.Plane, Src -> U.Plane);
	    break;
	case IP_OBJ_CTLPT:
	    GEN_COPY(&Dest -> U.CtlPt, &Src -> U.CtlPt,
		     sizeof(CagdCtlPtStruct));
	    break;
	case IP_OBJ_MATRIX:
	    if (Dest -> U.Mat == NULL)
		Dest -> U.Mat = (MatrixType *) IritMalloc(sizeof(MatrixType));
	    MAT_COPY(*Dest -> U.Mat, *Src -> U.Mat);
	    break;
	case IP_OBJ_STRING:
	    if (Dest -> U.Str == NULL)
		Dest -> U.Str = (char *) IritMalloc(LINE_LEN);
	    strcpy(Dest -> U.Str, Src -> U.Str);
	    break;
	case IP_OBJ_LIST_OBJ:
	    if (Dest -> U.Lst.PObjList != NULL)
		IritFree((VoidPtr) Dest -> U.Lst.PObjList);
	    Dest -> U.Lst.PObjList = (IPObjectStruct **)
		IritMalloc(sizeof(IPObjectStruct *) * Src -> U.Lst.ListMaxLen);
	    Dest -> U.Lst.ListMaxLen = Src -> U.Lst.ListMaxLen;

	    GEN_COPY(Dest -> U.Lst.PObjList, Src -> U.Lst.PObjList,
		     Dest -> U.Lst.ListMaxLen * sizeof(IPObjectStruct *));
	    for (Index = 0;
		 (PObjTmp = ListObjectGet(Dest, Index)) != NULL;
		 Index++)
		PObjTmp -> Count++;			   /* Inc. # of ref. */
	    break;
	case IP_OBJ_CURVE:
	    Dest -> U.Crvs = CagdCrvCopyList(Src -> U.Crvs);
	    break;
	case IP_OBJ_SURFACE:
	    Dest -> U.Srfs = CagdSrfCopyList(Src -> U.Srfs);
	    break;
	case IP_OBJ_TRIMSRF:
	    Dest -> U.TrimSrfs = TrimSrfCopyList(Src -> U.TrimSrfs);
	    break;
	case IP_OBJ_TRIVAR:
	    Dest -> U.Trivars = TrivTVCopyList(Src -> U.Trivars);
	    break;
	default:
	    sprintf(Line,
		"CopyObject Attemp to copy undefined object %s type %d",
		Src -> Name, Src -> ObjType);
	    IritPrsrFatalError(Line);
    }
    return Dest;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to create a new copy of an object list.		     	     M
*                                                                            *
* PARAMETERS:                                                                M
*   Pobjs:     Source objects.                                               M
*   CopyAll:   Do we want a complete identical copy?                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    Duplicated list of PObjs.                           M
*                                                                            *
* KEYWORDS:                                                                  M
*   CopyObjectList, copy                                                     M
*****************************************************************************/
IPObjectStruct *CopyObjectList(IPObjectStruct *PObjs, int CopyAll)
{
    IPObjectStruct *PObj,
	*NewPObjs = NULL,
	*TailPObj =NULL;

    for (PObj = PObjs; PObj != NULL; PObj = PObj -> Pnext) {
	if (NewPObjs == NULL)
	    NewPObjs = TailPObj = CopyObject(NULL, PObj, CopyAll);
	else {
	    TailPObj -> Pnext = CopyObject(NULL, PObj, CopyAll);
	    TailPObj = TailPObj -> Pnext;
	}
    }

    return NewPObjs;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to create a new copy of an object polygon list.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Src:      A polygon list to copy.                                        M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPPolygonStruct *:   Duplicated list of polygons.                        M
*                                                                            *
* KEYWORDS:                                                                  M
*   CopyPolygonList, copy                                                    M
*****************************************************************************/
IPPolygonStruct *CopyPolygonList(IPPolygonStruct *Src)
{
    IPPolygonStruct *Phead, *Ptail;

    if (Src == NULL)
	return NULL;

    /* Prepare the header of the new polygon list: */
    Phead = Ptail = IPAllocPolygon(1, Src -> Tags,
				   CopyVertexList(Src -> PVertex), NULL);
    PLANE_COPY(Ptail -> Plane, Src -> Plane);
    Ptail -> Attrs = AttrCopyAttributes(Src -> Attrs);
    IP_RST_BBOX_POLY(Ptail);
    Src = Src -> Pnext;

    while (Src != NULL) {
	Ptail -> Pnext = IPAllocPolygon(Src -> Count, Src -> Tags,
					CopyVertexList(Src -> PVertex), NULL);
	Ptail = Ptail -> Pnext;
	PLANE_COPY(Ptail -> Plane, Src -> Plane);
	Ptail -> Attrs = AttrCopyAttributes(Src -> Attrs);
	IP_RST_BBOX_POLY(Ptail);
	Src = Src -> Pnext;
    }

    return Phead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to create  a new copy of a polygon vertices list.                  M
*                                                                            *
* PARAMETERS:                                                                M
*   Src:       A vertex list to copy.                                        M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPVertexStruct *:  Duplicated list of vertices.                          M
*                                                                            *
* KEYWORDS:                                                                  M
*   CopyVertexList, copy                                                     M
*****************************************************************************/
IPVertexStruct *CopyVertexList(IPVertexStruct *Src)
{
    IPVertexStruct *Phead, *Ptail,
	*SrcFirst = Src;

    if (Src == NULL)
	return NULL;

    /* Prepare the header of the new vertex list: */
    Phead = Ptail = IPAllocVertex(Src -> Count, Src -> Tags, NULL, NULL);
    PT_COPY(Phead -> Coord, Src -> Coord);
    PT_COPY(Phead -> Normal, Src -> Normal);
    Phead -> Attrs = AttrCopyAttributes(Src -> Attrs);
    Src = Src -> Pnext;

    while (Src != SrcFirst && Src != NULL) {
	Ptail -> Pnext = IPAllocVertex(Src -> Count, Src -> Tags, NULL, NULL);
	Ptail = Ptail -> Pnext;
	PT_COPY(Ptail -> Coord, Src -> Coord);
	PT_COPY(Ptail -> Normal, Src -> Normal);
	Ptail -> Attrs = AttrCopyAttributes(Src -> Attrs);

	Src = Src -> Pnext;
    }

    if (Src == SrcFirst)
	Ptail -> Pnext = Phead;		       /* Make vertex list circular. */

    return Phead;
}
