/*****************************************************************************
* Filter to convert IRIT data files to a AutoCad DXF file.		     *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Gershon Elber				Ver 1.0, Apr 1992    *
*****************************************************************************/

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

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

static char *CtrlStr =
#ifdef DOUBLE
    "irit2dxf s%-Scale!F t%-Translate!F!F!F i%- F%-PolyOpti|FineNess!d!F 4%- o%-OutName!s T%- z%- DFiles!*s";
#else
    "irit2dxf s%-Scale!f t%-Translate!f!f!f i%- F%-PolyOpti|FineNess!d!f 4%- o%-OutName!s T%- z%- DFiles!*s";
#endif /* DOUBLE */

static char
    *OutFileName = "irit2dxf.dxf";

static RealType
    GlblXYZScale = 1.0,
    GlblXTranslate = 0.0,
    GlblYTranslate = 0.0,
    GlblZTranslate = 0.0;

static MatrixType CrntViewMat;			/* This is the current view! */

static void DumpDataForDXF(char *FileName, IPObjectStruct *PObjects);
static int DumpOneObject(FILE *f, IPObjectStruct *PObject);
static int DumpOnePoly(FILE *f,
		       IPPolygonStruct *PPoly,
		       char *ObjName,
		       IPObjectStruct *PObj);
static int DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon, char *ObjName);
static int DumpOnePolyline(FILE *f, IPPolygonStruct *PPolyline, char *ObjName);
static RealType *MapPoint(RealType *Pt);
static void Irit2DxfExit(int ExitCode);

/*****************************************************************************
* DESCRIPTION:                                                               M
* Main module of irit2dxf - 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,
	PrintSizeFlag = FALSE,
	VerFlag = FALSE,
	OutFileFlag = FALSE,
	TranslateFlag = FALSE,
	FineNessFlag = FALSE,
	NumFiles = 0;
    char
	**FileNames = NULL;
    IPObjectStruct *PObjects;

    if ((Error = GAGetArgs(argc, argv, CtrlStr, &PrintSizeFlag,
			   &GlblXYZScale, &TranslateFlag,
			   &GlblXTranslate, &GlblYTranslate,
			   &GlblZTranslate, &FFCState.ShowInternal,
			   &FineNessFlag, &FFCState.OptimalPolygons,
			   &FFCState.FineNess, &FFCState.FourPerFlat,
			   &OutFileFlag, &OutFileName,
			   &FFCState.Talkative, &VerFlag, &NumFiles,
			   &FileNames)) != 0) {
	GAPrintErrMsg(Error);
	GAPrintHowTo(CtrlStr);
	Irit2DxfExit(1);
    }

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

    if (!NumFiles) {
	fprintf(stderr, "No data file names were given, exit.\n");
	GAPrintHowTo(CtrlStr);
	Irit2DxfExit(1);
    }

    /* Get the data files: */
    IritPrsrSetFlattenObjects(TRUE);
    if ((PObjects = IritPrsrGetDataFiles(FileNames, NumFiles, TRUE, FALSE)) ==
									NULL)
	Irit2DxfExit(1);

    if (IritPrsrWasPrspMat)
        MatMultTwo4by4(CrntViewMat, IritPrsrViewMat, IritPrsrPrspMat);
    else
	GEN_COPY(CrntViewMat, IritPrsrViewMat, sizeof(MatrixType));

    DumpDataForDXF(OutFileFlag ? OutFileName : NULL, PObjects);

    Irit2DxfExit(0);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps the data for dxf into FileName (stdout in NULL).		     *
*                                                                            *
* PARAMETERS:                                                                *
*   FileName:   Where output should go to.                                   *
*   PObjects:   To dump into file.                                           *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpDataForDXF(char *FileName, IPObjectStruct *PObjects)
{
    int i,
	PolyCount = 0;
    FILE *f;
    static char *Header[] = {
	"999",
	"Creator: IRIT solid modeller using irit2dxf filter.",
	"  0",
	"SECTION",
	"  2",
	"ENTITIES",
	NULL
    };
    static char *Epilog[] = {
	"  0",
	"ENDSEC",
	"  0",
	"EOF",
	NULL
    };

    if (FileName != NULL) {
	if ((f = fopen(FileName, "w")) == NULL) {
	    fprintf(stderr, "Failed to open \"%s\".\n", FileName);
	    Irit2DxfExit(2);
	}
    }
    else
	f = stdout;

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

    while (PObjects) {
	IPObjectStruct *PObjNext;

	if (IP_IS_FFGEOM_OBJ(PObjects))
	    PObjects = ProcessFreeForm(PObjects, &FFCState);

	PolyCount += DumpOneObject(f, PObjects);

	PObjNext = PObjects -> Pnext;
	IPFreeObject(PObjects);
	PObjects = PObjNext;
    }

    if (PolyCount > 0)
	fprintf(stderr, "%d polygons were dumped.\n", PolyCount);

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

    fclose(f);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one object PObject to file f.                                        *
*                                                                            *
* PARAMETERS:                                                                *
*   f:            File to dump object to.                                    *
*   PObject:      Object to dump to file f.                                  *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static int DumpOneObject(FILE *f, IPObjectStruct *PObject)
{
    int PolyCount = 0;
    IPPolygonStruct *PList;

    switch (PObject -> ObjType) {
	case IP_OBJ_POLY:
	    PList = PObject -> U.Pl;
	    while (PList) {
		PolyCount += DumpOnePoly(f, PList,
					 PObject -> Name ? PObject -> Name
							 : "IRIT", PObject);
		PList =	PList -> Pnext;
	    }
	    break;
	case IP_OBJ_CURVE:
	case IP_OBJ_SURFACE:
	    break;
	default:
	    break;
    }

    return PolyCount;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one polygon/line, using global transform CrntViewMat.		     *
*   Polygon must be convex.                                                  *
*                                                                            *
*                                                                            *
* PARAMETERS:                                                                *
*   f:            File to dump object to.                                    *
*   PPoly:        Poly to dump to file f.                                    *
*   ObjName:      Name of object (FACE).                                     *
*   PObj:         Object PPoly came from to idetify a polygon from polyline. *
*                                                                            *
* RETURN VALUE:                                                              *
*   int:          Number of Polys.                                           *
*****************************************************************************/
static int DumpOnePoly(FILE *f,
		       IPPolygonStruct *PPoly,
		       char *ObjName,
		       IPObjectStruct *PObj)
{
    if (IP_IS_POLYGON_OBJ(PObj))
	return DumpOnePolygon(f, PPoly, ObjName);
    else if (IP_IS_POLYLINE_OBJ(PObj))
	return DumpOnePolyline(f, PPoly, ObjName);
    else
	return 0;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one polygon, using global Matrix transform CrntViewMat.		     *
*                                                                            *
* PARAMETERS:                                                                *
*   Fl:           File to dump polygon to.  		                     *
*   PPolygon:     Polygon to dump to file f.                                 *
*   ObjName:      Name of object.                                            *
*                                                                            *
* RETURN VALUE:                                                              *
*   int:          Number of triangles.                                       *
*****************************************************************************/
static int DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon, char *ObjName)
{
    int i, j,
	PolyCount = 0;
    RealType *MappedPoint[4];
    IPVertexStruct *VFirst, *V1, *V2, *V3,
	*VList = PPolygon -> PVertex;

    if (VList == NULL)
	return 0;

    if (!IritPrsrIsConvexPolygon(PPolygon)) {
	static int Printed = FALSE;

	if (!Printed) {
	    fprintf(stderr,
		    "\nWARNING: Non convex polygon(s) might be in data (see CONVEX in IRIT),\n\t\t\t\toutput can be wrong as the result!\n");
	    Printed = TRUE;
	}
    }

    VFirst = VList;
    V1 = VFirst -> Pnext;
    V2 = V1 -> Pnext;
    V3 = V2 -> Pnext;

    while (V2 != NULL) {
	MappedPoint[0] = MapPoint(VFirst -> Coord);
	MappedPoint[1] = MapPoint(V1 -> Coord);
	MappedPoint[2] = MapPoint(V2 -> Coord);
	if (V3 != NULL)
	    MappedPoint[3] = MapPoint(V3 -> Coord);
	else
	    MappedPoint[3] = MapPoint(V2 -> Coord); /* Duplicate fourth pt. */

	if (!PT_APX_EQ(MappedPoint[0], MappedPoint[1]) &&
	    !PT_APX_EQ(MappedPoint[0], MappedPoint[2]) &&
	    !PT_APX_EQ(MappedPoint[1], MappedPoint[2])) {
	    int HiddenEdges = (IP_IS_INTERNAL_VRTX(V1) ? 2 : 0) +
			      (IP_IS_INTERNAL_VRTX(V2) ? 4 : 0);

	    /* The last edge that closes the poly is always hidden since    */
	    /* we artificially introduced it here, unless it is the same as */
	    /* the edge of the original polygon, if it is the last edge.    */
	    if (V3 != NULL &&
		(V3 -> Pnext != NULL || IP_IS_INTERNAL_VRTX(V3)))
		HiddenEdges |= 8;

	    /* The first edge is always hidden since we artificially	    */
	    /* introduced it here, unless it is first edge of orig poly.    */
	    if (V1 == VFirst -> Pnext)
	        HiddenEdges |= IP_IS_INTERNAL_VRTX(VFirst) ? 1 : 0;
	    else
		HiddenEdges |= 1;

	    PolyCount++;

	    fprintf(f, "  0\n3DFACE\n  8\n%s\n 70\n%d\n", ObjName, HiddenEdges);

	    for (i = 0; i < 4; i++)
		for (j = 0; j < 3; j++)
		    fprintf(f, " %1d%1d\n%-10.7f\n",
			    j + 1, i, MappedPoint[i][j]);
	}

	if (V3 == NULL) {
	    V1 = V2;
	    V2 = V2 -> Pnext;
	}
	else {
	    V1 = V3;
	    V2 = V3 -> Pnext;
	    if (V2 != NULL)
		V3 = V2 -> Pnext;
	    else
	        V3 = NULL;
	}
    }

    return PolyCount;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one polyline, using global Matrix transform CrntViewMat.	     *
*                                                                            *
* PARAMETERS:                                                                *
*   Fl:           File to dump polyline to.  		                     *
*   PPolyline:    Polyline to dump to file f.                                *
*   ObjName:      Name of object.                                            *
*                                                                            *
* RETURN VALUE:                                                              *
*   int:          Number of polylines.                                       *
*****************************************************************************/
static int DumpOnePolyline(FILE *f, IPPolygonStruct *PPolyline, char *ObjName)
{
    return 0;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Maps the given E3 point using the CrntViewMat.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Pt:        Point to map.                                                 *
*                                                                            *
* RETURN VALUE:                                                              *
*   RealType *:   Mapped point, in local static place (for up to 4 calls).   *
*****************************************************************************/
static RealType *MapPoint(RealType *Pt)
{
    static int
	Count = 0;
    static RealType MappedPts[4][3];
    RealType *MappedPt = MappedPts[Count++];

    if (Count >= 4)
	Count = 0;

    MatMultVecby4by4(MappedPt, Pt, CrntViewMat);

    MappedPt[0] = MappedPt[0] * GlblXYZScale + GlblXTranslate;
    MappedPt[1] = MappedPt[1] * GlblXYZScale + GlblYTranslate;
    MappedPt[2] = MappedPt[2] * GlblXYZScale + GlblZTranslate;

    return MappedPt;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Irit2Dxf exit routine.						     *
*                                                                            *
* PARAMETERS:                                                                *
*   ExitCode:                                                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void Irit2DxfExit(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 */
