/*****************************************************************************
* Filter to convert AutoCad DXF data files to IRIT .irt files.		     *
*									     *
* Written by:  Gershon Elber				Ver 1.0, Apr 1992    *
*****************************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "irit_sm.h"
#include "iritprsr.h"
#include "allocate.h"
#include "attribut.h"
#include "getarg.h"
#include "genmat.h"

typedef enum {
    DXF_NONE,
    DXF_LINE,
    DXF_3DLINE,
    DXF_3DFACE,
    DXF_POLYLINE,
    DXF_SURFACE		 /* POLYLINE may be Bezier or Cubic Bspline surface. */
} DXFStructType;

#ifdef NO_CONCAT_STR
static char *VersionStr =
	"DXF2Irit		Version 5.0,		Gershon Elber,\n\
	 (C) Copyright 1989/90-95 Gershon Elber, Non commercial use only.";
#else
static char *VersionStr = "dxf2irit	" VERSION ",	Gershon Elber,	"
	__DATE__ ",   " __TIME__ "\n" COPYRIGHT ", Non commercial use only.";
#endif /* NO_CONCAT_STR */

static char
    *CtrlStr = "DXF2Irit m%- f%- z%- DXFFile!*s";

static int
    GlblFloatEndCondition = FALSE,
    GlblMoreFlag = FALSE;

static char *MakePrintable(char *Str);
static void DumpDataForIrit(FILE *f);
static IPPolygonStruct *Get3DLINE(FILE *f);
static IPPolygonStruct *Get3DFACE(FILE *f);
static int GetPOLYLINE(FILE *f,
		       DXFStructType *DXFPolyType,
		       IPPolygonStruct **PPoly,
		       CagdSrfStruct **PSrf);
static char *Real2Str(RealType R);
static void DumpOneObject(FILE *f, IPObjectStruct *PObject);

void Dxf2IritExit(int ExitCode);

/*****************************************************************************
* DESCRIPTION:                                                               M
* Main module of dat2irit - Read command line and do what is needed...	     M
*                                                                            *
* PARAMETERS:                                                                M
*   argc, argv:  Command line.                                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   main                                                                     M
*****************************************************************************/
void main(int argc, char **argv)
{
    int Error,
	VerFlag = FALSE,
	NumFiles = 0;
    char Line[LINE_LEN], *p,
	**FileNames = NULL;
    FILE *f;

    if ((Error = GAGetArgs(argc, argv, CtrlStr, &GlblMoreFlag,
			   &GlblFloatEndCondition,
			   &VerFlag, &NumFiles, &FileNames)) != 0) {
	GAPrintErrMsg(Error);
	GAPrintHowTo(CtrlStr);
	Dxf2IritExit(1);
    }

    if (VerFlag) {
	fprintf(stderr, "\n%s\n\n", VersionStr);
	GAPrintHowTo(CtrlStr);
	Dxf2IritExit(0);
    }

    if (!NumFiles) {
	fprintf(stderr, "No data file names were given, exit.\n");
	GAPrintHowTo(CtrlStr);
	Dxf2IritExit(1);
    }
    else if (NumFiles > 1) {
	fprintf(stderr, "Cannot handle more than one DXF file at a time, exit.\n");
	GAPrintHowTo(CtrlStr);
	Dxf2IritExit(1);
    }

    if (strcmp(FileNames[0], "-") == 0)
	f = stdin;
    else if ((f = fopen(FileNames[0], "r")) == NULL) {
	fprintf(stderr, "Cannot open DXF file \"%s\", exit.\n", FileNames[0]);
	Dxf2IritExit(1);
    }

    /* Skip the DXF file until "SECTION ENTITIES" is found. */
    while (!feof(f)) {   
	while ((p = fgets(Line, LINE_LEN - 1, f)) != NULL &&
	       strncmp(p, "SECTION", 7) != 0);
	if (strncmp(fgets(Line, LINE_LEN - 1, f), "  2", 3) == 0 &&
	    strncmp(fgets(Line, LINE_LEN - 1, f), "ENTITIES", 8) == 0)
	    break;
    }

    if (feof(f)) {
	fprintf(stderr, "Illegal DXF file \"%s\", exit.\n", FileNames[0]);
	Dxf2IritExit(1);
    }

    DumpDataForIrit(f);

    fclose(f);

    Dxf2IritExit(0);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Eliminates non printable characters from a string.                         *
*                                                                            *
* PARAMETERS:                                                                *
*   Str:         To eliminate  non printable characters from.                *
*                                                                            *
* RETURN VALUE:                                                              *
*   char *:      Same as Str butwith printable characters only.              *
*****************************************************************************/
static char *MakePrintable(char *Str)
{
    char
	*p = Str;

    while (*p)
	if (*p++ < ' ') {
	    *--p = 0;
	    break;
	}
    return Str;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps the data from DXF file f into stdout.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   f:        File where DXF input comes from.                               *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpDataForIrit(FILE *f)
{
    DXFStructType DXFPolyType,
	DXFType = DXF_NONE;
    char Line[LINE_LEN];
    CagdSrfStruct *PSrf;
    IPPolygonStruct *PPoly;
    IPObjectStruct
	*PObj = NULL;

    while (fgets(Line, LINE_LEN - 1, f) != NULL) {
	if (strncmp(Line, "LINE", 4) == 0) {
	    if (DXFType != DXF_NONE && DXFType != DXF_LINE) {
		DumpOneObject(stdout, PObj);
		IPFreeObject(PObj);
		PObj = NULL;
	    }
	    if (PObj == NULL) {
		DXFType = DXF_LINE;
		PObj = IPAllocObject("", IP_OBJ_POLY, NULL);
		IP_SET_POLYLINE_OBJ(PObj);
	    }
	    PPoly = Get3DLINE(f);   /* Same function as 3DLINE with Z == 0. */
	    PPoly -> Pnext = PObj -> U.Pl;
	    PObj -> U.Pl = PPoly;
	}
	else if (strncmp(Line, "3DLINE", 6) == 0) {
	    if (DXFType != DXF_NONE && DXFType != DXF_3DLINE) {
		DumpOneObject(stdout, PObj);
		IPFreeObject(PObj);
		PObj = NULL;
	    }
	    if (PObj == NULL) {
		DXFType = DXF_3DLINE;
		PObj = IPAllocObject("", IP_OBJ_POLY, NULL);
		IP_SET_POLYLINE_OBJ(PObj);
	    }
	    PPoly = Get3DLINE(f);
	    PPoly -> Pnext = PObj -> U.Pl;
	    PObj -> U.Pl = PPoly;
	}
	else if (strncmp(Line, "3DFACE", 6) == 0) {
	    if (DXFType != DXF_NONE && DXFType != DXF_3DFACE) {
		DumpOneObject(stdout, PObj);
		IPFreeObject(PObj);
		PObj = NULL;
	    }
	    if (PObj == NULL) {
	    	DXFType = DXF_3DFACE;
		PObj = IPAllocObject("", IP_OBJ_POLY, NULL);
		IP_SET_POLYGON_OBJ(PObj);
	    }
	    PPoly = Get3DFACE(f);
	    PPoly -> Pnext = PObj -> U.Pl;
	    PObj -> U.Pl = PPoly;
	}
	else if (strncmp(Line, "POLYLINE", 8) == 0) {
	    if (GetPOLYLINE(f, &DXFPolyType, &PPoly, &PSrf)) {/* A polyline. */
		if (DXFType != DXF_NONE && DXFType != DXF_POLYLINE) {
		    DumpOneObject(stdout, PObj);
		    IPFreeObject(PObj);
	    	    PObj = NULL;
		}
	        if (PObj == NULL) {
		    DXFType = DXF_POLYLINE;
		    PObj = IPAllocObject("", IP_OBJ_POLY, NULL);
		    IP_SET_POLYLINE_OBJ(PObj);
	        }

	        PPoly -> Pnext = PObj -> U.Pl;
	        PObj -> U.Pl = PPoly;
	    }
	    else {					       /* A surface. */
		if (DXFType != DXF_NONE && DXFType != DXF_SURFACE) {
		    DumpOneObject(stdout, PObj);
		    IPFreeObject(PObj);
	    	    PObj = NULL;
		}
	        if (PObj == NULL) {
		    DXFType = DXF_SURFACE;
		    PObj = IPAllocObject("", IP_OBJ_SURFACE, NULL);
	        }

	        PSrf -> Pnext = PObj -> U.Srfs;
	        PObj -> U.Srfs = PSrf;
	    }
	}
	else if (strncmp(Line, "  0", 3) == 0 ||
		 strncmp(Line, "  8", 3) == 0) {
	}
	else if (strncmp(Line, "ENDSEC", 6) == 0) {
	    break;
	}
	else {
	    if (GlblMoreFlag)
		fprintf(stderr, "Unsupported entity \"%s\" in file.\n",
			MakePrintable(Line));
	}
    }

    if (PObj != NULL) {
	DumpOneObject(stdout, PObj);
	IPFreeObject(PObj);
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Gets one 3DLINE entity out of DXF file f (3DLINE line read).		     *
*                                                                            *
* PARAMETERS:                                                                *
*   f:       File to read DXF from                                           *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPPolygonStruct *:    An IRIT polyline representing the 3DLINE.          *
*****************************************************************************/
static IPPolygonStruct *Get3DLINE(FILE *f)
{
    int i,
	Count = 0;
    char Line[LINE_LEN];
    PointType Pts[2];
    IPVertexStruct *V1, *V2;
    IPPolygonStruct *P;

    Pts[0][2] = Pts[1][2] = 0.0;	     /* For getting a two dim. line. */

    while (fgets(Line, LINE_LEN - 1, f) != NULL && Count < 6) {
	/* Search for one of 10/20/30 and 11/21/31: */
	if (Line[0] == ' ' &&
	    Line[1] >= '1' && Line[1] <= '3' &&
	    Line[2] >= '0' && Line[2] <= '1') {
	    int PtIndex = Line[2] - '0',
		CoordIndex = Line[1] - '1';

	    sscanf(fgets(Line, LINE_LEN - 1, f),
#ifdef DOUBLE
		   "%lf",
#else
		   "%f",
#endif /* DOUBLE */
		   &Pts[PtIndex][CoordIndex]);
	    Count++;
	}
	else
	    fgets(Line, LINE_LEN - 1, f);     /* Skip the data that follows. */
    }

    V2 = IPAllocVertex(0, 0, NULL, NULL);
    V1 = IPAllocVertex(0, 0, NULL, V2);
    P = IPAllocPolygon(0, 0, V1, NULL);

    for (i = 0; i < 3; i++) {
	V1 -> Coord[i] = Pts[0][i];
	V2 -> Coord[i] = Pts[1][i];
    }

    return P;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Gets one 3DFACE entity out of DXF file f (3DFACE line read).		     *
*                                                                            *
* PARAMETERS:                                                                *
*   f:       File to read DXF from                                           *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPPolygonStruct *:    An IRIT poly representing the 3DFACE.              *
*****************************************************************************/
static IPPolygonStruct *Get3DFACE(FILE *f)
{
    int i,
    	HiddenEdges = 0,
	Count = 0;
    char Line[LINE_LEN];
    PointType Pts[4];
    IPVertexStruct *V1, *V2, *V3, *V4;
    IPPolygonStruct *P;

    while (fgets(Line, LINE_LEN - 1, f) != NULL && Count < 12) {
	/* Search for one of 10/20/30 and 11/21/31: */
	if (Line[0] == ' ' &&
	    Line[1] >= '1' && Line[1] <= '3' &&
	    Line[2] >= '0' && Line[2] <= '3') {
	    int PtIndex = Line[2] - '0',
		CoordIndex = Line[1] - '1';

	    sscanf(fgets(Line, LINE_LEN - 1, f),
#ifdef DOUBLE
		   "%lf",
#else
		   "%f",
#endif /* DOUBLE */
		   &Pts[PtIndex][CoordIndex]);
	    Count++;
	}
	else if (strncmp(" 70", Line, 3) == 0) {
	    sscanf(fgets(Line, LINE_LEN - 1, f), "%d", &HiddenEdges);
	}
	else
	    fgets(Line, LINE_LEN - 1, f);      /* Skip the data the follows. */
    }

    V3 = IPAllocVertex(0, 0, NULL, NULL);
    V2 = IPAllocVertex(0, 0, NULL, V3);
    V1 = IPAllocVertex(0, 0, NULL, V2);
    P = IPAllocPolygon(0, 0, V1, NULL);

    if (PT_APX_EQ(Pts[2], Pts[3])) {
    	V4 = NULL;
    }
    else {
	V4 = IPAllocVertex(0, 0, NULL, NULL);
	V3 -> Pnext = V4;
    }

    /* Set hidden attributes. */
    if (HiddenEdges & 0x01)
	IP_SET_INTERNAL_VRTX(V1);
    if (HiddenEdges & 0x02)
	IP_SET_INTERNAL_VRTX(V2);
    if (HiddenEdges & 0x04)
	IP_SET_INTERNAL_VRTX(V3);
    if (V4 != NULL && HiddenEdges & 0x08)
	IP_SET_INTERNAL_VRTX(V4);

    P = IPAllocPolygon(0, 0, V1, NULL);

    /* From my little experience with DXF files it looks like the order of   */
    /* the vertices is consistent. To get normals to point inside as IRIT    */
    /* needs, we switch the order. Hopefully this is really consistent.      */
    for (i = 0; i < 3; i++) {
	V1 -> Coord[i] = Pts[0][i];
	V2 -> Coord[i] = Pts[1][i];
	V3 -> Coord[i] = Pts[2][i];
	if (V4 != NULL)			      /* We have 4 vertices polygon. */
	    V4 -> Coord[i] = Pts[3][i];
    }

    return P;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Gets one POLYLINE entity out of DXF file f (POLYLINEline read). 	     *
*   The entity can also be a surface mesh, so it is supported as well.       *
*    Returns TRUE if polyline, FALSE if a surface.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		   File to read DXF from.                                    *
*   DXFPolyType:   Poly Type.                                                *
*   PPoly:         Where to save the coordinates.                            *
*   PSrf:          Or if a surface, where to save the surface.               *
*                                                                            *
* RETURN VALUE:                                                              *
*   int:           TRUE if a polyline, FALSE if a surface.                   *
*****************************************************************************/
static int GetPOLYLINE(FILE *f,
		       DXFStructType *DXFPolyType,
		       IPPolygonStruct **PPoly,
		       CagdSrfStruct **PSrf)
{
    int PolyFlags = 0,
        NumVertices = 0,
	ULength = 0,
	VLength = 0,
	SurfaceType = 6, /* Cubic Bspline. */
	IsSurface = FALSE;
    char Line[LINE_LEN];
    IPVertexStruct *V,
	*VLast = NULL;
    IPPolygonStruct
	*P = IPAllocPolygon(0, 0, NULL, NULL);

    *DXFPolyType = DXF_POLYLINE;

    while (fgets(Line, LINE_LEN - 1, f) != NULL) {
    	if (strncmp(Line, " 70", 3) == 0) {
    	    if (fgets(Line, LINE_LEN - 1, f) != NULL &&
		sscanf(Line, "%d", &PolyFlags) == 1) {
		IsSurface = (PolyFlags & 16) != 0;
    	    }
    	    else
		fprintf(stderr, "Integer data expected, found \"%s\"\n",
			MakePrintable(Line));
    	}
    	else if (strncmp(Line, " 71", 3) == 0) {
	    if (fgets(Line, LINE_LEN - 1, f) == NULL ||
		sscanf(Line, "%d", &VLength) != 1) {
		fprintf(stderr, "Integer data expected, found \"%s\"\n",
			MakePrintable(Line));
	    }
    	}
    	else if (strncmp(Line, " 72", 3) == 0) {
	    if (fgets(Line, LINE_LEN - 1, f) == NULL ||
		sscanf(Line, "%d", &ULength) != 1) {
		fprintf(stderr, "Integer data expected, found \"%s\"\n",
			MakePrintable(Line));
	    }
    	}
    	else if (strncmp(Line, " 75", 3) == 0) {
	    if (fgets(Line, LINE_LEN - 1, f) == NULL ||
		sscanf(Line, "%d", &SurfaceType) != 1) {
		fprintf(stderr, "Integer data expected, found \"%s\"\n",
			MakePrintable(Line));
	    }
    	}
	else if ((strncmp(Line, "  0", 3) == 0 &&
		  strncmp(fgets(Line, LINE_LEN - 1, f), "VERTEX", 6) == 0) ||
		 strncmp(Line, "VERTEX", 6) == 0) {
	    int Count = 0;

	    NumVertices++;

	    V = IPAllocVertex(0, 0, NULL, NULL);
	    if (VLast == NULL) {
		VLast = P -> PVertex = V;
	    }
	    else {
		VLast -> Pnext = V;
		VLast = V;
	    }

	    while (fgets(Line, LINE_LEN - 1, f) != NULL && Count < 3) {
		/* Search for one of 10/20/30: */
		if (Line[0] == ' ' &&
		    Line[1] >= '1' && Line[1] <= '3' &&
		    Line[2] == '0') {
		    int Index = Line[1] - '1';

		    sscanf(fgets(Line, LINE_LEN - 1, f),
#ifdef DOUBLE
			   "%lf",
#else
			   "%f",
#endif /* DOUBLE */
			   &V -> Coord[Index]);
		    Count++;
		}
		else
		    fgets(Line, LINE_LEN - 1, f); /* Skip data that follows. */
	    }

	    /* Skip until the end of vertex is found. */
	    while (strncmp(Line, "  0", 3) != 0) {
		fgets(Line, LINE_LEN - 1, f);
		fgets(Line, LINE_LEN - 1, f);
	    }
	}
	else if (strncmp(Line, "SEQEND", 6) == 0)
	    break;
	else
	    fgets(Line, LINE_LEN - 1, f);     /* Skip the data that follows. */
    }

    if (IsSurface) {                 /* Convert the polyline into a surface. */
	int i;
    	CagdRType **Points;
	V = P -> PVertex;
	
    	if (NumVertices != ULength * VLength) {
	    fprintf(stderr, "Surface mesh of size %d expected, only %d found.\n",
	            ULength * VLength, NumVertices);
	    *PPoly = P;
	    return TRUE;		 /* Return it as a polyline instead. */
    	}

	switch (SurfaceType) {
	    case 5:
		*PSrf = BspSrfNew(ULength, VLength, 3, 3, CAGD_PT_E3_TYPE);
		if (GlblFloatEndCondition) {
		    BspKnotUniformFloat(ULength, 3, (*PSrf) -> UKnotVector);
		    BspKnotUniformFloat(VLength, 3, (*PSrf) -> VKnotVector);
		}
		else {
		    BspKnotUniformOpen(ULength, 3, (*PSrf) -> UKnotVector);
		    BspKnotUniformOpen(VLength, 3, (*PSrf) -> VKnotVector);
		}
		break;
	    default:
	    	fprintf(stderr,
		"Surface type of %d is no support, type 6 (cubic spline) selected.\n",
	    		SurfaceType);
	    case 6:
		*PSrf = BspSrfNew(ULength, VLength, 4, 4, CAGD_PT_E3_TYPE);
		if (GlblFloatEndCondition) {
		    BspKnotUniformFloat(ULength, 4, (*PSrf) -> UKnotVector);
		    BspKnotUniformFloat(VLength, 4, (*PSrf) -> VKnotVector);
		}
		else {
		    BspKnotUniformOpen(ULength, 4, (*PSrf) -> UKnotVector);
		    BspKnotUniformOpen(VLength, 4, (*PSrf) -> VKnotVector);
		}
		break;
	    case 8:
		*PSrf = BzrSrfNew(ULength, VLength, CAGD_PT_E3_TYPE);
		break;
	}

	/* Copy the vertices into the control mesh. */
	Points = (*PSrf) -> Points;
	for (i = 0; i < NumVertices; i++, V = V -> Pnext) {
	    Points[1][i] = V -> Coord[0];
	    Points[2][i] = V -> Coord[1];
	    Points[3][i] = V -> Coord[2];
	}

	IPFreePolygonList(P);
	return FALSE;
    }
    else {
	*PPoly = P;
	return TRUE;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Converts a real number into a string.					     *
*   The routine maintains 6 different buffers simultanuously so up to 6      *
* calls can be issued from same printf...				     *
*                                                                            *
* PARAMETERS:                                                                *
*   R:          To convert to a string.                                      *
*                                                                            *
* RETURN VALUE:                                                              *
*   char *:     A string representation for R.                               *
*****************************************************************************/
static char *Real2Str(RealType R)
{
    static int j, k,
	i = 0;
    static char Buffer[6][LINE_LEN_SHORT];

    if (ABS(R) < EPSILON)
	R = 0.0;			    /* Round off very small numbers. */

    sprintf(Buffer[i], "%-8.6g", R);

    for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++);
    if (k >= LINE_LEN) {
	fprintf(stderr, "Conversion of real number (%f) failed.\n", R);
	Dxf2IritExit(3);
    }

    for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--);
    if (strchr(Buffer[i], '.') != NULL)
	for (; Buffer[i][j] == '0' && j > k; j--);
    Buffer[i][j+1] = 0;

    j = i;
    i = (i + 1) % 6;
    return Buffer[j];
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one object PObject to files.                                         *
*                                                                            *
* PARAMETERS:                                                                *
*   f:            File to dump object to.                                    *
*   PObject:      Object to dump to file f.                                  *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpOneObject(FILE *f, IPObjectStruct *PObject)
{
    int i;
    char
	*ErrStr = NULL;
    IPPolygonStruct *PPolygon;
    IPVertexStruct *PVertex;
    IPAttributeStruct
	*Attr = AttrTraceAttributes(PObject -> Attrs, PObject -> Attrs);
    static char *Header[] = {
	"    Creator: by DXF2IRIT - Autocad DXF to IRIT filer.",
	"",
    	"    [OBJECT MATRICES",
    	"\t[OBJECT VIEW_MAT",
    	"\t    [MATRIX",
    	"\t\t1 0 0 0",
    	"\t\t0 1 0 0",
    	"\t\t0 0 1 0",
    	"\t\t0 0 0 1",
    	"\t    ]",
    	"\t]",
    	"    ]",
    	"",
    	NULL
    };

    for (i = 0; Header[i] != NULL; i++)
	fprintf(f, "%s\n", Header[i]);

    if (Attr) {
	fprintf(f, "    [OBJECT\n");

	while (Attr) {
	    fprintf(f, "\t%s\n", Attr2String(Attr));
	    Attr = AttrTraceAttributes(Attr, NULL);
	}
	fprintf(f, "    %s\n",
		strlen(PObject -> Name) > 0 ? PObject -> Name : "AUTOCAD");
    }
    else
	fprintf(f, "    [OBJECT %s\n",
		strlen(PObject -> Name) > 0 ? PObject -> Name : "AUTOCAD");

    switch (PObject -> ObjType) {
	case IP_OBJ_POLY:
	    for (PPolygon = PObject -> U.Pl;
		 PPolygon != NULL;
		 PPolygon = PPolygon -> Pnext) {
		if (PPolygon -> PVertex == NULL) {
		    fprintf(stderr, "Attempt to dump empty polygon.\n");
		    break;
		}
		for (PVertex = PPolygon -> PVertex -> Pnext, i = 1;
		     PVertex != PPolygon -> PVertex && PVertex != NULL;
		     PVertex = PVertex -> Pnext, i++);
		if (IP_IS_POLYLINE_OBJ(PObject))
		    fprintf(f, "\t[POLYLINE %d\n", i);
		else
		    fprintf(f, "\t[POLYGON %d\n", i);

		PVertex = PPolygon -> PVertex;
		do {		     /* Assume at least one edge in polygon! */
		    fprintf(f, "\t    [%s%s %s %s]\n",
			IP_IS_INTERNAL_VRTX(PVertex) ? "[INTERNAL] " : "",
			Real2Str(PVertex -> Coord[0]),
			Real2Str(PVertex -> Coord[1]),
			Real2Str(PVertex -> Coord[2]));

		    PVertex = PVertex -> Pnext;
		}
		while (PVertex != PPolygon -> PVertex && PVertex != NULL);
		fprintf(f, "\t]\n");	       /* Close the polygon. */
	    }
	    break;
	case IP_OBJ_CURVE:
	    CagdCrvWriteToFile3(PObject -> U.Crvs, f, 4, NULL, &ErrStr);
	    break;
	case IP_OBJ_SURFACE:
	    CagdSrfWriteToFile3(PObject -> U.Srfs, f, 4, NULL, &ErrStr);
	    break;
	default:
	    break;
    }

    fprintf(f, "    ]\n");				/* Close the object. */
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dxf2Irit Irit2Ray exit routine.					     *
*                                                                            *
* PARAMETERS:                                                                *
*   ExitCode:                                                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
void Dxf2IritExit(int ExitCode)
{
    exit(ExitCode);
}

#ifdef DEBUG

/*****************************************************************************
* DESCRIPTION:                                                               *
*    Dummy function to link at debugging time.                               *
*                                                                            *
* PARAMETERS:                                                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*                                                                            *
* KEYWORDS:                                                                  *
*****************************************************************************/
void DummyLinkCagdDebug(void)
{
    IritPrsrDbg();
}

#endif /* DEBUG */
