/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993 Jason I. Gobat and Darren C. Atkinson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/****************************************************************************
 *
 * File:	triangle.c
 *
 ***************************************************************************/

# include <math.h>
# include <stdio.h>
# include "allocate.h"
# include "error.h"
# include "fe.h"
# include "objects.h"
# include "mesh.h"
# include "triangle.h"

typedef double dbl_pair [2];
typedef int    triple_int [3];

static double PolygonArea (vcl, n)
   double  (*vcl) [2];
   int       n;
{
   int       i;
   double    A;

   A = 0.0;
   for (i = 0 ; i < n - 1 ; i++)
      A += (vcl [i][0]*vcl [i+1][1] - vcl [i+1][0]*vcl [i][1]);

   A += (vcl [n-1][0]*vcl [0][1] - vcl [0][0]*vcl [n-1][1]);
 
   return 0.5*A;
}

/****************************************************************************
 *
 * Function:	GenerateTriMesh
 *
 * Description:	a procedure to interface to Triangle and generate a mesh
 *		of triangular elements. 
 *
 ****************************************************************************/

unsigned GenerateTriMesh (trimesh,element,node,numelts,numnodes,bnode,belement)
   TriMesh	trimesh;
   Element	**element;
   Node		**node;
   unsigned	*numelts;
   unsigned	*numnodes;
   unsigned	bnode;
   unsigned	belement;
{
   unsigned	i,j;
   unsigned	count;
   int		n, m;
   int		ne, nn;
   int		status;
   struct triangulateio   in, out;
   int		npoints;
   double       x, y;
   int		start;
   double	A, Atot;
   double	Acrit;
   char		opts [32];

   if (trimesh -> numcurves <= 0) {
      error ("must have at least a boundary curve to generate a TriMesh");
      return 1;
   }

   if (trimesh -> definition -> numnodes != 3) {
      error ("TriMesh generation requires three node elements");
      return 1;
   }


   npoints = 0;

   Atot = 0.0;

   for (i = 0 ; i < trimesh -> numcurves ; i++) {
      if (trimesh -> curves [i] -> numvc < 3) {
         error ("each curve must have at least 3 points");
         return 1;
      }

      npoints += trimesh -> curves [i] -> numvc;

      A = PolygonArea(trimesh -> curves [i] -> vcl, 
                      trimesh -> curves [i] -> numvc);

      if (i == 0 && A < 0) {
         error ("main boundary points must be in CCW order");
         return 1;
      }
      else if (i > 0 && A > 0) {
         error ("hole boundary points must be in CW order");
         return 1;
      }

      Atot += A;
   }

   Acrit = trimesh -> alpha * Atot / trimesh -> target;

   if (npoints <= 0) {
      error ("nothing to generate");
      return 1;
   }

   in.numberofpoints = npoints;
   in.numberofpointattributes = 0;
   in.pointlist = (double *) malloc(in.numberofpoints * 2 * sizeof(double));
   in.pointattributelist = NULL;
   in.pointmarkerlist = (int *) malloc(sizeof(int) * in.numberofpoints);
   for (i = 0 ; i < in.numberofpoints ; i++)
       in.pointmarkerlist [i] = 1;

   in.numberofholes = trimesh -> numcurves - 1;
   if (in.numberofholes)
      in.holelist = (double *) malloc(2 * in.numberofholes * sizeof(double));
   else
      in.holelist = NULL;

   in.numberofregions = 0;
   in.numberofsegments = npoints;
   in.segmentlist = (int *) malloc(2 * in.numberofsegments * sizeof(int));
   in.segmentmarkerlist = (int *) malloc(sizeof(int) * in.numberofsegments);
   for (i = 0 ; i < in.numberofsegments ; i++)
       in.segmentmarkerlist [i] = 1;

   n = 0;
   m = 0;
   for (i = 0 ; i < trimesh -> numcurves ; i++) {
      start = m;
      for (j = 0 ; j < trimesh -> curves [i] -> numvc ; j++) {
         in.pointlist [n]     = trimesh -> curves [i] -> vcl [j][0];
         in.pointlist [n + 1] = trimesh -> curves [i] -> vcl [j][1];
        
         in.segmentlist [n]     = m; 
         in.segmentlist [n + 1] = m + 1;

         n += 2;
         m += 1;
      }

      in.segmentlist [n - 1] = start;
   }

   for (i = 0 ; i < in.numberofholes ; i++) {
      x = 0.0;
      y = 0.0;

      for (j = 0 ; j < trimesh -> curves [i+1] -> numvc ; j++) {
         x += trimesh -> curves [i+1] -> vcl [j][0];
         y += trimesh -> curves [i+1] -> vcl [j][1];
      }

      x /= trimesh -> curves [i+1] -> numvc;
      y /= trimesh -> curves [i+1] -> numvc;

      in.holelist [2*i]     = x;
      in.holelist [2*i + 1] = y;
   }

   out.pointlist                  = (double *) NULL;            
   out.pointattributelist         = (double *) NULL;
   out.pointmarkerlist            = (int *) NULL; 
   out.trianglelist               = (int *) NULL;          
   out.numberoftriangleattributes = 0;
   out.triangleattributelist      = (double *) NULL;
   out.segmentmarkerlist          = (int *) NULL;
   out.segmentlist                = (int *) NULL;

   sprintf (opts, "Qpqza%f", Acrit);

   triangulate(opts, &in, &out, NULL);

   ne = out.numberoftriangles;
   nn = out.numberofpoints;
   if (ne <= 0 || nn <= 0) {
      error ("nothing to generate");
      return 1;
   }

	/*
	 * allocate some memory to hold everything that we will generate
	 */

   if (!(*node = Allocate(Node, nn)))
      Fatal ("allocation error in TriMesh generation");

   UnitOffset (*node);

   for (i = 1 ; i <= nn ; i++) {
      if (!((*node) [i] = CreateNode (0)))
         Fatal ("allocation error in TriMesh generation");
   }

   if (!(*element = Allocate(Element, ne)))
      Fatal ("allocation error in TriMesh generation");

   UnitOffset (*element);

   for (i = 1 ; i <= ne ; i++) {
      if (!((*element) [i] = CreateElement (0, trimesh -> definition)))
         Fatal ("allocation error in TriMesh generation");
   }

	/*	
	 * generate all the nodes
	 */

   for (i = 1 ; i <= nn ; i++) {
 
      (*node) [i] -> number = i + bnode;
      (*node) [i] -> x = out.pointlist [2*i - 2];
      (*node) [i] -> y = out.pointlist [2*i - 1];
      (*node) [i] -> z = 0;

   }

	/*
	 * attach all the elements to the nodes
	 */

   for (i = 1 ; i <= ne ; i++) {

      (*element) [i] -> number = i + belement;
      (*element) [i] -> node [1] = (*node) [out.trianglelist [3*(i - 1) + 0] + 1];
      (*element) [i] -> node [2] = (*node) [out.trianglelist [3*(i - 1) + 1] + 1];
      (*element) [i] -> node [3] = (*node) [out.trianglelist [3*(i - 1) + 2] + 1];

   } 

   *numnodes = nn;
   *numelts  = ne;

   Deallocate(in.pointlist);
   Deallocate(in.pointmarkerlist);
   Deallocate(in.holelist);
   Deallocate(in.segmentlist);
   Deallocate(in.segmentmarkerlist);
   Deallocate(out.pointlist);
   Deallocate(out.pointattributelist);
   Deallocate(out.pointmarkerlist);
   Deallocate(out.trianglelist);
   Deallocate(out.triangleattributelist);
   Deallocate(out.segmentmarkerlist);
   Deallocate(out.segmentlist);

   return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1