/*****************************************************************************
* Conversion routines from curvesand surfaces to polygons and polylines.     *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Gershon Elber				Ver 1.0, Apr 1992    *
*****************************************************************************/

#include "irit_sm.h"
#include "iritgrap.h"
#include "iritprsr.h"
#include "allocate.h"
#include "ffcnvrt.h"
#include "ip_cnvrt.h"

FreeformConvState FFCState = {
    FALSE,   /* Talkative */
    FALSE,   /* DumpObjsAsPolylines */
    TRUE,    /* DrawFFGeom */
    FALSE,   /* DrawFFMesh */
    { IG_DEFAULT_NUM_OF_ISOLINES,
	  IG_DEFAULT_NUM_OF_ISOLINES,
	      IG_DEFAULT_NUM_OF_ISOLINES },
    IG_DEFAULT_SAMPLES_PER_CURVE,
    0,       /* OptimalPolylines */
    FALSE,   /* ShowIntrnal */
    FALSE,   /* CubicCrvsAprox */
    IG_DEFAULT_POLYGON_FINENESS, /* FineNess */
    FALSE,   /* ComputeUV */
    FALSE,   /* FourPerFlat */
    0,       /* OptimalPolygons */
    FALSE,   /* BBoxGrid */
    TRUE     /* LinearOnePolyFlag */
};

/*****************************************************************************
* DESCRIPTION:                                                               M
* Convert a curve into a polyline with SamplesPerCurve samples. 	     M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:              A curve to piecewise linear approximate.               M
*   DrawCurve:        Do we want to draw the curve?                          M
*   DrawCtlPoly:      Do we want to draw its control polygon?                M
*   SamplesPerCurve:  Number of samples on curve.                            M
*   OptimalPolyline:  Do we want optimal yet expensive sampling?             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPPolygonStruct *:   Polyline(s) representing the curve and its          M
*                        control polygon.                                    M
* KEYWORDS:                                                                  M
*   Curve2Polylines                                                          M
*****************************************************************************/
IPPolygonStruct *Curve2Polylines(CagdCrvStruct *Crv,
				 int DrawCurve,
				 int DrawCtlPoly,
				 int SamplesPerCurve,
				 int OptimalPolyline)
{
    IPPolygonStruct *Poly,
	*PolyHead =
	    DrawCurve ? IritCurve2Polylines(Crv, SamplesPerCurve,
					    OptimalPolyline)
		      : NULL;

    if (DrawCtlPoly) {
	Poly = IritCurve2CtlPoly(Crv);
	Poly -> Pnext = PolyHead;
	PolyHead = Poly;
    }

    return PolyHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Converts a single surface into polylines with SamplesPerCurve samples,     M
* NumOfIsolines isolines into a polyline object list.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   Srf:              A surface to piecewise linear approximate.             M
*   DrawSurface:      Do we want to draw the surface?                        M
*   DrawMesh:         Do we want to draw its control mesh?                   M
*   NumOfIsolines:    Number of isocurves in each parametric direction.      M
*   SamplesPerCurve:  Number of samples on curve.                            M
*   OptimalPolyline:  Do we want optimal yet expensive sampling?             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPPolygonStruct *:  Polyline(s) representing the surface and its         M
*                       control mesh.	                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   Surface2Polylines                                                        M
*****************************************************************************/
IPPolygonStruct *Surface2Polylines(CagdSrfStruct *Srf,
				   int DrawSurface,
				   int DrawMesh,
				   int NumOfIsolines[2],
				   int SamplesPerCurve,
				   int OptimalPolylines)
{
    IPPolygonStruct *Poly, *PolyTemp,
	*PolyHead = DrawSurface ?
	    IritSurface2Polylines(Srf, NumOfIsolines, SamplesPerCurve,
				  OptimalPolylines) :
	    NULL;

    if (DrawMesh) {
	Poly = PolyTemp = IritSurface2CtlMesh(Srf);
	if (PolyTemp) {
	    while (PolyTemp -> Pnext)
		PolyTemp = PolyTemp -> Pnext;
	    PolyTemp -> Pnext = PolyHead;
	    PolyHead = Poly;
	}
    }

    return PolyHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Converts a single trimmed surface into polylines with SamplesPerCurve      M
* samples, NumOfIsolines isolines into a polyline object list.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   TrimSrf:          A trimmed surface to piecewise linear approximate.     M
*   DrawSurface:      Do we want to draw the surface?                        M
*   DrawMesh:         Do we want to draw its control mesh?                   M
*   NumOfIsolines:    Number of isocurves in each parametric direction.      M
*   SamplesPerCurve:  Number of samples on curve.                            M
*   OptimalPolyline:  Do we want optimal yet expensive sampling?             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPPolygonStruct *:  Polyline(s) representing the trimmed surface and its M
*                       control mesh.	                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TSrf2Polylines                                                           M
*****************************************************************************/
IPPolygonStruct *TSrf2Polylines(TrimSrfStruct *TrimSrf,
				int DrawSurface,
				int DrawMesh,
				int NumOfIsolines[2],
				int SamplesPerCurve,
				int OptimalPolylines)
{
    IPPolygonStruct
	*PolyHead = DrawSurface ?
	    IritTrimSrf2Polylines(TrimSrf, NumOfIsolines, SamplesPerCurve,
				  OptimalPolylines, TRUE, TRUE) :
	    NULL;

    if (DrawMesh)
	PolyHead = IritPrsrAppendPolyLists(IritSurface2CtlMesh(TrimSrf -> Srf),
					   PolyHead);

    return PolyHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Converts a single trivariate function into polylines with SamplesPerCurve  M
* samples, NumOfIsolines isolines into a polyline object list.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Trivar:           A trivariate function to piecewise linear approximate. M
*   DrawTrivar:       Do we want to draw the trivariate?                     M
*   DrawMesh:         Do we want to draw its control mesh?                   M
*   NumOfIsolines:    Number of isocurves in each parametric direction.      M
*   SamplesPerCurve:  Number of samples on curve.                            M
*   OptimalPolyline:  Do we want optimal yet expensive sampling?             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPPolygonStruct *:  Polyline(s) representing the trivariate and its      M
*                       control mesh.	                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TV2Polylines                                                             M
*****************************************************************************/
IPPolygonStruct *TV2Polylines(TrivTVStruct *Trivar,
			      int DrawTrivar,
			      int DrawMesh,
			      int NumOfIsolines[3],
			      int SamplesPerCurve,
			      int OptimalPolylines)
{
    IPPolygonStruct
	*PolyHead = DrawTrivar ?
	    IritTrivar2Polylines(Trivar, NumOfIsolines, SamplesPerCurve,
				 OptimalPolylines) :
	    NULL;

    if (DrawMesh)
	PolyHead = IritPrsrAppendPolyLists(IritTrivar2CtlMesh(Trivar),
					   PolyHead);

    return PolyHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Converts a whole set of geometry to polylines.                             M
*                                                                            *
* PARAMETERS:                                                                M
*   FreeForms:  Crvs/Srfs/Trimmed Srfs/Trivariates read from a file by the   M
*               irit parser.					             M
*   Talkative:        Do we want some more information printed.		     M
*   DrawGeom:         Do we want to draw the geometry?                       M
*   DrawMesh:         Do we want to draw its control mesh?                   M
*   NumOfIsolines:    Number of isocurves in each parametric direction.      M
*   SamplesPerCurve:  Number of samples on curve.                            M
*   OptimalPolylines: Do we want optimal yet expensive sampling?             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Polyline(s) representing the trivariate and its      M
*                       control mesh.	                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   FreeForm2Polylines                                                       M
*****************************************************************************/
IPObjectStruct *FreeForm2Polylines(IritPrsrFreeFormStruct *FreeForms,
				   int Talkative,
				   int DrawGeom,
				   int DrawMesh,
				   int NumOfIsolines[3],
				   int SamplesPerCurve,
				   int OptimalPolylines)
{
    IPObjectStruct *PObj,
	*CrvObjs = FreeForms -> CrvObjs,
	*SrfObjs = FreeForms -> SrfObjs,
	*TrimSrfObjs = FreeForms -> TrimSrfObjs,
	*TrivarObjs = FreeForms -> TrivarObjs;
    CagdCrvStruct *Crv, *Crvs;
    CagdSrfStruct *Srf, *Srfs;
    TrimSrfStruct *TrimSrf, *TrimSrfs;
    TrivTVStruct *TV, *TVs;
    IPPolygonStruct *PPolygon;

    if (CrvObjs) {
	for (PObj = CrvObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing curve object \"%s\"\n",
			PObj -> Name);

	    Crvs = PObj -> U.Crvs;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYLINE_OBJ(PObj);
	    strcat(PObj -> Name, "Pl");
	    for (Crv = Crvs; Crv != NULL; Crv = Crv -> Pnext) {
		PPolygon = Curve2Polylines(Crv, DrawGeom, DrawMesh,
					   SamplesPerCurve, OptimalPolylines);

		PObj -> U.Pl = IritPrsrAppendPolyLists(PPolygon,
						       PObj -> U.Pl);
	    }
	    CagdCrvFreeList(Crvs);
	}
    }

    if (SrfObjs) {
	for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing surface object \"%s\"\n",
			PObj -> Name);
	    
	    Srfs = PObj -> U.Srfs;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYLINE_OBJ(PObj);
	    strcat(PObj -> Name, "Pl");
	    for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
		PPolygon = Surface2Polylines(Srf, DrawGeom, DrawMesh,
					     NumOfIsolines, SamplesPerCurve,
					     OptimalPolylines);

		PObj -> U.Pl = IritPrsrAppendPolyLists(PPolygon,
						       PObj -> U.Pl);
	    }
	    CagdSrfFreeList(Srfs);
	}
    }

    if (TrimSrfObjs) {
	for (PObj = TrimSrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing trimmed surface object \"%s\"\n",
			PObj -> Name);
		
	    TrimSrfs = PObj -> U.TrimSrfs;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYLINE_OBJ(PObj);
	    strcat(PObj -> Name, "Pl");
	    for (TrimSrf = TrimSrfs;
		 TrimSrf != NULL;
		 TrimSrf = TrimSrf -> Pnext) {
		PPolygon = TSrf2Polylines(TrimSrf, DrawGeom, DrawMesh,
					  NumOfIsolines, SamplesPerCurve,
					  OptimalPolylines);

		PObj -> U.Pl = IritPrsrAppendPolyLists(PPolygon,
						       PObj -> U.Pl);
	    }
	    TrimSrfFreeList(TrimSrfs);
	}
    }

    if (TrivarObjs) {
	for (PObj = TrivarObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing trivariate object \"%s\"\n",
			PObj -> Name);
		
	    TVs = PObj -> U.Trivars;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYLINE_OBJ(PObj);
	    strcat(PObj -> Name, "Pl");
	    for (TV = TVs; TV != NULL; TV = TV -> Pnext) {
		PPolygon = TV2Polylines(TV, DrawGeom, DrawMesh, NumOfIsolines,
					SamplesPerCurve, OptimalPolylines);

		PObj -> U.Pl = IritPrsrAppendPolyLists(PPolygon,
						       PObj -> U.Pl);
	    }
	    TrivTVFreeList(TVs);
	}
    }

    return IritPrsrConcatFreeForm(FreeForms);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Converts a whole set of geometry to cubic bezier curves.                   M
*                                                                            *
* PARAMETERS:                                                                M
*   FreeForms:  Crvs/Srfs/Trimmed Srfs/Trivariates read from a file by the   M
*               irit parser.					             M
*   Talkative:        Do we want some more information printed.		     M
*   DrawGeom:         Do we want to draw the geometry?                       M
*   DrawMesh:         Do we want to draw its control mesh?                   M
*   NumOfIsolines:    Number of isocurves in each parametric direction.      M
*   SamplesPerCurve:  Number of samples on curve.                            M
*   OptimalPolylines: Do we want optimal yet expensive sampling?             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Polyline(s) representing the trivariate and its      M
*                       control mesh.	                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   FreeForm2CubicBzr                                                        M
*****************************************************************************/
IPObjectStruct *FreeForm2CubicBzr(IritPrsrFreeFormStruct *FreeForms,
				  int Talkative,
				  int DrawGeom,
				  int DrawMesh,
				  int NumOfIsolines[3],
				  int SamplesPerCurve,
				  int OptimalPolylines)
{
    IPObjectStruct *PObj,
	*CrvObjs = FreeForms -> CrvObjs,
	*SrfObjs = FreeForms -> SrfObjs,
	*TrimSrfObjs = FreeForms -> TrimSrfObjs,
	*TrivarObjs = FreeForms -> TrivarObjs;
    IPPolygonStruct *PPolygon;
    CagdCrvStruct *CubicBzrCrvs;

    /* Convert curves and surfaces into cubic polynomials (bezier). */
    if (CrvObjs) {
	for (PObj = CrvObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing curve object \"%s\"\n",
			PObj -> Name);

	    PPolygon = NULL;
	    CubicBzrCrvs = IritCurvesToCubicBzrCrvs(PObj -> U.Crvs, &PPolygon,
						    DrawGeom, DrawMesh,
						    INFINITY);

	    if (CubicBzrCrvs) {
		CagdCrvFreeList(PObj -> U.Crvs);
		PObj -> U.Crvs = CubicBzrCrvs;
		PObj -> ObjType = IP_OBJ_CURVE;
		strcat(PObj -> Name, "Cb");
	    }
	    else
		PObj -> ObjType = IP_OBJ_UNDEF;

	    if (PPolygon) {
		PObj -> Pnext = IPAllocObject("Mesh", IP_OBJ_POLY,
					      PObj -> Pnext);
		strcat(PObj -> Pnext -> Name, PObj -> Name);
		IP_SET_POLYLINE_OBJ(PObj -> Pnext);
		PObj = PObj -> Pnext;
		PObj -> U.Pl = PPolygon;
	    }
	}
    }

    if (SrfObjs) {
	for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing surface object \"%s\"\n",
			PObj -> Name);

	    PPolygon = NULL;
	    CubicBzrCrvs =
		IritSurfacesToCubicBzrCrvs(PObj -> U.Srfs, &PPolygon,
					   DrawGeom, DrawMesh, NumOfIsolines,
					   INFINITY);
	    if (CubicBzrCrvs) {
		CagdSrfFreeList(PObj -> U.Srfs);
		PObj -> U.Crvs = CubicBzrCrvs;
		PObj -> ObjType = IP_OBJ_CURVE;
		strcat(PObj -> Name, "Cb");
	    }
	    else
		PObj -> ObjType = IP_OBJ_UNDEF;

	    if (PPolygon) {
		PObj -> Pnext = IPAllocObject("", IP_OBJ_POLY, PObj -> Pnext);
		IP_SET_POLYLINE_OBJ(PObj -> Pnext);
		PObj = PObj -> Pnext;
		PObj -> U.Pl = PPolygon;
	    }
	}
    }

    if (TrimSrfObjs) {
	for (PObj = TrimSrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing trimmed surface object \"%s\"\n",
			PObj -> Name);

	    PPolygon = NULL;
	    CubicBzrCrvs =
		IritTrimSrfsToCubicBzrCrvs(PObj -> U.TrimSrfs, &PPolygon,
					   DrawGeom, DrawMesh, NumOfIsolines,
					   INFINITY);

	    /* Get the trimming curves as well. */
	    PObj -> Pnext = IPAllocObject("", IP_OBJ_POLY, PObj -> Pnext);
	    IP_SET_POLYLINE_OBJ(PObj -> Pnext);
	    PObj -> Pnext -> U.Pl = IritTrimSrf2Polylines(PObj -> U.TrimSrfs,
							  NumOfIsolines,
							  SamplesPerCurve,
							  OptimalPolylines,
							  TRUE, FALSE);

	    if (CubicBzrCrvs) {
		TrimSrfFreeList(PObj -> U.TrimSrfs);
		PObj -> U.Crvs = CubicBzrCrvs;
		PObj -> ObjType = IP_OBJ_CURVE;
		strcat(PObj -> Name, "Cb");
	    }
	    else
		PObj -> ObjType = IP_OBJ_UNDEF;

	    /* And finally the control mesh, if any. */
	    PObj = PObj -> Pnext;       /* Skip the trimming curves object. */
	    if (PPolygon) {
		PObj -> Pnext = IPAllocObject("Mesh", IP_OBJ_POLY,
					      PObj -> Pnext);
		strcat(PObj -> Pnext -> Name, PObj -> Name);
		IP_SET_POLYLINE_OBJ(PObj -> Pnext);
		PObj = PObj -> Pnext;
		PObj -> U.Pl = PPolygon;
	    }
	}
    }

    if (TrivarObjs) {
	for (PObj = TrivarObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    if (Talkative)
		fprintf(stderr, "Processing trivariate object \"%s\"\n",
			PObj -> Name);

	    PPolygon = NULL;
	    CubicBzrCrvs =
		IritTrivarToCubicBzrCrvs(PObj -> U.Trivars, &PPolygon,
					 DrawGeom, DrawMesh, NumOfIsolines,
					 INFINITY);
	    if (CubicBzrCrvs) {
		TrivTVFreeList(PObj -> U.Trivars);
		PObj -> U.Crvs = CubicBzrCrvs;
		PObj -> ObjType = IP_OBJ_CURVE;
		strcat(PObj -> Name, "Cb");
	    }
	    else
		PObj -> ObjType = IP_OBJ_UNDEF;

	    if (PPolygon) {
		PObj -> Pnext = IPAllocObject("Mesh", IP_OBJ_POLY,
					      PObj -> Pnext);
		strcat(PObj -> Pnext -> Name, PObj -> Name);
		IP_SET_POLYLINE_OBJ(PObj -> Pnext);
		PObj = PObj -> Pnext;
		PObj -> U.Pl = PPolygon;
	    }
	}
    }

    return IritPrsrConcatFreeForm(FreeForms);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Converts a whole set of geometry to polygons.                              M
*                                                                            *
* PARAMETERS:                                                                M
*   FreeForms:        Crvs/Srfs/Trimmed Srfs/Trivariates read from a file by M
*                     the irit parser.				             M
*   Talkative:        Do we want some more information printed?		     M
*   FourPerFlat:      See IritSurface2Polygons.	                             M
*   FineNess:         See IritSurface2Polygons.	                             M
*   ComputeUV:        See IritSurface2Polygons.	                             M
*   Optimal:          See IritSurface2Polygons.	                             M
*   BBoxGridFlag:     Do we want bounding box values and grid estimation.    M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Polygon/line(s) representing the geometry and its    M
*                       control mesh.	                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   FreeForm2Polygons                                                        M
*****************************************************************************/
IPObjectStruct *FreeForm2Polygons(IritPrsrFreeFormStruct *FreeForms,
				  int Talkative,
				  int FourPerFlat,
				  int FineNess,
				  int ComputeUV,
				  int Optimal,
				  int BBoxGrid)
{
    int LocalFourPerFlat;
    CagdSrfStruct *Srf, *Srfs;
    TrimSrfStruct *TrimSrf, *TrimSrfs;
    TrivTVStruct *TV, *TVs;
    IPPolygonStruct *PPolygon;
    IPObjectStruct *PObj,
	*SrfObjs = FreeForms -> SrfObjs,
	*TrimSrfObjs = FreeForms -> TrimSrfObjs,
	*TrivarObjs = FreeForms -> TrivarObjs;

    if (SrfObjs) {
	for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    CagdBBoxStruct BBox, TempBBox;
	    char GridStr[LINE_LEN];
	    RealType RelativeFineNess;

	    if (Talkative)
		fprintf(stderr, "Processing surface object \"%s\"\n",
			PObj -> Name);

	    Srfs = PObj -> U.Srfs;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYGON_OBJ(PObj);
	    strcat(PObj -> Name, "Pg");

	    LocalFourPerFlat = FourPerFlat;
		
	    if (AttrGetObjectStrAttrib(PObj, "twoperflat"))
		LocalFourPerFlat = FALSE;
	    if (AttrGetObjectStrAttrib(PObj, "fourperflat"))
		LocalFourPerFlat = TRUE;
		
	    if ((RelativeFineNess = AttrGetObjectRealAttrib(PObj,
					   "resolution")) > IP_ATTR_BAD_REAL)
		RelativeFineNess = 1.0;
		
	    for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
		RealType t;

		if (BBoxGrid) {
		    /* Generate bounding box to surfaces and estimate */
		    /* the grid size for it using GlblGridSize.	  */
		    if (Srf == Srfs)
			CagdSrfBBox(Srf, &BBox);
		    else {
			CagdSrfBBox(Srf, &TempBBox);
			CagdMergeBBox(&BBox, &TempBBox);
		    }
		}

		if ((t = AttrGetObjectRealAttrib(PObj, "u_resolution"))
							    < IP_ATTR_BAD_REAL)
		    AttrSetRealAttrib(&Srf -> Attr, "u_resolution", t);
		if ((t = AttrGetObjectRealAttrib(PObj, "v_resolution"))
							    < IP_ATTR_BAD_REAL)
		    AttrSetRealAttrib(&Srf -> Attr, "v_resolution", t);

		PPolygon = IritSurface2Polygons(Srf, LocalFourPerFlat,
						RelativeFineNess * FineNess,
						ComputeUV, Optimal);

		PObj -> U.Pl = IritPrsrAppendPolyLists(PPolygon,
						       PObj -> U.Pl);
	    }
	    CagdSrfFreeList(Srfs);

	    if (BBoxGrid) {
		RealType
		    Dx = BBox.Max[0] - BBox.Min[0],
		    Dy = BBox.Max[1] - BBox.Min[1],
		    Dz = BBox.Max[2] - BBox.Min[2],
		    M = MAX(MAX(Dx, Dy), Dz);
		int IDx = (int) (BBoxGrid * (Dx / M)),
		    IDy = (int) (BBoxGrid * (Dy / M)),
		    IDz = (int) (BBoxGrid * (Dz / M));
		    
		/* Save grid information derived from the surface bbox. */
		sprintf(GridStr, "%d %d %d",
			IDx > 0 ? IDx : 1,
			IDy > 0 ? IDy : 1,
			IDz > 0 ? IDz : 1);
		AttrSetObjectStrAttrib(PObj, "GridSize", GridStr);
		sprintf(GridStr, "%f %f %f %f %f %f",
			BBox.Min[0], BBox.Max[0],
			BBox.Min[1], BBox.Max[1],
			BBox.Min[2], BBox.Max[2]);
		AttrSetObjectStrAttrib(PObj, "BBox", GridStr);
	    }
	}
    }

    if (TrimSrfObjs) {
	for (PObj = TrimSrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    CagdBBoxStruct BBox, TempBBox;
	    char GridStr[LINE_LEN];
	    RealType RelativeFineNess;

	    if (Talkative)
		fprintf(stderr, "Processing trimmed surface object \"%s\"\n",
			PObj -> Name);

	    TrimSrfs = PObj -> U.TrimSrfs;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYGON_OBJ(PObj);
	    strcat(PObj -> Name, "Pg");

	    LocalFourPerFlat = FourPerFlat;
		
	    if (AttrGetObjectStrAttrib(PObj, "twoperflat"))
		LocalFourPerFlat = FALSE;
	    if (AttrGetObjectStrAttrib(PObj, "fourperflat"))
		LocalFourPerFlat = TRUE;
		
	    if ((RelativeFineNess = AttrGetObjectRealAttrib(PObj,
					   "resolution")) > IP_ATTR_BAD_REAL)
		RelativeFineNess = 1.0;
		
	    for (TrimSrf = TrimSrfs;
		 TrimSrf != NULL;
		 TrimSrf = TrimSrf -> Pnext) {
		RealType t;

		if (BBoxGrid) {
		    /* Generate bounding box to surfaces and estimate */
		    /* the grid size for it using GlblGridSize.	  */
		    if (TrimSrf == TrimSrfs)
			CagdSrfBBox(TrimSrf -> Srf, &BBox);
		    else {
			CagdSrfBBox(TrimSrf -> Srf, &TempBBox);
			CagdMergeBBox(&BBox, &TempBBox);
		    }
		}

		if ((t = AttrGetObjectRealAttrib(PObj, "u_resolution"))
							    < IP_ATTR_BAD_REAL)
		    AttrSetRealAttrib(&TrimSrf -> Attr, "u_resolution", t);
		if ((t = AttrGetObjectRealAttrib(PObj, "v_resolution"))
							    < IP_ATTR_BAD_REAL)
		    AttrSetRealAttrib(&TrimSrf -> Attr, "v_resolution", t);

		PPolygon = IritTrimSrf2Polygons(TrimSrf, LocalFourPerFlat,
						RelativeFineNess * FineNess,
						ComputeUV, Optimal);

		PObj -> U.Pl = IritPrsrAppendPolyLists(PPolygon,
						       PObj -> U.Pl);
	    }
	    TrimSrfFreeList(TrimSrfs);

	    if (BBoxGrid) {
		RealType
		    Dx = BBox.Max[0] - BBox.Min[0],
		    Dy = BBox.Max[1] - BBox.Min[1],
		    Dz = BBox.Max[2] - BBox.Min[2],
		    M = MAX(MAX(Dx, Dy), Dz);
		int IDx = (int) (BBoxGrid * (Dx / M)),
		    IDy = (int) (BBoxGrid * (Dy / M)),
		    IDz = (int) (BBoxGrid * (Dz / M));
		    
		/* Save grid information derived from the surface bbox. */
		sprintf(GridStr, "%d %d %d",
			IDx > 0 ? IDx : 1,
			IDy > 0 ? IDy : 1,
			IDz > 0 ? IDz : 1);
		AttrSetObjectStrAttrib(PObj, "GridSize", GridStr);
		sprintf(GridStr, "%f %f %f %f %f %f",
			BBox.Min[0], BBox.Max[0],
			BBox.Min[1], BBox.Max[1],
			BBox.Min[2], BBox.Max[2]);
		AttrSetObjectStrAttrib(PObj, "BBox", GridStr);
	    }
	}
    }

    if (TrivarObjs) {
	for (PObj = TrivarObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    CagdBBoxStruct BBox, TempBBox;
	    char GridStr[LINE_LEN];
	    RealType RelativeFineNess;

	    if (Talkative)
		fprintf(stderr, "Processing trivariate object \"%s\"\n",
			PObj -> Name);

	    TVs = PObj -> U.Trivars;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYGON_OBJ(PObj);
	    strcat(PObj -> Name, "Pg");

	    LocalFourPerFlat = FourPerFlat;
		
	    if (AttrGetObjectStrAttrib(PObj, "twoperflat"))
		LocalFourPerFlat = FALSE;
	    if (AttrGetObjectStrAttrib(PObj, "fourperflat"))
		LocalFourPerFlat = TRUE;
		
	    if ((RelativeFineNess = AttrGetObjectRealAttrib(PObj,
					   "resolution")) > IP_ATTR_BAD_REAL)
		RelativeFineNess = 1.0;

	    for (TV = TVs; TV != NULL; TV = TV -> Pnext) {
		if (BBoxGrid) {
		    /* Generate bounding box to surfaces and estimate */
		    /* the grid size for it using BBoxGrid.	      */
		    if (TV == TVs)
			TrivTVBBox(TV, &BBox);
		    else {
			TrivTVBBox(TV, &TempBBox);
			CagdMergeBBox(&BBox, &TempBBox);
		    }
		}
		PPolygon = IritTrivar2Polygons(TV, LocalFourPerFlat,
					       RelativeFineNess * FineNess,
					       ComputeUV, Optimal);

		PObj -> U.Pl = IritPrsrAppendPolyLists(PPolygon,
						       PObj -> U.Pl);
	    }
	    TrivTVFreeList(TVs);

	    if (BBoxGrid) {
		RealType
		    Dx = BBox.Max[0] - BBox.Min[0],
		    Dy = BBox.Max[1] - BBox.Min[1],
		    Dz = BBox.Max[2] - BBox.Min[2],
		    M = MAX(MAX(Dx, Dy), Dz);
		int IDx = (int) (BBoxGrid * (Dx / M)),
		    IDy = (int) (BBoxGrid * (Dy / M)),
		    IDz = (int) (BBoxGrid * (Dz / M));
		    
		/* Save grid information derived from the surface bbox. */
		sprintf(GridStr, "%d %d %d",
			IDx > 0 ? IDx : 1,
			IDy > 0 ? IDy : 1,
			IDz > 0 ? IDz : 1);
		AttrSetObjectStrAttrib(PObj, "GridSize", GridStr);
		sprintf(GridStr, "%f %f %f %f %f %f",
			BBox.Min[0], BBox.Max[0],
			BBox.Min[1], BBox.Max[1],
			BBox.Min[2], BBox.Max[2]);
		AttrSetObjectStrAttrib(PObj, "BBox", GridStr);
	    }
	}
    }

    return IritPrsrConcatFreeForm(FreeForms);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to convert a single freeform geometry to polylines/polygons.       M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:  A Crv/Srf/Trimmed Srf/Trivariate freeform geoemtry.               M
*   State: The way the freeform geometry should be converted.                M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Processed freeform geometry.                         M
*                                                                            *
* KEYWORDS:                                                                  M
*   ProcessFreeForm, conversion                                              M
*****************************************************************************/
IPObjectStruct *ProcessFreeForm(IPObjectStruct *PObj,
				FreeformConvState *State)
{
    static int
	FirstTime = TRUE;
    IritPrsrFreeFormStruct FreeForms;
    int DumpObjsAsPolylines = State -> DumpObjsAsPolylines;
    IPObjectStruct
	*PObjNext = PObj -> Pnext;

    PObj -> Pnext = NULL;

    if (FirstTime) {
	FirstTime = FALSE;

	if (FFCState.LinearOnePolyFlag)
	    CagdSetLinear2Poly(CAGD_ONE_POLY_PER_COLIN);
	else
	    CagdSetLinear2Poly(CAGD_REG_POLY_PER_LIN);
    }

    FreeForms.CrvObjs = NULL;
    FreeForms.SrfObjs = NULL;
    FreeForms.TrimSrfObjs = NULL;
    FreeForms.TrivarObjs = NULL;

    switch (PObj -> ObjType) {
	case IP_OBJ_CURVE:
	    FreeForms.CrvObjs = PObj;
	    DumpObjsAsPolylines = TRUE;
	    break;
	case IP_OBJ_SURFACE:
	    FreeForms.SrfObjs = PObj;
	    break;
	case IP_OBJ_TRIMSRF:
	    FreeForms.TrimSrfObjs = PObj;
	    break;
	case IP_OBJ_TRIVAR:
	    FreeForms.TrivarObjs = PObj;
	    break;
	default:
	    fprintf(stderr, "Non freeform geometry detected\n");
	    return NULL;
    }

    if (FFCState.CubicCrvsAprox) {
	PObj = FreeForm2CubicBzr(&FreeForms,
				 State -> Talkative,
				 State -> DrawFFGeom,
				 State -> DrawFFMesh,
				 State -> NumOfIsolines,
				 State -> SamplesPerCurve,
				 State -> OptimalPolylines);
    }
    else if (DumpObjsAsPolylines) {
	PObj = FreeForm2Polylines(&FreeForms,
				  State -> Talkative,
				  State -> DrawFFGeom,
				  State -> DrawFFMesh,
				  State -> NumOfIsolines,
				  State -> SamplesPerCurve,
				  State -> OptimalPolylines);
    }
    else {
	IPObjectStruct
	    *MeshObj = NULL;

	if (State -> DrawFFMesh) {
	    FreeformConvState
		TState = *State;

	    TState.DrawFFGeom = FALSE;
	    TState.DumpObjsAsPolylines = TRUE;
	    MeshObj = ProcessFreeForm(CopyObject(NULL, PObj, TRUE), &TState);
	}

	PObj = FreeForm2Polygons(&FreeForms,
				 State -> Talkative,
				 State -> FourPerFlat,
				 (int) State -> FineNess,
				 State -> ComputeUV,
				 State -> OptimalPolygons,
				 State -> BBoxGrid);
	if (MeshObj) {
	    MeshObj -> Pnext = PObj -> Pnext;
	    PObj -> Pnext = MeshObj;
	}
    }

    return IritPrsrAppendObjLists(PObj, PObjNext);
}
