www.pudn.com > easymesh.rar > EasyMesh.c


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%                                                     %%%%%%%%%%%%
%%%%%%%%%%%%                                                     %%%%%%%%%%%%
%%%%%%%%%%%%        o88°°88o  o88°°88o  o88°°88o  888  888       %%%%%%%%%%%%
%%%%%%%%%%%%        888  888  °°°  888  888  °°°  888  888       %%%%%%%%%%%%
%%%%%%%%%%%%        888  888       888  888       888  888       %%%%%%%%%%%%
%%%%%%%%%%%%        8888888°  o8888888  °888888o  888  888       %%%%%%%%%%%%
%%%%%%%%%%%%        888       888  888       888  888  888       %%%%%%%%%%%%
%%%%%%%%%%%%        888  ooo  888  888  ooo  888  °8888888       %%%%%%%%%%%%
%%%%%%%%%%%%        °88oo88°  °8888°88  °88oo88°       888       %%%%%%%%%%%%
%%%%%%%%%%%%                                      ooo  888       %%%%%%%%%%%%
%%%%%%%%%%%%                                      °888888°       %%%%%%%%%%%%
%%%%%%%%%%%%                                                     %%%%%%%%%%%%
%%%%%%%%%%%%                                                     %%%%%%%%%%%%
%%%%%%%%%%%%                                         888         %%%%%%%%%%%%
%%%%%%%%%%%%                                         888         %%%%%%%%%%%%
%%%%%%%%%%%%                                         888         %%%%%%%%%%%%
%%%%%%%%%%%%      8888888o888o   o88°°88o  o88°°88o  888°°88o    %%%%%%%%%%%%
%%%%%%%%%%%%      888  888  88o  888  888  888  °°°  888  888    %%%%%%%%%%%%
%%%%%%%%%%%%      888  888  888  888  888  888       888  888    %%%%%%%%%%%%
%%%%%%%%%%%%      888  888  888  8888888°  °888888o  888  888    %%%%%%%%%%%%
%%%%%%%%%%%%      888  888  888  888            888  888  888    %%%%%%%%%%%%
%%%%%%%%%%%%      888  888  888  888  ooo  ooo  888  888  888    %%%%%%%%%%%%
%%%%%%%%%%%%      888  888  888  °88oo88°  °88oo88°  888  888    %%%%%%%%%%%%
%%%%%%%%%%%%                                                     %%%%%%%%%%%%
%%%%%%%%%%%%                                                     %%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%                        %%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%  Author: Bojan NICENO  %%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%                        %%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%% niceno@univ.trieste.it %%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%                        %%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define GRAPHICS OFF

#include 
#include 
#include 
#include 

#ifndef max
#define max(a,b)  (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b)  (((a) < (b)) ? (a) : (b))
#endif
#ifndef PI
#define PI    3.14159265359
#endif

#define SMALL 1e-30
#define GREAT 1e+30

#define ON      0 
#define OFF    -1       /* element is switched off */
#define WAIT   -2       /* node is waiting (it is a corner node) */
#define A       3
#define D       4
#define W       5

#define MAX_NODES 3000

/*-----------------------------+
|  definitions for the chains  |
+-----------------------------*/
#define CLOSED 0
#define OPEN   1
#define INSIDE 2


struct ele
 {
  int i,  j,  k;
  int ei, ej, ek;
  int si, sj, sk;

  int mark;             /* is it off (ON or OFF) */
  int state;            /* is it (D)one, (A)ctive or (W)aiting */
  int material;

  double xv, yv, xin, yin, R, r, Det;

  int new_numb;         /* used for renumeration */
 }
elem[MAX_NODES*2];


struct sid
 {
  int ea, eb;           /* left and right element */
  int a, b, c, d;       /* left, right, start and end point */

  int mark;             /* is it off, is on the boundary */

  double s;

  int new_numb;         /* used for renumeration */
 }
side[MAX_NODES*3];


struct nod
 {
  double x, y, F;
			
  double sumx, sumy;
  int    Nne;

  int mark;             /* is it off */

  int next;             /* next node in the boundary chain */
  int chain;            /* on which chains is the node */
  int inserted;

  int new_numb;         /* used for renumeration */
 }
node[MAX_NODES], point[MAX_NODES/2];


 struct seg
  {int n0, n1;
   int N; int chain; int bound; int mark;}
 *segment;
 
 struct chai
  {int s0, s1, type;}
 *chain;


int Ne, Nn, Ns, Nc;             /* number of: elements, nodes, sides */
int ugly;                       /* mora li biti globalna ??? */


/*=========================================================================*/
double area(struct nod *na, struct nod *nb, struct nod *nc)
{
 return 0.5 * (   ((*nb).x-(*na).x)*((*nc).y-(*na).y) 
		- ((*nb).y-(*na).y)*((*nc).x-(*na).x));
}
/*-------------------------------------------------------------------------*/


/*=========================================================================*/
double dist(struct nod *na, struct nod *nb)
{
 return sqrt(   ((*nb).x-(*na).x)*((*nb).x-(*na).x)
	      + ((*nb).y-(*na).y)*((*nb).y-(*na).y) );
}
/*-------------------------------------------------------------------------*/


/*=========================================================================*/
in_elem(struct nod *n)
{
 int e;
 
 for(e=0; e= 0.0
       && area(n, &node[elem[e].j], &node[elem[e].k]) >= 0.0
       && area(n, &node[elem[e].k], &node[elem[e].i]) >= 0.0 )
   
   break;
  }
 return e;
}
/*-in_elem-----------------------------------------------------------------*/


/*=========================================================================*/
bowyer(int n, int spac)
{
 int e, i, s, swap;
 struct nod vor;

 do  
  { 
   swap=0;
   for(s=0; s1 && node[side[s].d].bound==OFF && side[s].s<(node[side[s].c].F+node[side[s].d].F) ) ||
	  (node[side[s].d].inserted>1 && node[side[s].c].bound==OFF && side[s].s<(node[side[s].c].F+node[side[s].d].F) ) ) ) */
    {
     if(side[s].a==n)
      {e=side[s].eb; 
       if(e!=OFF)
	{vor.x=elem[e].xv; 
	 vor.y=elem[e].yv;
	 if( dist(&vor, &node[n]) < elem[e].R )
	  {swap_side(s); swap=1;}}}
   
     else if(side[s].b==n)
      {e=side[s].ea; 
       if(e!=OFF)
	{vor.x=elem[e].xv; 
	 vor.y=elem[e].yv;
	 if( dist(&vor, &node[n]) < elem[e].R )
	  {swap_side(s); swap=1;}}}
    }
  }
 while(swap==1);

}
/*-bowyer------------------------------------------------------------------*/


/*=========================================================================*/
circles(int e)
/*---------------------------------------------------+
|  This function calculates radii of inscribed and   |
|  circumscribed circle for a given element (int e)  |
+---------------------------------------------------*/
{
 double x, y, xi, yi, xj, yj, xk, yk, xij, yij, xjk, yjk, num, den;
 double si, sj, sk, O;

 xi=node[elem[e].i].x; yi=node[elem[e].i].y;
 xj=node[elem[e].j].x; yj=node[elem[e].j].y;
 xk=node[elem[e].k].x; yk=node[elem[e].k].y;
   
 xij=0.5*(xi+xj); yij=0.5*(yi+yj);
 xjk=0.5*(xj+xk); yjk=0.5*(yj+yk);

 num = (xij-xjk)*(xj-xi) + (yij-yjk)*(yj-yi);
 den = (xj -xi) *(yk-yj) - (xk -xj) *(yj-yi);

 if(den>0)
  {
   elem[e].xv = x = xjk + num/den*(yk-yj);
   elem[e].yv = y = yjk - num/den*(xk-xj);

   elem[e].R  = sqrt( (xi-x)*(xi-x) + (yi-y)*(yi-y) );
  }

 si=side[elem[e].si].s;
 sj=side[elem[e].sj].s;
 sk=side[elem[e].sk].s;
 O =si+sj+sk;
 elem[e].Det = xi*(yj-yk) - xj*(yi-yk) + xk*(yi-yj);

 elem[e].xin = ( xi*si + xj*sj + xk*sk ) / O;
 elem[e].yin = ( yi*si + yj*sj + yk*sk ) / O;

 elem[e].r   = elem[e].Det / O;
}
/*-circles-----------------------------------------------------------------*/


/*=========================================================================*/
spacing(int e, int n)
/*----------------------------------------------------------------+
|  This function calculates the value of the spacing function in  |
|  a new node 'n' which is inserted in element 'e' by a linear    |
|  approximation from the values of the spacing function in the   |
|  elements nodes.                                                |
+----------------------------------------------------------------*/
{
 double dxji, dxki, dyji, dyki, dx_i, dy_i, det, a, b;

 dxji = node[elem[e].j].x - node[elem[e].i].x;
 dyji = node[elem[e].j].y - node[elem[e].i].y;
 dxki = node[elem[e].k].x - node[elem[e].i].x;
 dyki = node[elem[e].k].y - node[elem[e].i].y;
 dx_i = node[n].x - node[elem[e].i].x;
 dy_i = node[n].y - node[elem[e].i].y;

 det = dxji*dyki - dxki*dyji;

 a = (+ dyki*dx_i - dxki*dy_i)/det;
 b = (- dyji*dx_i + dxji*dy_i)/det;

 node[n].F = node[elem[e].i].F + 
	     a*(node[elem[e].j].F - node[elem[e].i].F) +
	     b*(node[elem[e].k].F - node[elem[e].i].F);
}
/*-spacing-----------------------------------------------------------------*/


/*=========================================================================*/
insert_node(double x, double y, int spac,
	 int prev_n, int prev_s_mark, int mark, int next_s_mark, int next_n)
{
 int    i,j,k,en, n, e,ei,ej,ek, s,si,sj,sk;
 double sx, sy;

 Nn++;          /* one new node */
 
 node[Nn-1].x = x;
 node[Nn-1].y = y;
 node[Nn-1].mark = mark;

/* find the element which contains new node */ 
 e = in_elem(&node[Nn-1]);

/* calculate the spacing function in the new node */
 if(spac==ON)
   spacing(e, Nn-1);

 i =elem[e].i;  j =elem[e].j;  k =elem[e].k;
 ei=elem[e].ei; ej=elem[e].ej; ek=elem[e].ek; 
 si=elem[e].si; sj=elem[e].sj; sk=elem[e].sk; 
 
 Ne+=2;
 Ns+=3;

/*---------------+
|  new elements  |
+---------------*/ 
 elem[Ne-2].i=Nn-1;  elem[Ne-2].j=k;     elem[Ne-2].k=i;
 elem[Ne-1].i=Nn-1;  elem[Ne-1].j=i;     elem[Ne-1].k=j; 
 
 elem[Ne-2].ei=ej;   elem[Ne-2].ej=Ne-1; elem[Ne-2].ek=e;
 elem[Ne-1].ei=ek;   elem[Ne-1].ej=e;    elem[Ne-1].ek=Ne-2;
 
 elem[Ne-2].si=sj;   elem[Ne-2].sj=Ns-2; elem[Ne-2].sk=Ns-3;
 elem[Ne-1].si=sk;   elem[Ne-1].sj=Ns-1; elem[Ne-1].sk=Ns-2;
 
/*------------+ 
|  new sides  |
+------------*/ 
 side[Ns-3].c =k;    side[Ns-3].d =Nn-1;     /* c-d */
 side[Ns-3].a =j;    side[Ns-3].b =i;        /* a-b */
 side[Ns-3].ea=e;    side[Ns-3].eb=Ne-2;
 
 side[Ns-2].c =i;    side[Ns-2].d =Nn-1;     /* c-d */
 side[Ns-2].a =k;    side[Ns-2].b =j;        /* a-b */
 side[Ns-2].ea=Ne-2; side[Ns-2].eb=Ne-1;
 
 side[Ns-1].c =j;    side[Ns-1].d =Nn-1;     /* c-d */
 side[Ns-1].a =i;    side[Ns-1].b =k;        /* a-b */
 side[Ns-1].ea=Ne-1; side[Ns-1].eb=e;       

 for(s=1; s<=3; s++)
  {sx = node[side[Ns-s].c].x - node[side[Ns-s].d].x;
   sy = node[side[Ns-s].c].y - node[side[Ns-s].d].y;
   side[Ns-s].s = sqrt(sx*sx+sy*sy);}

 elem[e].i  = Nn-1;
 elem[e].ej = Ne-2;
 elem[e].ek = Ne-1;
 elem[e].sj = Ns-3;
 elem[e].sk = Ns-1;

 if(side[si].a==i) {side[si].a=Nn-1; side[si].ea=e;}
 if(side[si].b==i) {side[si].b=Nn-1; side[si].eb=e;}
 
 if(side[sj].a==j) {side[sj].a=Nn-1; side[sj].ea=Ne-2;}
 if(side[sj].b==j) {side[sj].b=Nn-1; side[sj].eb=Ne-2;}
 
 if(side[sk].a==k) {side[sk].a=Nn-1; side[sk].ea=Ne-1;} 
 if(side[sk].b==k) {side[sk].b=Nn-1; side[sk].eb=Ne-1;} 

 if(ej!=-1)
  {if(elem[ej].ei==e) {elem[ej].ei=Ne-2;}
   if(elem[ej].ej==e) {elem[ej].ej=Ne-2;}
   if(elem[ej].ek==e) {elem[ej].ek=Ne-2;}}

 if(ek!=-1)
  {if(elem[ek].ei==e) {elem[ek].ei=Ne-1;}
   if(elem[ek].ej==e) {elem[ek].ej=Ne-1;}
   if(elem[ek].ek==e) {elem[ek].ek=Ne-1;}}

/* Find circumenters for two new elements, 
   and for the one who's segment has changed */
 circles(e);
 circles(Ne-2);
 circles(Ne-1);

 bowyer(Nn-1, spac);

/*-------------------------------------------------+
|  NEW ! Insert boundary conditions for the sides  |
+-------------------------------------------------*/
 for(s=3; s ratio)
      {ratio=max(ratio, elem[e].R/elem[e].r);
       ugly=e;}
    }

/*-------------------------------------------------+
|  Second part of the trick:                       |
|    if non-acceptable element on the boundary is  |
|    found, ignore the elements inside the domain  |
+-------------------------------------------------*/
 if(ugly==OFF)
   for(e=0; e ratio)
	  {ratio=max(ratio, elem[e].R/elem[e].r);
	   ugly=e;}
	}
      }

}
/*-classify----------------------------------------------------------------*/


/*=========================================================================*/
new_node()
/*---------------------------------------------------+
|  This function is very important.                  |
|  It determines the position of the inserted node.  |
+---------------------------------------------------*/
{
 int    s=OFF, n, e;
 double xM, yM, xCa, yCa, p, px, py, q, qx, qy, rhoM, rho_M, d;

 struct nod Ca;

/*-------------------------------------------------------------------------+
|  It's obvious that elements which are near the boundary, will come into  |
|  play first.                                                             |
|                                                                          |
|  However, some attention has to be payed for the case when two accepted  |
|  elements surround the ugly one                                          |
|                                                                          |
|  What if new points falls outside the domain                             |
+-------------------------------------------------------------------------*/
 if(elem[elem[ugly].ei].state==D)    {s=elem[ugly].si; n=elem[ugly].i;}
 if(elem[elem[ugly].ej].state==D)    {s=elem[ugly].sj; n=elem[ugly].j;}
 if(elem[elem[ugly].ek].state==D)    {s=elem[ugly].sk; n=elem[ugly].k;}
 if(side[elem[ugly].si].mark > 0)    {s=elem[ugly].si; n=elem[ugly].i;}
 if(side[elem[ugly].sj].mark > 0)    {s=elem[ugly].sj; n=elem[ugly].j;}
 if(side[elem[ugly].sk].mark > 0)    {s=elem[ugly].sk; n=elem[ugly].k;}
 if(s==OFF) return;

 xM  = 0.5*(node[side[s].c].x + node[side[s].d].x);
 yM  = 0.5*(node[side[s].c].y + node[side[s].d].y);

 Ca.x = elem[ugly].xv;
 Ca.y = elem[ugly].yv;

 p  = 0.5*side[s].s;    /* not checked */

 qx = Ca.x-xM;
 qy = Ca.y-yM;
 q  = sqrt(qx*qx+qy*qy);

 rhoM = 0.577 *  0.5*(node[side[s].c].F + node[side[s].d].F);

 rho_M = min( max( rhoM, p), 0.5*(p*p+q*q)/q );

 if(rho_M < p) d=rho_M;
 else          d=rho_M+sqrt(rho_M*rho_M-p*p); 

/*---------------------------------------------------------------------+
|  The following line check can the new point fall outside the domain. |
|  However, I can't remember how it works, but I believe that it is    |
|  still a weak point of the code, particulary when there are lines    |
|  inside the domain                                                   |
+---------------------------------------------------------------------*/

 if( area(&node[side[s].c], &node[side[s].d], &Ca) *
     area(&node[side[s].c], &node[side[s].d], &node[n]) > 0.0 )
   insert_node(xM + d*qx/q,  yM + d*qy/q, ON, OFF, 0, 0, 0, OFF);
/*
 else
  {
   node[n].x = xM - d*qx/q;
   node[n].y = yM - d*qy/q;
   node[n].mark=6;   
   for(e=0; e=3; T--)
   for(s=0; s1 && dummy[strlen(dummy)-1]=='#') {}
   else if(dummy[0]=='#') {do{fscanf(in,"%c", &dum);} while(dum!='#');}
   else                   {*numb=atoi(dummy); break;} }
}

load_d(FILE *in, double *numb)
{
 char dum, dummy[128];

 for(;;)
  {fscanf(in,"%s", dummy);
   if(dummy[0]=='#' && strlen(dummy)>1 && dummy[strlen(dummy)-1]=='#') {}
   else if(dummy[0]=='#') {do{fscanf(in,"%c", &dum);} while(dum!='#');}
   else                   {*numb=atof(dummy); break;} }
}

load_s(FILE *in, char *string)
{
 char dum, dummy[128];

 for(;;)
  {fscanf(in,"%s", dummy);
   if(dummy[0]=='#' && strlen(dummy)>1 && dummy[strlen(dummy)-1]=='#') {}
   else if(dummy[0]=='#') {do{fscanf(in,"%c", &dum);} while(dum!='#');}
   else                   {strcpy(string, dummy); break;} }
}
/*-------------------------------------------------------------------------*/


/*=========================================================================*/
load()
{
 int  c, n, s, Fl, M, N0, chains, bound;
 char dummy[80];
 double xmax=-GREAT, xmin=+GREAT, ymax=-GREAT, ymin=+GREAT, xt, yt, gab;

 FILE *in;

 int m;
 double xO, yO, xN, yN, xC, yC, L, Lx, Ly, dLm, ddL, L_tot;
 
 int *inserted;

/*----------+
|           |
|  Loading  |
|           |
+----------*/
 if((in=fopen(name, "r"))==NULL)
  {fprintf(stderr, "Cannot load file %s !\n", name);
   return 1;}

 load_i(in, &Nc);
 inserted=(int *) calloc(Nc, sizeof(int)); 
 for(n=0; n L ) &&
       (segment[s].n0 != segment[s].n1) )
    {point[segment[s].n0].F = min(point[segment[s].n0].F,L);
     point[segment[s].n1].F = min(point[segment[s].n1].F,L);}
  }

/*-------------------------------------+
   counting the nodes on each segment
+-------------------------------------*/
 for(s=0; s point[segment[s].n1].F)
	{M=-segment[s].N/2; ddL=(point[segment[s].n1].F-dLm)/M;}
       else
	{M=+segment[s].N/2; ddL=(dLm-point[segment[s].n0].F)/M;}
      }

/*=================
*  middle points  *
=================*/
     L_tot=0;
     if(point[segment[s].n0].F + point[segment[s].n1].F <= L)
       for(m=1; m point[segment[s].n1].F)
	  {M++; if(M==0 && segment[s].N%2==0) M++;}
	 else
	  {M--; if(M==0 && segment[s].N%2==0) M--;}

	 if(s==chain[c].s1 && m==(abs(segment[s].N)-1))
	  {insert_node(xO+Lx/L*L_tot, yO+Ly/L*L_tot, OFF,
	   Nn-1, segment[s].mark, segment[s].mark, segment[s].mark, point[segment[s].n1].new_numb);
	   node[Nn-1].next = Nn;}
	 
	 else if(m==1)
	  {insert_node(xO+Lx/L*L_tot, yO+Ly/L*L_tot, OFF,
	   point[segment[s].n0].new_numb, segment[s].mark, segment[s].mark, OFF, OFF);
	   node[Nn-1].next = Nn;}

	 else
	  {insert_node(xO+Lx/L*L_tot, yO+Ly/L*L_tot, OFF,
	   Nn-1, segment[s].mark, segment[s].mark, OFF, OFF);
	   node[Nn-1].next = Nn;}

	 node[Nn-1].chain    = segment[s].chain;
	 node[Nn-1].F        = 0.5*(node[Nn-2].F + (dLm-M*ddL));
	}

/*==============
*  last point  * -> just for the inside chains
==============*/
     if( (point[segment[s].n1].new_numb == OFF) && (s==chain[c].s1) )
      {
       insert_node(xN, yN, OFF,
       Nn-1, segment[s].mark, point[segment[s].n1].mark, OFF, OFF);
       node[Nn-1].next     = OFF;
       node[Nn-1].chain    = segment[s].chain;
       node[Nn-1].F        = point[segment[s].n1].F;
      }

     if( chain[c].type==CLOSED && s==chain[c].s1)
       node[Nn-1].next     = point[segment[chain[c].s0].n0].new_numb;

     if( chain[c].type==OPEN && s==chain[c].s1)
       node[Nn-1].next     = OFF;
    }
  }

 free(segment);
 free(inserted);

 return 0;
}
/*-load--------------------------------------------------------------------*/


/*=========================================================================*/
save()
{
 int  e, s, n, r_Nn=0, r_Ns=0, r_Ne=0;

 struct nod *r_node;
 struct ele *r_elem;
 struct sid *r_side;

 FILE *out;
 
 r_node=(struct nod *) calloc(Nn, sizeof(struct nod));
 r_elem=(struct ele *) calloc(Ne, sizeof(struct ele));
 r_side=(struct sid *) calloc(Ns, sizeof(struct sid));
 if(r_side==NULL)
  {fprintf(stderr, "Sorry, cannot allocate enough memory !\n");
   return 1;}

 for(n=0; n0) /* It means, side is on the boundary */
    {
     xc=node[side[s].c].x; yc=node[side[s].c].y;
     xd=node[side[s].d].x; yd=node[side[s].d].y;
     line_dxf(xc, yc, 0, xd, yd, 0, "boundary");
    }
 
/*----------------+
|  Draw Delaunay  |
+----------------*/
 for(s=0; s0) /* It means, side is on the boundary */
    {
     xc=node[side[s].c].x; yc=node[side[s].c].y;
     xd=node[side[s].d].x; yd=node[side[s].d].y;
     line_fig ( 450+(int)floor(scl*xc), 450+(int)floor(scl*yc), 
		450+(int)floor(scl*xd), 450+(int)floor(scl*yd), 
		0, 3, 0, 0.000);
    }
 
/*----------------+
|  Draw Delaunay  |
+----------------*/
 for(s=0; s
#define B_CIRCLE(x1, y1, x2, y2)  _ellipse(_GBORDER,       x1, y1, x2, y2)
#define I_CIRCLE(x1, y1, x2, y2)  _ellipse(_GFILLINTERIOR, x1, y1, x2, y2)
#define CLEARSCREEN               _clearscreen(_GCLEARSCREEN)
#define CLOSEGRAPH                _setvideomode(_DEFAULTMODE)
#define COLOR(b)                  _setcolor(b)
#define FILL(x1, y1, color)       _floodfill(x1, y1, color)
#define GRTEXT(x1, y1, string)    _moveto(x1, y1); _outgtext(string)
#define LINE(x1, y1, x2, y2)      _moveto(x1, y1); _lineto(x2,y2)
#define OPEN_SVGA                 _setvideomode(_SVRES256COLOR)
#define OPEN_VGA                  _setvideomode(_VRES16COLOR)
#define RECTANGLE(x1, y1, x2, y2) _rectangle(_GBORDER, x1, y1, x2, y2)
/*------------------------------------------------------------------------*/


/*=========================================================================*/
draw(int mesh, int voronoi, int marks, int fill)
{
 int    e, n, s, X0, Y0, ei, ej, ek, ea, eb;
 double scl, x, y, xc, yc, xd, yd, x1, y1, x2, y2,
	xmax=-GREAT, xmin=+GREAT, ymax=-GREAT, ymin=+GREAT;
 char   numb[80];

 for(n=0; n0) /* It means, side is on the boundary */
    {
     if(marks==ON) COLOR(16-side[s].mark);
     else          COLOR(15);

     xc=node[side[s].c].x; yc=node[side[s].c].y;
     xd=node[side[s].d].x; yd=node[side[s].d].y;
   
     LINE(xc*scl + X0, -yc*scl + Y0, xd*scl + X0, -yd*scl + Y0);
    }
 
 if(marks==ON)
   for(n=0; n0)  /* node is on the boundary */
      {
       COLOR(16-node[n].mark);
       x=node[n].x; y=node[n].y;
       I_CIRCLE(x*scl+X0+2, -y*scl+Y0+2, x*scl+X0-2, -y*scl+Y0-2);
      }
    }

 if(voronoi!=OFF)
  {
   if(voronoi==ON) COLOR(7);
   else            COLOR(voronoi);

   for(s=0; s  []");
   printf("\n\n***************");
   printf("\n*** OPTIONS ***");
   printf("\n***************");
   printf("\n\nValid options are:");
   printf("\n   -d        don't triangulate domain");
   printf("\n   -g        without graphic output");
   printf("\n   -m        without messages");
   printf("\n   -r        without relaxation");
   printf("\n   -s        without Laplacian smoothing");
   printf("\n   +dxf      create drawing in DXF format");
   printf("\n   +fig      create drawing in fig format");
   printf("\n   +example  create example input file");
   printf("\n\n*************");
   printf("\n*** INPUT ***");
   printf("\n*************");
   printf("\n\nInput file (NAME.d) has the following format");
   printf("\n  first line:          ");
   printf("\n  following Nbp lines:     ");
   printf("\n  one line:            ");
   printf("\n  following Nbs lines:    ");
   printf("\n\n  where:");
   printf("\n    Nbn     is the number of points defining the boundary");
   printf("\n    Nbp     is the number of sides defining the boundary");
   printf("\n    marker  is the boundary condition marker");
   printf("\n\nNote: Input file has to end with the extension: .d !");
   printf("\n\n**************");
   printf("\n*** OUTPUT ***");
   printf("\n**************");
   printf("\n\nEasyMesh produces the following three output files:");
   printf("\n  NAME.n");
   printf("\n  NAME.e");
   printf("\n  NAME.s");
   printf("\n\nNode file (NAME.n) has the following format:");
   printf("\n  first line:         ");
   printf("\n  following Nn lines:     ");
   printf("\n  last two lines:     comments inserted by the program ");
   printf("\n\n  where:");
   printf("\n  Nn      is the number of nodes");
   printf("\n  x, y    are the node coordinates");
   printf("\n  marker  is the node boundary marker");
   printf("\n\nElement file (NAME.e) has the following format:");
   printf("\n  first line           ");
   printf("\n  following Ne lines:              ");
   printf("\n  last two lines:     comments inserted by the program ");
   printf("\n\n  where:");
   printf("\n    Ne          is the number of elements");
   printf("\n    i,   j,  k  are the nodes belonging to the element, ");
   printf("\n    ei, ej, ek  are the neighbouring elements,");
   printf("\n    si, sj, sk  are the element sides. ");
   printf("\n    xV, yV      are the coordinates of the element circumcenter");
   printf("\n    marker      is the side boundary marker");
   printf("\n\nSide file (NAME.s) has the following format:");
   printf("\n  first line:          ");
   printf("\n  following Ns lines:       "); 
   printf("\n  last two lines:     comments inserted by the program ");
   printf("\n\n  where:");
   printf("\n    Ns      is the number of sides");
   printf("\n    c,  d   are the starting and ending node of the side,");
   printf("\n    ea, eb  are the elements on the left and on the right of the side.");
   printf("\n\nNote: If eb equals to -1, it means that the right element does not exists,");
   printf("\n      i.e. the side is on the boundary !");  
   printf("\n\n");
   
   return 0;}
 else
  {if(strcmp(argv[1], "+example")==0) exa=ON;
   strcpy(name,     argv[1]);
   len=strlen(name);
   if(name[len-2]=='.')
     if(name[len-1]=='d' || name[len-1]=='D' )
       name[len-2]='\0';
   strcpy(dxf_name, name); strcat(dxf_name, ".dxf"); 
   strcpy(fig_name, name); strcat(fig_name, ".fig");}

/*-----------------------+
|  command line options  |
+-----------------------*/
 for(arg=2; arg EasyMesh example +fig");
     fprintf(out, "\n ");
     fprintf(out, "\n  if you want to see the results with xfig,");
     fprintf(out, "\n  or with");
     fprintf(out, "\n");
     fprintf(out, "\n  > EasyMesh example +dxf");
     fprintf(out, "\n");
     fprintf(out, "\n  if you want to see the results with some tool that");
     fprintf(out, "\n  suports Autodesk DXF format");
     fprintf(out, "\n");
     fprintf(out, "\n*******************************************************#");
     fprintf(out, "\n");
     fprintf(out, "\n#*********");
     fprintf(out, "\n  POINTS");
     fprintf(out, "\n*********#");
     fprintf(out, "\n8 # number of points defining the boundary #");
     fprintf(out, "\n");
     fprintf(out, "\n# rectangular domain #");
     fprintf(out, "\n#-------+-----+-----+---------+--------#");
     fprintf(out, "\n# point |  x  |  y  | spacing | marker #");
     fprintf(out, "\n#-------+-----+-----+---------+--------#"); 
     fprintf(out, "\n   0:     0.0   0.0    0.05       1");
     fprintf(out, "\n   1:     2.0   0.0    0.25       2");
     fprintf(out, "\n   2:     2.0   1.6    0.25       2");
     fprintf(out, "\n   3:     0.0   1.6    0.1        1");
     fprintf(out, "\n");
     fprintf(out, "\n# square hole #");
     fprintf(out, "\n#-------+-----+-----+---------+--------#");
     fprintf(out, "\n# point |  x  |  y  | spacing | marker #");
     fprintf(out, "\n#-------+-----+-----+---------+--------#"); 
     fprintf(out, "\n   4:     0.5   0.5    0.05       3");
     fprintf(out, "\n   5:     0.5   1.1    0.08       3");
     fprintf(out, "\n   6:     1.1   1.1    0.2        3");
     fprintf(out, "\n   7:     1.1   0.5    0.2        3");
     fprintf(out, "\n");
     fprintf(out, "\n#***********");
     fprintf(out, "\n  SEGMENTS");
     fprintf(out, "\n***********#");
     fprintf(out, "\n8 # number of segments #");
     fprintf(out, "\n");
     fprintf(out, "\n# domain #");
     fprintf(out, "\n#---------+-----+-----+--------#");
     fprintf(out, "\n# segment | 1st | 2nd | marker #");
     fprintf(out, "\n#---------+-----+-----+--------#");    
     fprintf(out, "\n     0:      0     1      1");
     fprintf(out, "\n     1:      1     2      2");
     fprintf(out, "\n     2:      2     3      1");
     fprintf(out, "\n     3:      3     0      1");
     fprintf(out, "\n");
     fprintf(out, "\n# hole #");
     fprintf(out, "\n#---------+-----+-----+--------#");
     fprintf(out, "\n# segment | 1st | 2nd | marker #");
     fprintf(out, "\n#---------+-----+-----+--------#");
     fprintf(out, "\n     4:      4     5      3");
     fprintf(out, "\n     5:      5     6      3");
     fprintf(out, "\n     6:      6     7      3");
     fprintf(out, "\n     7:      7     4      3\n");
     printf("\nThe file 'example.d' created !\n");
     fclose(out);
     return 0;
    }
  }

 strcat(name, ".d");
 len=strlen(name);

 if(load()!=0)
   return 1;
 erase();
 classify();

 if(m==ON)
   printf("Working.  Please wait !\n"); fflush(stdout);

 if(d==ON)
   do
    {
     Nn0=Nn;
     new_node();
     classify();
     if(Nn==MAX_NODES-1) break;
     if(Nn==Nn0) break;
    }
   while(ugly!=OFF);

 neighbours();
 
 if(r==ON || s==ON)
   if(m==ON)
     printf("Improving the grid quality.  Please wait !\n"); fflush(stdout);
 if(r==ON)           relax();
 if(r==ON || s==ON) smooth();

 if(m==ON)
   printf("Renumerating nodes, elements and sides. Please wait !\n"); fflush(stdout);
 renum();

 if(m==ON)
   printf("Processing material marks. Please wait !\n"); fflush(stdout);
 materials();

#if GRAPHICS == ON
 if(g==ON)
  {
   do
    {
     printf("\n****************************");
     printf("\n**   Enter your choice:   **");
     printf("\n****************************\n\n");
     printf("0. Exit\n");
     printf("1. Delaunay\n");
     printf("2. Voronoi\n");
     printf("3. Delaunay and Voronoi\n");
     printf("4. Materials\n");
     printf("5. Boundary condition marks only\n");
     printf("6. Boundary condition marks with Delaunay\n");
     printf("7. Boundary condition marks with Voronoi\n\n");

     printf("-> "); scanf("%d", &ans);

     switch(ans)
      {
       case 1: OPEN_SVGA; draw(11,  OFF, OFF, OFF); printf("Press any key to continue !"); fflush(stdout); getch(); CLOSEGRAPH; break;
       case 2: OPEN_SVGA; draw(OFF, 12,  OFF, OFF); printf("Press any key to continue !"); fflush(stdout); getch(); CLOSEGRAPH; break;
       case 3: OPEN_SVGA; draw(11,  12,  OFF, OFF); printf("Press any key to continue !"); fflush(stdout); getch(); CLOSEGRAPH; break;
       case 4: OPEN_SVGA; draw(ON,  OFF, OFF, ON ); printf("Press any key to continue !"); fflush(stdout); getch(); CLOSEGRAPH; break;
       case 5: OPEN_SVGA; draw(OFF, OFF, ON,  OFF); printf("Press any key to continue !"); fflush(stdout); getch(); CLOSEGRAPH; break;
       case 6: OPEN_SVGA; draw(ON,  OFF, ON,  OFF); printf("Press any key to continue !"); fflush(stdout); getch(); CLOSEGRAPH; break;
       case 7: OPEN_SVGA; draw(OFF, ON,  ON,  OFF); printf("Press any key to continue !"); fflush(stdout); getch(); CLOSEGRAPH; break;
      }
    }
   while(ans!=0);
  }
#endif

 save();

 if(dxf==ON)
  {start_dxf(); draw_dxf(); end_dxf();}

 if(fig==ON)
  {start_fig(); draw_fig(); end_fig();}

 return 1;
}