/******************************************************************************
* Trng2Ply.c - Converts a triangular surface surface into polygons.           *
*******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                 *
*******************************************************************************
* Written by Gershon Elber, Aug. 96.					      *
******************************************************************************/

#include "trng_loc.h"
#include "allocate.h"
#include "iritprsr.h"
#include "geomat3d.h"
#include "convex.h"

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to convert a single triangular surface to a set of triangles       M
* approximating it. 							     M
*   FineNess is a fineness control on result and the larger it is more       M
* triangles may result.							     M
*   A value of 10 is a good starting value.				     M
* NULL is returned in case of an error, otherwise list of CagdPolygonStruct. M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrf:           To approximate into triangles.                         M
*   FineNess:         Control on accuracy, the higher the finer.             M
*   ComputeNormals:   If TRUE, normal information is also computed.          M
*   ComputeUV:        If TRUE, UV values are stored and returned as well.    M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdPolygonStruct *:   A list of polygons with optional normal and/or    M
*                         UV parametric information.                         M
*                         NULL is returned in case of an error.              M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrf2Polygons, polygonization, surface approximation               M
*****************************************************************************/
CagdPolygonStruct *TrngTriSrf2Polygons(TrngTriangSrfStruct *TriSrf,
				       int FineNess,
				       CagdBType ComputeNormals,
				       CagdBType ComputeUV)
{
    int i, j;
    CagdPtStruct *Pts;
    CagdVecStruct *Nrml;
    CagdRType UMin, UMax, VMin, VMax, WMin, WMax, Du, Dv, u, v;
    CagdPolygonStruct
	*CagdPlList = NULL;

    TrngTriSrfDomain(TriSrf, &UMin, &UMax, &VMin, &VMax, &WMin, &WMax);
    Du = (UMax - UMin - IRIT_UEPS) / FineNess;
    Dv = (VMax - VMin - IRIT_UEPS) / FineNess;

    Pts = (CagdPtStruct *) IritMalloc(sizeof(CagdPtStruct) * (FineNess + 1));
    Nrml = (CagdVecStruct *) IritMalloc(sizeof(CagdVecStruct) * (FineNess + 1));

    for (v = VMin, j = 0; j <= FineNess; v += Dv, j++) { /* Eval first row. */
	CagdRType
	    *R = TrngTriSrfEval2(TriSrf, UMin, v);

	CagdCoerceToE3(Pts[j].Pt, &R, -1, TriSrf -> PType);

	if (ComputeNormals) {
	    Nrml[j] = *TrngTriSrfNrml(TriSrf, UMin, v);
	}
    }

    for (u = UMin + Du, i = 1; i <= FineNess; u += Du, i++) {
	CagdPType LastPt;
	CagdVType LastNrml;

	for (v = VMin, j = 0; j + i <= FineNess; v += Dv, j++) {
	    CagdRType
	        *R = TrngTriSrfEval2(TriSrf, u, v);
	    CagdPType NewPt;
	    CagdVType NewNrml;
	    CagdPolygonStruct
	        *CagdPl = CagdPolygonNew();

	    CagdCoerceToE3(NewPt, &R, -1, TriSrf -> PType);

	    if (ComputeNormals) {
		CagdVecStruct
		    *N = TrngTriSrfNrml(TriSrf, u, v);

		PT_COPY(NewNrml, N -> Vec);
	    }

	    if (j > 0) {
		PT_COPY(CagdPl -> Polygon[0].Pt, LastPt);
		PT_COPY(CagdPl -> Polygon[1].Pt, NewPt);
		PT_COPY(CagdPl -> Polygon[2].Pt, Pts[j].Pt);
		if (ComputeNormals) {
		    PT_COPY(CagdPl -> Polygon[0].Nrml, LastNrml);
		    PT_COPY(CagdPl -> Polygon[1].Nrml, NewNrml);
		    PT_COPY(CagdPl -> Polygon[2].Nrml, Nrml[j].Vec);
		}
		if (ComputeUV) {
		    CagdPl -> Polygon[0].UV[0] = u;
		    CagdPl -> Polygon[0].UV[1] = v - Dv;
		    CagdPl -> Polygon[1].UV[0] = u;
		    CagdPl -> Polygon[1].UV[1] = v;
		    CagdPl -> Polygon[2].UV[0] = u - Du;
		    CagdPl -> Polygon[2].UV[1] = v - Dv;
		}
		LIST_PUSH(CagdPl, CagdPlList);

	        CagdPl = CagdPolygonNew();
	    }

	    PT_COPY(CagdPl -> Polygon[0].Pt, Pts[j + 1].Pt);
	    PT_COPY(CagdPl -> Polygon[1].Pt, Pts[j].Pt);
	    PT_COPY(CagdPl -> Polygon[2].Pt, NewPt);
	    if (ComputeNormals) {
		PT_COPY(CagdPl -> Polygon[0].Nrml, Nrml[j + 1].Vec);
		PT_COPY(CagdPl -> Polygon[1].Nrml, Nrml[j].Vec);
		PT_COPY(CagdPl -> Polygon[2].Nrml, NewNrml);
	    }
	    if (ComputeUV) {
		CagdPl -> Polygon[0].UV[0] = u - Du;
		CagdPl -> Polygon[0].UV[1] = v;
		CagdPl -> Polygon[1].UV[0] = u - Du;
		CagdPl -> Polygon[1].UV[1] = v - Dv;
		CagdPl -> Polygon[2].UV[0] = u;
		CagdPl -> Polygon[2].UV[1] = v;
	    }
	    LIST_PUSH(CagdPl, CagdPlList);

	    PT_COPY(LastPt, NewPt);
	    PT_COPY(Pts[j].Pt, LastPt);
	    if (ComputeNormals) {
		PT_COPY(LastNrml, NewNrml);
		PT_COPY(Nrml[j].Vec, LastNrml);
	    }

	}
    }

    IritFree((VoidPtr) Pts);
    IritFree((VoidPtr) Nrml);

    return CagdPlList;
}
