/******************************************************************************
* Poly_Pts.c - distribute uniformly points on a polygonal object	      *
*******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                 *
*******************************************************************************
* Written by Gershon Elber, Feb 1997.					      *
******************************************************************************/

#include <math.h>
#include <stdio.h>
#include "irit_sm.h"
#include "geomat3d.h"
#include "geomvals.h"
#include "convex.h"
#include "iritprsr.h"
#include "allocate.h"

#define VERTEX_COPY(VDest, VSrc)  { PT_COPY(VDest -> Coord, VSrc -> Coord); \
				    PT_COPY(VDest -> Normal, VSrc -> Normal); \
				    VDest -> Tags = VSrc -> Tags; \
				    VDest -> Attrs = \
				        AttrCopyAttributes(VSrc -> Attrs); }

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Creates a new polygonal objects out of given one, that contains only     M
* triangles.  None convex polygons are split to convex one which, in turn,   M
* converted to triangles.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   PolyObj:   Polygonal object to split into triangles.                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A polygonal object containing only triangles         M
*		representing the same model as PolyObj.			     M
*                                                                            *
* SEE ALSO:                                                                  M
*   ConvexPolyObjectN                                                        M
*                                                                            *
* KEYWORDS:                                                                  M
*   CGConvertPolysToTriangles                                                M
*****************************************************************************/
IPObjectStruct *CGConvertPolysToTriangles(IPObjectStruct *PolyObj)
{
    IPPolygonStruct *Pl;
    int IsCirc = IritPrsrSetPolyListCirc(FALSE);

    IritPrsrSetPolyListCirc(IsCirc); /* Restore state, now that we know it. */

    PolyObj = ConvexPolyObjectN(PolyObj);

    for (Pl = PolyObj -> U.Pl; Pl != NULL; ) {
	IPPolygonStruct
	    *PlNext = Pl -> Pnext;
	IPVertexStruct
	    *VHead = Pl -> PVertex;
	int Len = IritPrsrVrtxListLen(VHead);

	if (Len > 3) {	                   /* Split into several triangles. */
	    int VLastTags;
	    IPVertexStruct *VLast,
		*VRest = VHead -> Pnext -> Pnext -> Pnext;
	    IPPolygonStruct
		*PlNew = NULL;

	    /* Isolate the first triangle out of the original polygon. */
	    VHead -> Pnext -> Pnext -> Pnext = IsCirc ? VHead : NULL;
	    VLast = VHead -> Pnext -> Pnext;
	    VLastTags = VLast -> Tags;
	    IP_SET_INTERNAL_VRTX(VLast);

	    /* Construct triangles out of the rest of the points. */
	    while (VRest != NULL && VRest != VHead) {
		IPVertexStruct
		    *VRestNext = VRest -> Pnext,
		    *V3 = IPAllocVertex(0, NULL, NULL),
		    *V2 = IPAllocVertex(0, NULL, V3),
		    *V1 = IPAllocVertex(0, NULL, V2);

		VERTEX_COPY(V1, VHead);
		VERTEX_COPY(V2, VLast);
		VERTEX_COPY(V3, VRest);

		if (IsCirc)
		    V3 -> Pnext = V1;

		IP_SET_INTERNAL_VRTX(V1);
		V2 -> Tags = VLastTags;
		if (VRest -> Pnext != NULL && VRest -> Pnext != VHead)
		    IP_SET_INTERNAL_VRTX(V3);
		else
		    V3 -> Tags = VRest -> Tags;

		PlNew = IPAllocPolygon(0, V1, PlNew);
		PLANE_COPY(PlNew -> Plane, Pl -> Plane);
		VLast = V3;
		VLastTags = VRest -> Tags;

		IPFreeVertex(VRest);
		VRest = VRestNext;
	    }

	    Pl -> Pnext = PlNew;
	    PlNew = IritPrsrGetLastPoly(PlNew);
	    PlNew -> Pnext = PlNext;
	}

	Pl = PlNext;
    }

    return PolyObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes a uniform distribution of points on a polygonal object.         M
*                                                                            *
* PARAMETERS:                                                                M
*   PolyObj:      Object to compute a uniform point distribution on.         M
*   n:		  Number of points to distribute (estimate).		     M
*   Dir:	  If given - use it as view dependent uniform distribution.  M
*		  Note that if Dir != NULL less than n points will be        M
*		  generated.						     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    A point list object.                                M
*                                                                            *
* KEYWORDS:                                                                  M
*   CGPointCoverOfPolyObj	                                             M
*****************************************************************************/
IPObjectStruct *CGPointCoverOfPolyObj(IPObjectStruct *PolyObj,
				      int n,
				      RealType *Dir)
{
    IPObjectStruct *PObj;
    RealType Area;
    VectorType ViewDir;
    IPPolygonStruct *Pl;
    IPVertexStruct
	*PtDistList = NULL;

    if (Dir != NULL) {
        PT_COPY(ViewDir, Dir);
	PT_NORMALIZE(ViewDir);
    }
      
    PolyObj = CGConvertPolysToTriangles(PolyObj);
    Area = PolyObjectArea(PolyObj);

    for (Pl = PolyObj -> U.Pl; Pl != NULL; Pl = Pl -> Pnext) {
	VectorType V1, V2;
	RealType
	    NumOfPts = n * (PolyOnePolyArea(Pl) / Area) *
			   (Dir == NULL ? 1.0 : DOT_PROD(Dir, Pl -> Plane)),
	    *Pt1 = Pl -> PVertex -> Coord,
	    *Pt2 = Pl -> PVertex -> Pnext -> Coord,
	    *Pt3 = Pl -> PVertex -> Pnext -> Pnext -> Coord;
	int i,
	    PolyN = (int) NumOfPts;

	PT_SUB(V1, Pt2, Pt1);
	PT_SUB(V2, Pt3, Pt1);
	
	if ((NumOfPts - PolyN) > IritRandom(0.0, 1.0))
	    PolyN++;

        /* Generate PolyN points on this triangle. */
        for (i = 0; i < PolyN; i++) {
	    VectorType V1a, V2a;
	    RealType
		Rand1 = IritRandom(0.0, 1.0),
		Rand2 = IritRandom(0.0, 1.0);
	    IPVertexStruct
		*V = IPAllocVertex(0, NULL, PtDistList);

	    PtDistList = V;

	    /* Guarantee that we are inside the triangle... */
	    if (Rand1 + Rand2 > 1.0) {
		Rand1 = 1.0 - Rand1;
		Rand2 = 1.0 - Rand2;
	    }

	    PT_COPY(V1a, V1);
	    PT_COPY(V2a, V2);
	    PT_SCALE(V1a, Rand1);
	    PT_SCALE(V2a, Rand2);

	    PT_COPY(V -> Coord, Pt1);
	    PT_ADD(V -> Coord, V -> Coord, V1a);
	    PT_ADD(V -> Coord, V -> Coord, V2a);
	}
    }

    IPFreeObject(PolyObj);

    Pl = IPAllocPolygon(0, PtDistList, NULL);

    PObj = GenPOLYObject(Pl);
    IP_SET_POINTLIST_OBJ(PObj);
    return PObj;
}
