/*****************************************************/
/* ShellyV1.5: The ShellShapeGenerator by:           */
/*         RANDi                                     */
/*              (rschultz@informatik.uni-rostock.de) */
/*****************************************************/

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>

#include "shelly.h"

int countw = 0, counth = 0, countp = 0, countl = 0, countt = 0;
double camx = 0, camy = 500, camz = 500;
int camposspecified = NO;
struct lmerk *bigllist;
struct tmerk *bigtlist;

/********************************************/
/*cot:                                      */
/********************************************/
double
cot (double in)
{
  if (sin (in) == 0)
    return (0);
  else
    return (cos (in) / sin (in));
}


/********************************************/
/*round:                                    */
/********************************************/
double
round (double in)
{
  if (in - floor (in) < 0.5)
    return (floor (in));
  else
    return (floor (in) + 1);
}


/********************************************/
/*myfree:                                   */
/********************************************/
int
myfree (struct punkt *anker1)
{
  struct punkt *hp, *hpnew;
  if (anker1 == NULL)
    return (0);

  hp = anker1;
  hpnew = hp;
  do
    {
      hp = hpnew;
      hpnew = (*hp).next;

      free (hp);
    }
  while (hpnew != NULL);

  return (0);
}


/********************************************/
/*mycopystr:                                */
/********************************************/
char *
mycopystr (char *source, char *destination, char endchar)
{
  int ende = 1;
  char *merk;

  merk = destination;		/* merk points now on destination */
  while (ende)
    {
      if ((*source == '\0') || (*source == endchar))
	{
	  ende = 0;
	}
      else
	{
	  *destination = *source;
	  destination++;
	  source++;
	}			/* if */
    }				/* while */
  *destination = '\0';
  return (merk);
}


/********************************************/
/*filecopy:                                 */
/********************************************/
void
filecopy (FILE * source, FILE * dest)
{
  int a, b;

  fseek (source, 0, 0);
  do
    {
      a = fgetc (source);
      if (a != EOF)
	{
	  b = fputc (a, dest);
	  if (b == EOF)
	    {
	      fclose (source);
	      fclose (dest);
	      exit (5);
	    };			/* if */
	};			/* if */
    }
  while (a != EOF);
}

/********************************************/
/*ReadInfile:                               */
/********************************************/
void
ReadInfile (struct ShellyArguments *ShellyArgs, char *fin)
{
  char readline[laenge], hilf[laenge], *hp;
  FILE *fp;

  /* set some defaults */

  (*ShellyArgs).output = POV;
  (*ShellyArgs).mode = NORMAL;
  (*ShellyArgs).Scano = 0.05;
  (*ShellyArgs).Scans = 0.05;
  (*ShellyArgs).heightdiffo = 0.1;
  (*ShellyArgs).heightdiffs = 0.1;

  (*ShellyArgs).Scale = 1.0;
  (*ShellyArgs).Render = NO;
  (*ShellyArgs).N2 = 0;
  (*ShellyArgs).N3 = 0;
  (*ShellyArgs).N = 0;


  mycopystr ("-f +d +w200 +h160", (*ShellyArgs).povargs, '\0');


  fp = fopen (fin, "r");
  if (fp != NULL)
    {
      fprintf (stdout, "Parsing:");
      while (fgets (readline, laenge, fp) != NULL)
	{
	  fprintf (stdout, ".");

	  hp = strstr (readline, "alpha:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 6, hilf, '\0');
	      (*ShellyArgs).alpha = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "beta:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      (*ShellyArgs).beta = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "phi:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 4, hilf, '\0');
	      (*ShellyArgs).phi = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "my:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).my = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "omega:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 6, hilf, '\0');
	      (*ShellyArgs).omega = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "smin:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      (*ShellyArgs).smin = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "smax:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      (*ShellyArgs).smax = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "sd:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).sd = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "A:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 2, hilf, '\0');
	      (*ShellyArgs).A = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "a:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 2, hilf, '\0');
	      (*ShellyArgs).a = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "b:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 2, hilf, '\0');
	      (*ShellyArgs).b = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "P:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 2, hilf, '\0');
	      (*ShellyArgs).P = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "W1:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).W1 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "W2:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).W2 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "N:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 2, hilf, '\0');
	      (*ShellyArgs).N = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "L:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 2, hilf, '\0');
	      (*ShellyArgs).L = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "omin:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      (*ShellyArgs).omin = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "omax:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      (*ShellyArgs).omax = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "od:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).od = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "Hdo:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 4, hilf, '\0');
	      (*ShellyArgs).heightdiffo = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "Hds:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 4, hilf, '\0');
	      (*ShellyArgs).heightdiffs = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "Scans:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 6, hilf, '\0');
	      (*ShellyArgs).Scans = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "Scano:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 6, hilf, '\0');
	      (*ShellyArgs).Scano = atof (hilf);
	    }			/* if */

	  hp = strstr (readline, "Scale:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 6, hilf, '\0');
	      (*ShellyArgs).Scale = atof (hilf);
	    }			/* if */

	  hp = strstr (readline, "POV");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).output = POV;
	    }			/* if */
	  hp = strstr (readline, "RPL");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).output = RPL;
	    }			/* if */
	  hp = strstr (readline, "T3D");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).output = T3D;
	    }			/* if */
	  hp = strstr (readline, "RAW");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).output = RAW;
	    }			/* if */
	  hp = strstr (readline, "X3D");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).output = X3D;
	    }			/* if */

	  hp = strstr (readline, "NORMAL");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).mode = NORMAL;
	    }			/* if */
	  hp = strstr (readline, "NODULE");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).mode = NODULE;
	    }			/* if */
	  hp = strstr (readline, "NEWNOD");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).mode = NEWNOD;
	    }			/* if */
	  hp = strstr (readline, "RENDER");
	  if (hp != NULL)
	    {
	      (*ShellyArgs).Render = YES;
	    }			/* if */

	  hp = strstr (readline, "POVARGS:");
	  if (hp != NULL)
	    mycopystr (hp + 8, (*ShellyArgs).povargs, '\n');

	  hp = strstr (readline, "P2:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).P2 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "W12:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 4, hilf, '\0');
	      (*ShellyArgs).W12 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "W22:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 4, hilf, '\0');
	      (*ShellyArgs).W22 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "N2:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).N2 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "L2:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).L2 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "P3:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).P3 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "W13:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 4, hilf, '\0');
	      (*ShellyArgs).W13 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "W23:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 4, hilf, '\0');
	      (*ShellyArgs).W23 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "N3:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).N3 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "L3:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 3, hilf, '\0');
	      (*ShellyArgs).L3 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "Off2:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      (*ShellyArgs).Off2 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "Off3:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      (*ShellyArgs).Off3 = atof (hilf);
	    }			/* if */
	  hp = strstr (readline, "camx:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      camx = atof (hilf);
	      camposspecified = YES;
	    }			/* if */
	  hp = strstr (readline, "camy:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      camy = atof (hilf);
	      camposspecified = YES;
	    }			/* if */
	  hp = strstr (readline, "camz:");
	  if (hp != NULL)
	    {
	      mycopystr (hp + 5, hilf, '\0');
	      camz = atof (hilf);
	      camposspecified = YES;
	    }			/* if */

	}			/* while */

      fprintf (stdout, "\n");
      if (fclose (fp) != 0)
	fprintf (stdout, "Error while closing file: %s!\n", fin);
    }
  else
    {
      fprintf (stdout, "Could not open datafile: %s!\n", fin);
      exit (5);
    }
}				/* ReadInfile */


/********************************************/
/* triangulate:                             */
/*                                          */
/********************************************/
int
triangulate (struct punkt *list1, struct punkt *list2, struct triangle **result)
{
  struct punkt *p11, *p12, *p21, *p22;
  struct triangle *tp, *tp2, *anker = NULL;
  int ende = 1;

  if ((list1 == NULL) || (list2 == NULL))
    return (5);

  p11 = list1;
  p21 = list2;

  while (ende)
    {
      p12 = p11->next;
      p22 = p21->next;


      if ((p11->next == NULL) && (p21->next == NULL))
	ende = 0;
      else if (p11->next == NULL)
	{
	  tp = calloc (1, sizeof (struct triangle));
	  if (tp != NULL)
	    {
	      tp->p1 = p21;
	      tp->p2 = p22;
	      tp->p3 = p11;
	      if (anker == NULL)
		anker = tp;
	      else
		tp2->next = tp;
	      tp2 = tp;
	    }
	  p21 = p22;
	}
      else if (p21->next == NULL)
	{
	  tp = calloc (1, sizeof (struct triangle));
	  if (tp != NULL)
	    {
	      tp->p1 = p11;
	      tp->p2 = p21;
	      tp->p3 = p12;
	      if (anker == NULL)
		anker = tp;
	      else
		tp2->next = tp;
	      tp2 = tp;
	    }
	  p11 = p12;
	}
      else if (p11->s == p21->s)
	{
	  if (fabs (p11->s - p12->s) < fabs (p21->s - p22->s))
	    {
	      tp = calloc (1, sizeof (struct triangle));
	      if (tp != NULL)
		{
		  tp->p1 = p11;
		  tp->p2 = p21;
		  tp->p3 = p12;
		  if (anker == NULL)
		    anker = tp;
		  else
		    tp2->next = tp;
		  tp2 = tp;
		}
	      p11 = p12;
	    }
	  else
	    {
	      tp = calloc (1, sizeof (struct triangle));
	      if (tp != NULL)
		{
		  tp->p1 = p21;
		  tp->p2 = p22;
		  tp->p3 = p11;
		  if (anker == NULL)
		    anker = tp;
		  else
		    tp2->next = tp;
		  tp2 = tp;
		}
	      p21 = p22;
	    }
	}
      else if (p11->s < p21->s)
	{
	  tp = calloc (1, sizeof (struct triangle));
	  if (tp != NULL)
	    {
	      tp->p1 = p11;
	      tp->p2 = p21;
	      tp->p3 = p12;
	      if (anker == NULL)
		anker = tp;
	      else
		tp2->next = tp;
	      tp2 = tp;
	    }
	  p11 = p12;

	}
      else if (p11->s > p21->s)
	{
	  tp = calloc (1, sizeof (struct triangle));
	  if (tp != NULL)
	    {
	      tp->p1 = p21;
	      tp->p2 = p22;
	      tp->p3 = p11;
	      if (anker == NULL)
		anker = tp;
	      else
		tp2->next = tp;
	      tp2 = tp;
	    }
	  p21 = p22;

	}			/* big if-cascade ;) */

    }				/* while */

  *result = anker;
  return (0);

}				/* triangulate */


/********************************************/
/* writepovheader:                          */
/*                                          */
/********************************************/
void
writepovheader (FILE * fp)
{

  fprintf (fp, "/* POV-Scenefile generated by Shelly1.5           */\n");
  fprintf (fp, "/* by RANDi: (rschultz@informatik.uni-rostock.de) */\n");

  fprintf (fp, "#declare te = pigment { color red 1 green 0 blue 0 }\n");

  fprintf (fp, "camera\n{\n location  <%.1f,%.1f,%.1f>\n", camx, camy, camz);
  fprintf (fp, " look_at <0, 0, 0>\n}\n");

  fprintf (fp, "object\n{\n light_source {\n");
  fprintf (fp, "  <250, 500, 500> color red 1 green 1 blue 1\n }\n");
  fprintf (fp, "}\n");
  fprintf (fp, "object\n{\n light_source {\n");
  fprintf (fp, "  <-250, 500, 500> color red 1 green 1 blue 1\n }\n");
  fprintf (fp, "}\n");

}				/* writepovheader */


/********************************************/
/* writepovtriangles:                       */
/********************************************/
int
writepovtriangles (FILE * fp, struct punkt *anker1, struct punkt *anker2, int mode)
{
  struct punkt *p11, *p12, *p21, *p22;
  struct triangle *tp, *tp1, *tp2;

  if ((anker1 == NULL) || (anker2 == NULL))
    return (0);

  if (mode == 1)
    {
      triangulate (anker1, anker2, &tp);

      tp1 = tp;
      while (tp1 != NULL)
	{

	  fprintf (fp, "triangle{<%.2f,%.2f,%.2f><%.2f,%.2f,%.2f><%.2f,%.2f,%.2f>\n", tp1->p1->x, tp1->p1->y, tp1->p1->z, tp1->p2->x, tp1->p2->y, tp1->p2->z, tp1->p3->x, tp1->p3->y, tp1->p3->z);
	  fprintf (fp, "pigment{te}}\n");

	  tp2 = tp1->next;

	  free (tp1);

	  tp1 = tp2;
	}			/* while */

      return (0);
    };


  p11 = anker1;
  p12 = p11;
  p21 = anker2;
  p22 = p21;

  do
    {
      p11 = p12;
      p21 = p22;
      p12 = (*p11).next;
      p22 = (*p21).next;

      if ((p12 != NULL) && (p22 != NULL))
	{
	  fprintf (fp, "triangle{<%.2f,%.2f,%.2f><%.2f,%.2f,%.2f><%.2f,%.2f,%.2f>\n", (*p11).x, (*p11).y, (*p11).z, (*p12).x, (*p12).y, (*p12).z, (*p21).x, (*p21).y, (*p21).z);
	  fprintf (fp, "pigment{te}}\n");

	  fprintf (fp, "triangle{<%.2f,%.2f,%.2f><%.2f,%.2f,%.2f><%.2f,%.2f,%.2f>\n", (*p21).x, (*p21).y, (*p21).z, (*p12).x, (*p12).y, (*p12).z, (*p22).x, (*p22).y, (*p22).z);
	  fprintf (fp, "pigment{te}}\n");
	}
    }
  while ((p12 != NULL) && (p22 != NULL));

  return (0);
}				/* writepovtriangles */


/********************************************/
/* writepovfinish:                          */
/********************************************/
void
writepovfinish (FILE * fptemp, FILE * fp)
{

  filecopy (fptemp, fp);

}


/********************************************/
/* writerplline:                            */
/********************************************/
int
writerplline (FILE * fp, struct punkt *anker1, struct punkt *anker2, int mode)
{
  struct punkt *p11, *p12;
  struct triangle *tp1, *tp2, *tp;

  if (mode == 1)
    {
      triangulate (anker1, anker2, &tp);

      tp1 = tp;
      while (tp1 != NULL)
	{
	  fprintf (fp, "%.3f %.3f %.3f\n%.3f %.3f %.3f\n%.3f %.3f %.3f\n", tp1->p1->x / 100.0, tp1->p1->y / 100.0, tp1->p1->z / 100.0, tp1->p2->x / 100.0, tp1->p2->y / 100.0, tp1->p2->z / 100.0, tp1->p3->x / 100.0, tp1->p3->y / 100.0, tp1->p3->z / 100.0);
	  fprintf (fp, "0 0 0\n3\n0 0 255 0\n\"Triangle\"\n0\n\"CEND\"\nC_POLYGON DROP\n");

	  tp2 = tp1->next;

	  free (tp1);

	  tp1 = tp2;
	}			/* while */

      return (0);
    };

  if (anker1 == NULL)
    return (0);

  p11 = anker1;
  p12 = p11;

  countw++;			/* calc number of lines created */

  fprintf (fp, "%.3f  %.3f  %.3f\n", (*p11).x / 100.0, (*p11).y / 100.0, (*p11).z / 100.0);

  do
    {
      p11 = p12;
      p12 = (*p11).next;

      if (p12 != NULL)
	{
	  fprintf (fp, "%.3f  %.3f  %.3f\n", (*p12).x / 100.0, (*p12).y / 100.0, (*p12).z / 100.0);
	}
    }
  while (p12 != NULL);

  return (0);
}				/* writerplline */


/********************************************/
/* writerplfinish:                          */
/*                                          */
/********************************************/
void
writerplfinish (FILE * fptemp, FILE * fp, int mode)
{

  filecopy (fptemp, fp);

  if (mode == 0)
    {
      fprintf (fp, "%d\n", counth);	/* height width of the mesh */
      fprintf (fp, "%d\n", countw);

      fprintf (fp, "3\n0\n255 255 255 0\n");	/* RGBA */
      fprintf (fp, "\"Shell\"\n0\n");	/* Name */
      fprintf (fp, "\"CEND\"\n");
      fprintf (fp, "C_MESH DROP\n");
    }				/* if */
}				/* writerplfinish */

/********************************************/
/* writex3dheader:                          */
/*                                          */
/********************************************/
void
writex3dheader (FILE * fp)
{

  fprintf (fp, "2\n");		/* Number of Colors */
  fprintf (fp, "0  0 0 0\n");	/* Color 0 Black */
  fprintf (fp, "1  255 0 0\n");	/* Color 1 Red */

}				/* writex3dheader */


/********************************************/
/* new_pnode:                               */
/*                                          */
/********************************************/
void
new_pnode (struct pmerk **anker, struct punkt *p1)
{
  struct pmerk *mp;

  if ((mp = calloc (1, sizeof (struct pmerk))) != NULL)
    {
      mp->x = p1->x;
      mp->y = p1->y;
      mp->z = p1->z;
      mp->id = countp;
      mp->next = *anker;
      *anker = mp;
    }
  else
    return;

}				/* new_pnode */

/********************************************/
/* free_pmerk_list:                         */
/*                                          */
/********************************************/
void
free_pmerk_list (struct pmerk *anker)
{
  struct pmerk *mp1 = anker, *mp2;

  while (mp1 != NULL)
    {
      mp2 = mp1->next;
      free (mp1);
      mp1 = mp2;
    }				/* while */

}				/* free_pmerk_list */

/********************************************/
/* is_p_in:                                 */
/*                                          */
/********************************************/
int
is_p_in (struct pmerk *anker, struct punkt *p)
{
  struct pmerk *mp1 = anker, *mp2;

  while (mp1 != NULL)
    {
      if (mp1->x == p->x)
	if (mp1->y == p->y)
	  if (mp1->z == p->z)
	    return (mp1->id);

      mp2 = mp1->next;
      mp1 = mp2;
    }
  return (0);
}				/* is_p_in */


/********************************************/
/* new_lnode:                               */
/*                                          */
/********************************************/
void
new_lnode (struct lmerk **anker, int id1, int id2)
{
  struct lmerk *lp, *lp1 = *anker, *lp2;

  if (lp1 == NULL)
    {
      if ((lp = calloc (1, sizeof (struct lmerk))) != NULL)
	{
	  lp->id1 = id1;
	  lp->id2 = id2;
	  lp->id = countl;
	  *anker = lp;
	}
      else
	return;
    }

  while (lp1 != NULL)
    {
      lp2 = lp1->next;
      if (lp2 == NULL)
	if ((lp = calloc (1, sizeof (struct lmerk))) != NULL)
	  {
	    lp->id1 = id1;
	    lp->id2 = id2;
	    lp->id = countl;
	    lp1->next = lp;
	  }
	else
	  return;

      lp1 = lp2;
    }

}				/* new_lnode */


/********************************************/
/* app_llist:                               */
/*                                          */
/********************************************/
void
app_llist (struct lmerk *anker, struct lmerk *list)
{
  struct lmerk *lp1 = anker, *lp2;

  while (lp1 != NULL)
    {
      lp2 = lp1->next;
      if (lp2 == NULL)
	lp1->next = list;
      lp1 = lp2;
    }
  return;
}				/* app_llist */

/********************************************/
/* free_lmerk_list:                         */
/*                                          */
/********************************************/
void
free_lmerk_list (struct lmerk *anker)
{
  struct lmerk *mp1 = anker, *mp2;

  while (mp1 != NULL)
    {
      mp2 = mp1->next;
      free (mp1);
      mp1 = mp2;
    }				/* while */

}				/* free_lmerk_list */

/********************************************/
/* is_l_in:                                 */
/*                                          */
/********************************************/
int
is_l_in (struct lmerk *anker, int id1, int id2)
{
  struct lmerk *mp1 = anker, *mp2;

  while (mp1 != NULL)
    {
      if (mp1->id1 == id1)
	if (mp1->id2 == id2)
	  return (mp1->id);

      if (mp1->id2 == id1)
	if (mp1->id1 == id2)
	  return (mp1->id);

      mp2 = mp1->next;
      mp1 = mp2;
    }
  return (0);
}				/* is_l_in */


/********************************************/
/* new_tnode:                               */
/*                                          */
/********************************************/
void
new_tnode (struct tmerk **anker, int id1, int id2, int id3)
{
  struct tmerk *tp, *tp1 = *anker, *tp2;
  if (tp1 == NULL)
    if ((tp = calloc (1, sizeof (struct tmerk))) != NULL)
      {
	tp->lid1 = id1;
	tp->lid2 = id2;
	tp->lid3 = id3;
	*anker = tp;
      }
    else
      return;
  while (tp1 != NULL)
    {
      tp2 = tp1->next;
      if (tp2 == NULL)
	if ((tp = calloc (1, sizeof (struct tmerk))) != NULL)
	  {
	    tp->lid1 = id1;
	    tp->lid2 = id2;
	    tp->lid3 = id3;
	    tp1->next = tp;
	  }
	else
	  return;
      tp1 = tp2;
    }

}				/* new_tnode */

/********************************************/
/* free_tmerk_list:                         */
/*                                          */
/********************************************/
void
free_tmerk_list (struct tmerk *anker)
{
  struct tmerk *tp1 = anker, *tp2;

  while (tp1 != NULL)
    {
      tp2 = tp1->next;
      free (tp1);
      tp1 = tp2;
    }				/* while */

}				/* free_tmerk_list */


/********************************************/
/* writex3dline:                            */
/********************************************/
int
writex3dline (FILE * fp, struct punkt *anker1, struct punkt *anker2, int mode)
{
  struct punkt *p11, *p12;
  struct triangle *tp, *tp1, *tp2;

  static struct pmerk *plist1 = NULL;
  struct pmerk *plist2 = NULL;
  static struct lmerk *llist1 = NULL;
  struct lmerk *llist2 = NULL;

  static int called = 0, count = 0;
  int pid1, pid2, pid3;
  int lid1, lid2, lid3;

  if (mode == 2)
    {
      free_pmerk_list (plist1);
      return (0);
    };

  if (mode == 1)
    {
      triangulate (anker1, anker2, &tp);

      tp1 = tp;
      while (tp1 != NULL)
	{
	  if (((pid1 = is_p_in (plist2, tp1->p1)) == 0) && ((pid1 = is_p_in (plist1, tp1->p1)) == 0))
	    {
	      fprintf (fp, "%d %.3f %.3f %.3f\n", countp, tp1->p1->x, tp1->p1->y, tp1->p1->z);
	      new_pnode (&plist2, tp1->p1);
	      pid1 = countp;
	      countp++;
	    }

	  if (((pid2 = is_p_in (plist2, tp1->p2)) == 0) && ((pid2 = is_p_in (plist1, tp1->p2)) == 0))
	    {
	      fprintf (fp, "%d %.3f %.3f %.3f\n", countp, tp1->p2->x, tp1->p2->y, tp1->p2->z);
	      new_pnode (&plist2, tp1->p2);
	      pid2 = countp;
	      countp++;
	    }

	  if (((pid3 = is_p_in (plist2, tp1->p3)) == 0) && ((pid3 = is_p_in (plist1, tp1->p3)) == 0))
	    {
	      fprintf (fp, "%d %.3f %.3f %.3f\n", countp, tp1->p3->x, tp1->p3->y, tp1->p3->z);
	      new_pnode (&plist2, tp1->p3);
	      pid3 = countp;
	      countp++;
	    }

	  if (((lid1 = is_l_in (llist2, pid1, pid2)) == 0) && ((lid1 = is_l_in (llist1, pid1, pid2)) == 0))
	    {
	      new_lnode (&llist2, pid1, pid2);
	      lid1 = countl;
	      countl++;
	    }

	  if (((lid2 = is_l_in (llist2, pid2, pid3)) == 0) && ((lid2 = is_l_in (llist1, pid2, pid3)) == 0))
	    {
	      new_lnode (&llist2, pid2, pid3);
	      lid2 = countl;
	      countl++;
	    }

	  if (((lid3 = is_l_in (llist2, pid3, pid1)) == 0) && ((lid3 = is_l_in (llist1, pid3, pid1)) == 0))
	    {
	      new_lnode (&llist2, pid3, pid1);
	      lid3 = countl;
	      countl++;
	    }

	  new_tnode (&bigtlist, lid1, lid2, lid3);
	  countt++;

	  tp2 = tp1->next;
	  free (tp1);
	  tp1 = tp2;
	}			/* while */


      free_pmerk_list (plist1);
      plist1 = plist2;

      if (called == 0)
	bigllist = llist2;
      else
	app_llist (llist1, llist2);
      llist1 = llist2;

      called = 1;
      return (0);
    };



  if (anker1 == NULL)
    return (0);

  if (called == 0)
    {
      called = 1;
      count = -1;
      countw = 0;
    }
  countw++;

  p11 = anker1;
  p12 = p11;

  fprintf (fp, "%d  %.3f %.3f %.3f\n", ++count, (*p11).x, (*p11).y, (*p11).z);

  do
    {
      p11 = p12;
      p12 = (*p11).next;

      if (p12 != NULL)
	{
	  fprintf (fp, "%d  %.3f %.3f %.3f\n", ++count, (*p12).x, (*p12).y, (*p12).z);
	}
    }
  while (p12 != NULL);

  return (0);
}				/* writex3dline */

/********************************************/
/* writex3dfinish:                          */
/*                                          */
/********************************************/
void
writex3dfinish (FILE * fptemp, FILE * fp, int mode)
{
  int edges = 0, faces = 0, edgecount = 0, facecount = 0, a = 0, b = 0,
    r = 0, r2 = 0, r3 = 0;
  int point1 = 0, point2 = 0, edge1 = 0, edge2 = 0, edge3 = 0;
  struct tmerk *tp1 = bigtlist, *tp2;
  struct lmerk *lp1 = bigllist, *lp2;

  fprintf (stdout, "\nWriting additional X3D-Data ...");

  fprintf (fp, "%d\n", countp);	/* Number of points */

  filecopy (fptemp, fp);

  if (mode == 1)
    {
      edges = countl;
      fprintf (fp, "%d\n", edges);

      while (lp1 != NULL)
	{
	  fprintf (fp, "%d 1 %d %d\n", edgecount++, lp1->id1, lp1->id2);
	  lp2 = lp1->next;
	  free (lp1);
	  lp1 = lp2;
	}

      faces = countt;
      fprintf (fp, "%d\n", faces);

      while (tp1 != NULL)
	{
	  fprintf (fp, "%d 1 3 %d %d %d\n", facecount++, tp1->lid1, tp1->lid2, tp1->lid3);
	  tp2 = tp1->next;
	  free (tp1);
	  tp1 = tp2;
	}

      return;
    }

  edges = (counth * (countw - 1) + countw * (counth - 1) + (counth - 1) * (countw - 1));
  /* number of edges! */
  fprintf (fp, "%d\n", edges);


  /* write horizontal edges */
  for (a = 0; a < counth; a++)
    {
      r = a;
      for (b = 0; b < (countw - 1); b++)
	{
	  point1 = r;
	  point2 = r + counth;
	  fprintf (fp, "%d  1   %d %d\n", edgecount++, point1, point2);
	  r = r + counth;
	}
    }
  /* write vertical edges */
  for (a = 0; a < countw; a++)
    {
      r = a * counth;
      for (b = 0; b < (counth - 1); b++)
	{
	  point1 = r + b;
	  point2 = r + b + 1;
	  fprintf (fp, "%d  1   %d %d\n", edgecount++, point1, point2);
	}
    }
  /* write diagonal edges */
  for (a = 0; a < counth - 1; a++)
    {
      r = a;
      for (b = 0; b < (countw - 1); b++)
	{
	  point1 = r;
	  point2 = r + counth + 1;
	  fprintf (fp, "%d  1   %d %d\n", edgecount++, point1, point2);
	  r = r + counth;
	}
    }
  /* ohhh boy, THIS (^^^) took me time ! :), now to that faces! */

  /* write faces */

  faces = 2 * (countw - 1) * (counth - 1);

  fprintf (fp, "%d\n", faces);	/* number of faces/polygons */

  r = 0;
  r3 = countw * (counth - 1) + counth * (countw - 1);

  for (a = 0; a < counth - 1; a++)
    {
      r2 = counth * (countw - 1) + a;
      for (b = 0; b < countw - 1; b++)
	{
	  edge1 = r + countw - 1;
	  edge2 = r2;
	  edge3 = r3;
	  fprintf (fp, "%d  1  3  %d %d %d\n", facecount++, edge1, edge2, edge3);

	  edge1 = r;
	  edge2 = r2 + counth - 1;
	  edge3 = r3;
	  fprintf (fp, "%d  1  3  %d %d %d\n", facecount++, edge1, edge2, edge3);

	  r++;
	  r2 = r2 + counth - 1;
	  r3++;
	}
    }


}				/* writex3dfinish */


/********************************************/
/* writet3dheader:                          */
/*                                          */
/********************************************/
void
writet3dheader (FILE * fp)
{
  char percent = '%';

  fprintf (fp, " %c T3Dlib-data-file generated by Shelly1.5\n", percent);
  fprintf (fp, " %c the ShellShapeGenerator by RANDi :    \n", percent);
  fprintf (fp, " %c (rschultz@informatik.uni-rostock.de)\n", percent);

  fprintf (fp, "OBJ Begin \"Hierarchy 1\"\n");
  fprintf (fp, " DESC Begin \"Object 1 at level 1 of hierarchy 1\"\n");
  fprintf (fp, "  NAME \"SHELL\"\n");
  fprintf (fp, "  SHAP Shape = 2\n");
  fprintf (fp, "  SHAP Lamp  = 0\n");
  fprintf (fp, "  POSI X=0 Y=0 Z=0\n");
  fprintf (fp, "  AXIS XAxis X=1 Y=0 Z=0\n");
  fprintf (fp, "  AXIS YAxis X=0 Y=1 Z=0\n");
  fprintf (fp, "  AXIS ZAxis X=0 Y=0 Z=1\n");
  fprintf (fp, "  SIZE X=32 Y=32 Z=32\n");

}				/* writet3dheader */


/********************************************/
/* writet3dline:                            */
/********************************************/
int
writet3dline (FILE * fp, struct punkt *anker1, struct punkt *anker2, int mode)
{
  struct punkt *p11, *p12;
  struct triangle *tp, *tp1, *tp2;
  static int called = 0, count = 0;

  static struct pmerk *plist1 = NULL;
  struct pmerk *plist2 = NULL;
  static struct lmerk *llist1 = NULL;
  struct lmerk *llist2 = NULL;


  int pid1, pid2, pid3;
  int lid1, lid2, lid3;

  if ((anker1 == NULL) && (anker2 == NULL))
    return (5);

  if (mode == 2)
    {
      free_pmerk_list (plist1);
      return (0);
    };

  if (mode == 1)
    {
      triangulate (anker1, anker2, &tp);

      tp1 = tp;
      while (tp1 != NULL)
	{
	  if (((pid1 = is_p_in (plist2, tp1->p1)) == 0) && ((pid1 = is_p_in (plist1, tp1->p1)) == 0))
	    {
	      fprintf (fp, "  PNTS Point[%d] X=%.3f Y=%.3f Z=%.3f\n", countp, tp1->p1->x, tp1->p1->y, tp1->p1->z);
	      new_pnode (&plist2, tp1->p1);
	      pid1 = countp;
	      countp++;
	    }

	  if (((pid2 = is_p_in (plist2, tp1->p2)) == 0) && ((pid2 = is_p_in (plist1, tp1->p2)) == 0))
	    {
	      fprintf (fp, "  PNTS Point[%d] X=%.3f Y=%.3f Z=%.3f\n", countp, tp1->p2->x, tp1->p2->y, tp1->p2->z);
	      new_pnode (&plist2, tp1->p2);
	      pid2 = countp;
	      countp++;
	    }

	  if (((pid3 = is_p_in (plist2, tp1->p3)) == 0) && ((pid3 = is_p_in (plist1, tp1->p3)) == 0))
	    {
	      fprintf (fp, "  PNTS Point[%d] X=%.3f Y=%.3f Z=%.3f\n", countp, tp1->p3->x, tp1->p3->y, tp1->p3->z);
	      new_pnode (&plist2, tp1->p3);
	      pid3 = countp;
	      countp++;
	    }

	  if (((lid1 = is_l_in (llist2, pid1, pid2)) == 0) && ((lid1 = is_l_in (llist1, pid1, pid2)) == 0))
	    {
	      new_lnode (&llist2, pid1, pid2);
	      lid1 = countl;
	      countl++;
	    }

	  if (((lid2 = is_l_in (llist2, pid2, pid3)) == 0) && ((lid2 = is_l_in (llist1, pid2, pid3)) == 0))
	    {
	      new_lnode (&llist2, pid2, pid3);
	      lid2 = countl;
	      countl++;
	    }

	  if (((lid3 = is_l_in (llist2, pid3, pid1)) == 0) && ((lid3 = is_l_in (llist1, pid3, pid1)) == 0))
	    {
	      new_lnode (&llist2, pid3, pid1);
	      lid3 = countl;
	      countl++;
	    }

	  new_tnode (&bigtlist, lid1, lid2, lid3);
	  countt++;

	  tp2 = tp1->next;
	  free (tp1);
	  tp1 = tp2;
	}			/* while */


      free_pmerk_list (plist1);
      plist1 = plist2;

      if (called == 0)
	bigllist = llist2;
      else
	app_llist (llist1, llist2);
      llist1 = llist2;

      called = 1;
      return (0);
    };


  if (anker1 == NULL)
    return (0);

  if (called == 0)
    {
      called = 1;
      count = -1;
      countw = 0;
    }
  countw++;

  p11 = anker1;
  p12 = p11;

  fprintf (fp, "  PNTS Point[%d] X=%.3f Y=%.3f Z=%.3f\n", ++count, (*p11).x, (*p11).y, (*p11).z);

  do
    {
      p11 = p12;
      p12 = (*p11).next;

      if (p12 != NULL)
	{
	  fprintf (fp, "  PNTS Point[%d] X=%.3f Y=%.3f Z=%.3f\n", ++count, (*p12).x, (*p12).y, (*p12).z);
	}
    }
  while (p12 != NULL);

  return (0);
}				/* writet3dline */


/********************************************/
/* writet3dfinish:                          */
/*                                          */
/********************************************/
void
writet3dfinish (FILE * fptemp, FILE * fp, int mode)
{
  int edges = 0, faces = 0, edgecount = 0, facecount = 0, a = 0, b = 0,
    r = 0, r2 = 0, r3 = 0;
  int point1 = 0, point2 = 0, edge1 = 0, edge2 = 0, edge3 = 0;
  struct tmerk *tp1 = bigtlist, *tp2;
  struct lmerk *lp1 = bigllist, *lp2;


  fprintf (stdout, "\nWriting additional T3Dlib-Data ...");

  fprintf (fp, "  PNTS PCount %d\n", countp);

  filecopy (fptemp, fp);

  if (mode == 1)
    {
      edges = countl;
      fprintf (fp, "  EDGE ECount %d\n", edges);

      while (lp1 != NULL)
	{
	  fprintf (fp, "  EDGE Edge[%d] %d %d\n", edgecount++, lp1->id1, lp1->id2);
	  lp2 = lp1->next;
	  free (lp1);
	  lp1 = lp2;
	}

      faces = countt;
      fprintf (fp, "  FACE TCount %d\n", faces);

      while (tp1 != NULL)
	{
	  fprintf (fp, "  FACE Connect[%d] %d %d %d\n", facecount++, tp1->lid1, tp1->lid2, tp1->lid3);
	  tp2 = tp1->next;
	  free (tp1);
	  tp1 = tp2;
	}

      return;
    }

  edges = (counth * (countw - 1) + countw * (counth - 1) + (counth - 1) * (countw - 1));
  /* number of edges! */
  fprintf (fp, "  EDGE ECount %d\n", edges);


  /* write horizontal edges */
  for (a = 0; a < counth; a++)
    {
      r = a;
      for (b = 0; b < (countw - 1); b++)
	{
	  point1 = r;
	  point2 = r + counth;
	  fprintf (fp, "  EDGE Edge[%d] %d %d\n", edgecount++, point1, point2);
	  r = r + counth;
	}
    }
  /* write vertical edges */
  for (a = 0; a < countw; a++)
    {
      r = a * counth;
      for (b = 0; b < (counth - 1); b++)
	{
	  point1 = r + b;
	  point2 = r + b + 1;
	  fprintf (fp, "  EDGE Edge[%d] %d %d\n", edgecount++, point1, point2);
	}
    }
  /* write diagonal edges */
  for (a = 0; a < counth - 1; a++)
    {
      r = a;
      for (b = 0; b < (countw - 1); b++)
	{
	  point1 = r;
	  point2 = r + counth + 1;
	  fprintf (fp, "  EDGE Edge[%d] %d %d\n", edgecount++, point1, point2);
	  r = r + counth;
	}
    }
  /* ohhh boy, THIS (^^^) took me time ! :), now to that faces! */

  /* write faces */

  faces = 2 * (countw - 1) * (counth - 1);

  fprintf (fp, "  FACE TCount %d\n", faces);

  r = 0;
  r3 = countw * (counth - 1) + counth * (countw - 1);

  for (a = 0; a < counth - 1; a++)
    {
      r2 = counth * (countw - 1) + a;
      for (b = 0; b < countw - 1; b++)
	{
	  edge1 = r + countw - 1;
	  edge2 = r2;
	  edge3 = r3;
	  fprintf (fp, "  FACE Connect[%d] %d %d %d\n", facecount++, edge1, edge2, edge3);

	  edge1 = r;
	  edge2 = r2 + counth - 1;
	  edge3 = r3;
	  fprintf (fp, "  FACE Connect[%d] %d %d %d\n", facecount++, edge1, edge2, edge3);

	  r++;
	  r2 = r2 + counth - 1;
	  r3++;
	}
    }

  fprintf (fp, "  COLR R=98 G=68 B=58\n");
  fprintf (fp, "  REFL R=0 G=0 B=0\n");
  fprintf (fp, "  TRAN R=0 G=0 B=0\n");
  fprintf (fp, "  SPC1 R=0 G=0 B=0\n");
  fprintf (fp, "  End DESC   \"Object 1 at level 1 of hierarchy 1\"\n");
  fprintf (fp, " TOBJ       \"Object 0 at level 1 of hierarchy 1\"\n");
  fprintf (fp, "End OBJ  \"Hierarchy 1\"\n");

}				/* writet3dfinish */


/********************************************/
/* writerawtriangles:                       */
/********************************************/
int
writerawtriangles (FILE * fp, struct punkt *anker1, struct punkt *anker2, int mode)
{
  struct punkt *p11, *p12, *p21, *p22;
  struct triangle *tp, *tp1, *tp2;

  if ((anker1 == NULL) || (anker2 == NULL))
    return (0);

  if (mode == 1)
    {
      triangulate (anker1, anker2, &tp);

      tp1 = tp;
      while (tp1 != NULL)
	{
	  fprintf (fp, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n", tp1->p1->x, tp1->p1->y, tp1->p1->z, tp1->p2->x, tp1->p2->y, tp1->p2->z, tp1->p3->x, tp1->p3->y, tp1->p3->z);
	  tp2 = tp1->next;

	  free (tp1);

	  tp1 = tp2;
	}			/* while */

      return (0);
    };

  p11 = anker1;
  p12 = p11;
  p21 = anker2;
  p22 = p21;

  do
    {
      p11 = p12;
      p21 = p22;
      p12 = (*p11).next;
      p22 = (*p21).next;

      if ((p12 != NULL) && (p22 != NULL))
	{
	  fprintf (fp, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n", (*p11).x, (*p11).y, (*p11).z, (*p12).x, (*p12).y, (*p12).z, (*p21).x, (*p21).y, (*p21).z);

	  fprintf (fp, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n", (*p21).x, (*p21).y, (*p21).z, (*p12).x, (*p12).y, (*p12).z, (*p22).x, (*p22).y, (*p22).z);
	}
    }
  while ((p12 != NULL) && (p22 != NULL));

  return (0);
}				/* writerawtriangles */

/********************************************/
/*calcg:                                    */
/********************************************/
double
calcg (double O, double N)
{
  if (N == 0)
    return (0);
  else
    return ((2 * pi) / N * (O * N / (2 * pi) - round (O * N / (2 * pi))));

}				/* calcg */


/********************************************/
/*calck:                                    */
/********************************************/
double
calck (struct ShellyArguments *ShellyArgs, double S, double O)
{
  static double N, N2, N3, L, L2, L3, W1, W2, W12, W13, W22, W23, P, P2,
    P3, Off2, Off3;
  double k = 0, g;
  static int called = 0;



  if (called == 0)
    {

      N = (*ShellyArgs).N;
      W1 = (*ShellyArgs).W1 * pi / 180;
      W2 = (*ShellyArgs).W2 * pi / 180;
      P = (*ShellyArgs).P * pi / 180;
      L = (*ShellyArgs).L;

      N2 = (*ShellyArgs).N2;
      W12 = (*ShellyArgs).W12 * pi / 180;
      W22 = (*ShellyArgs).W22 * pi / 180;
      P2 = (*ShellyArgs).P2 * pi / 180;
      L2 = (*ShellyArgs).L2;

      N3 = (*ShellyArgs).N3;
      W13 = (*ShellyArgs).W13 * pi / 180;
      W23 = (*ShellyArgs).W23 * pi / 180;
      P3 = (*ShellyArgs).P3 * pi / 180;
      L3 = (*ShellyArgs).L3;

      Off2 = (*ShellyArgs).Off2 * pi / 180;
      Off3 = (*ShellyArgs).Off3 * pi / 180;

    }


  g = calcg (O, N);
  if (N != 0)
    k = L * exp (-(2 * (S - P) / W1) * (2 * (S - P) / W1)) * exp (-(2 * g / W2) * (2 * g / W2));

  g = calcg (O + Off2, N2);
  if (N2 != 0)
    k = k + (L2 * exp (-(2 * (S - P2) / W12) * (2 * (S - P2) / W12)) * exp (-(2 * g / W22) * (2 * g / W22)));

  g = calcg (O + Off3, N3);
  if (N3 != 0)
    k = k + (L3 * exp (-(2 * (S - P3) / W13) * (2 * (S - P3) / W13)) * exp (-(2 * g / W23) * (2 * g / W23)));

  called = 1;

  return (k);
}				/* calck */


/********************************************/
/*innodule2:                                */
/********************************************/
double
innodule2 (struct ShellyArguments *ShellyArgs, double sc, double O, double S)
{
  double k1 = 0, k2 = 0;

  k1 = calck (ShellyArgs, S, O);

  k2 = calck (ShellyArgs, S + sc, O);

  return (fabs (k1) - fabs (k2));

}				/* innodule */


/********************************************/
/*innodule:                                 */
/********************************************/
double
innodule (struct ShellyArguments *ShellyArgs, double sc, double O)
{
  static double N, N2, N3, L, L2, L3, W2, W22, W23, Off2, Off3;

  double k1 = 0, k2 = 0, g;
  static int called = 0;


  if (called == 0)
    {

      N = (*ShellyArgs).N;
      W2 = (*ShellyArgs).W2 * pi / 180;
      L = (*ShellyArgs).L;
      N2 = (*ShellyArgs).N2;
      W22 = (*ShellyArgs).W22 * pi / 180;
      L2 = (*ShellyArgs).L2;
      N3 = (*ShellyArgs).N3;
      W23 = (*ShellyArgs).W23 * pi / 180;
      L3 = (*ShellyArgs).L3;
      Off2 = (*ShellyArgs).Off2 * pi / 180;
      Off3 = (*ShellyArgs).Off3 * pi / 180;

      called = 1;
    }

  g = calcg (O, N);
  if (N != 0)
    k1 = L * exp (-(2 * g / W2) * (2 * g / W2));
  g = calcg (O + Off2, N2);
  if (N2 != 0)
    k1 = k1 + (L2 * exp (-(2 * g / W22) * (2 * g / W22)));
  g = calcg (O + Off3, N3);
  if (N3 != 0)
    k1 = k1 + (L3 * exp (-(2 * g / W23) * (2 * g / W23)));

  g = calcg (O + sc, N);
  if (N != 0)
    k2 = L * exp (-(2 * g / W2) * (2 * g / W2));
  g = calcg (O + Off2 + sc, N2);
  if (N2 != 0)
    k2 = k2 + (L2 * exp (-(2 * g / W22) * (2 * g / W22)));
  g = calcg (O + Off3 + sc, N3);
  if (N3 != 0)
    k2 = k2 + (L3 * exp (-(2 * g / W23) * (2 * g / W23)));


  return (fabs (k1) - fabs (k2));

}				/* innodule */


/********************************************/
/*calccamera:                               */
/********************************************/
void
calccamera (double x, double y, double z)
{
  static double biggest;


  if ((fabs (x) > fabs (y)) && (fabs (x) > fabs (z)))
    if (fabs (x) > biggest)
      {
	biggest = fabs (x);
	camy = biggest * 1.5;
	camz = biggest * 1.5;
      }
  if ((fabs (y) > fabs (x)) && (fabs (y) > fabs (z)))
    if (fabs (y) > biggest)
      {
	biggest = fabs (y);
	camy = biggest * 1.5;
	camz = biggest * 1.5;
      }

  if ((fabs (z) > fabs (y)) && (fabs (z) > fabs (x)))
    if (fabs (z) > biggest)
      {
	biggest = fabs (z);
	camy = biggest * 1.5;
	camz = biggest * 1.5;
      }




}				/* calccamera */


/**********************************************/
/* CalcPoint:                                 */
/*                                            */
/**********************************************/
int
calcpoint (double O, double S, struct ShellyArguments *ShellyArgs, struct punkt **point)
{
  struct punkt *point1 = NULL;
  double x, y, z, R, Re, k;
  static double my;
  static double a, b, A, beta, phi, omega, alpha, Scale;
  static int called = 0;

  if (called == 0)
    {
      alpha = (*ShellyArgs).alpha * pi / 180;
      beta = (*ShellyArgs).beta * pi / 180;
      phi = (*ShellyArgs).phi * pi / 180;
      omega = (*ShellyArgs).omega * pi / 180;
      my = (*ShellyArgs).my * pi / 180;

      a = (*ShellyArgs).a;
      b = (*ShellyArgs).b;
      A = (*ShellyArgs).A;

      Scale = (*ShellyArgs).Scale;
      called = 1;
    }
  counth = 0;

  Re = pow ((pow (a, -2.0) * (cos (S) * cos (S)) + pow (b, -2.0) * (sin (S) * sin (S))), -0.5);

  k = calck (ShellyArgs, S, O);

  R = Re + k;

  /* alternatively: */
  /* R = pow((pow(a,2.0)*pow(cos(S),2.0)+pow(b,2.0)*pow(sin(S),2.0)),0.5); */

  x = Scale * (A * sin (beta) * cos (O) + R * cos (S + phi) * cos (O + omega) - R * sin (my) * sin (S + phi) * sin (O)) * exp (O * cot (alpha));
  y = Scale * (-1 * A * sin (beta) * sin (O) - R * cos (S + phi) * sin (O + omega) - R * sin (my) * sin (S + phi) * cos (O)) * exp (O * cot (alpha));
  z = Scale * (-1 * A * cos (beta) + R * sin (S + phi) * cos (my)) * exp (O * cot (alpha));
  if (camposspecified == NO)
    calccamera (x, y, z);
  if ((point1 = calloc (1, sizeof (struct punkt))) == NULL)
    {
      fprintf (stdout, "Shelly: NOT ENOUGH MEMORY!!! ... exiting ... !\n");
      return (5);
    }				/* if */

  (*point1).x = x;
  (*point1).y = y;
  (*point1).z = z;
  (*point1).s = S;

  *point = point1;

  return (0);

}				/* calcline */


/**********************************************/
/* calcnews:                                  */
/*             SSIA :)                        */
/**********************************************/
void
calcnews (struct ShellyArguments *SA, double O, double Sold, double *newS)
{
  double S = Sold, sd;
  int mittenodul = NO;
  sd = SA->sd * pi / 180;

  S += SA->Scans;


  while ((fabs (innodule2 (SA, S - Sold, O, Sold)) < SA->heightdiffs) && (S - Sold < sd) && (mittenodul == NO))
    {
      S += SA->Scans;
      if ((innodule2 (SA, SA->Scans, O, Sold) < 0) && (innodule2 (SA, SA->Scans, O, S) > 0))
	{
	  mittenodul = YES;
	}
    }

  *newS = S;

  return;

}				/* calcnews */


/**********************************************/
/* CalcnodLine:                               */
/*                                            */
/**********************************************/
int
calcnodline (double O, struct ShellyArguments *ShellyArgs, struct punkt **list)
{
  struct punkt *list1 = NULL, *L1p1, *L1p2;
  double S, newS;
  static double sc;
  static double smin, smax, sd;
  static int called = 0;

  if (called == 0)
    {
      smin = (*ShellyArgs).smin * pi / 180;
      smax = (*ShellyArgs).smax * pi / 180;
      sd = (*ShellyArgs).sd * pi / 180;

      sc = (*ShellyArgs).Scans;

      called = 1;
    }
  S = smin;

  calcpoint (O, smin, ShellyArgs, &list1);
  L1p1 = list1;
  L1p2 = list1;

  while (S <= smax)
    {
      calcnews (ShellyArgs, O, S, &newS);
      S = newS;

      calcpoint (O, S, ShellyArgs, &L1p1);
      L1p2->next = L1p1;
      L1p2 = L1p1;


    }				/* while */

  *list = list1;

  return (0);

}				/* calcnodline */


/**********************************************/
/* CalcLine:                                  */
/*                                            */
/**********************************************/
int
calcline (double O, struct ShellyArguments *ShellyArgs, struct punkt **list)
{
  struct punkt *list1 = NULL, *L1p1, *L1p2;
  double x, y, z, R, S, Re, k;
  static double my;
  static double smin, smax, sd, a, b, A, beta, phi, omega, alpha, Scale;
  static int called = 0;

  if (called == 0)
    {
      smin = (*ShellyArgs).smin * pi / 180;
      smax = (*ShellyArgs).smax * pi / 180;
      sd = (*ShellyArgs).sd * pi / 180;

      alpha = (*ShellyArgs).alpha * pi / 180;
      beta = (*ShellyArgs).beta * pi / 180;
      phi = (*ShellyArgs).phi * pi / 180;
      omega = (*ShellyArgs).omega * pi / 180;
      my = (*ShellyArgs).my * pi / 180;

      a = (*ShellyArgs).a;
      b = (*ShellyArgs).b;
      A = (*ShellyArgs).A;

      Scale = (*ShellyArgs).Scale;
      called = 1;
    }
  counth = 0;

  for (S = smin; (S + sd) < smax; S = S + sd)
    {
      counth++;
      countp++;

      Re = pow ((pow (a, -2.0) * (cos (S) * cos (S)) + pow (b, -2.0) * (sin (S) * sin (S))), -0.5);

      k = calck (ShellyArgs, S, O);

      R = Re + k;

      /* alternatively: */
      /* R = pow((pow(a,2.0)*pow(cos(S),2.0)+pow(b,2.0)*pow(sin(S),2.0)),0.5); */

      x = Scale * (A * sin (beta) * cos (O) + R * cos (S + phi) * cos (O + omega) - R * sin (my) * sin (S + phi) * sin (O)) * exp (O * cot (alpha));
      y = Scale * (-1 * A * sin (beta) * sin (O) - R * cos (S + phi) * sin (O + omega) - R * sin (my) * sin (S + phi) * cos (O)) * exp (O * cot (alpha));
      z = Scale * (-1 * A * cos (beta) + R * sin (S + phi) * cos (my)) * exp (O * cot (alpha));
      if (camposspecified == NO)
	calccamera (x, y, z);

      if ((L1p1 = calloc (1, sizeof (struct punkt))) == NULL)
	{
	  fprintf (stdout, "Shelly: NOT ENOUGH MEMORY!!! ... exiting ... !\n");
	  if (S != smin)
	    myfree (list1);
	  return (5);
	}			/* if */
      if (S == smin)
	list1 = L1p1;
      else
	(*L1p2).next = L1p1;
      L1p2 = L1p1;

      (*L1p1).x = x;
      (*L1p1).y = y;
      (*L1p1).z = z;
      (*L1p1).s = S;

    }				/* for */

  *list = list1;

  return (0);

}				/* calcline */


/**********************************************/
/* calcnewo:                                  */
/*             SSIA :)                        */
/**********************************************/
void
calcnewo (struct ShellyArguments *SA, double Oold, double *newO)
{
  double O = Oold, od;
  int mittenodul = NO;
  od = SA->od * pi / 180;

  O += SA->Scano;

  while ((fabs (innodule (SA, O - Oold, Oold)) < SA->heightdiffo) && (O - Oold < od) && (mittenodul == NO))
    {
      O += SA->Scano;
      if ((innodule (SA, SA->Scano, Oold) < 0) && (innodule (SA, SA->Scano, O) > 0))
	{
	  mittenodul = YES;
	}
    }

  *newO = O;

  return;

}				/* calcnewo */


/**********************************************/
/* CalcNewNod:                                */
/*             SSIA :)                        */
/**********************************************/
void
CalcNewNod (struct ShellyArguments *ShellyArgs, char *fout)
{
  struct punkt *list1 = NULL, *list2;

  double O, newO, omin, omax;
  FILE *fptemp, *fp;
  char *hilf, temp[laenge];

  omin = (*ShellyArgs).omin * pi / 180;
  omax = (*ShellyArgs).omax * pi / 180;
  O = omin;

  mycopystr (fout, temp, '\0');
  hilf = strchr (temp, '\0');
  if (hilf != NULL)
    mycopystr (".tmp", hilf, '\0');


  if ((fptemp = fopen (temp, "w+")) == NULL)
    {
      fprintf (stdout, "Could not open outfile: %s!\n", temp);
      exit (5);
    }

  if ((fp = fopen (fout, "w")) == NULL)
    {
      fprintf (stdout, "Could not open outfile: %s!\n", fout);
      exit (5);
    }
  if ((*ShellyArgs).output == X3D)
    writex3dheader (fp);
  if ((*ShellyArgs).output == T3D)
    writet3dheader (fp);


  fprintf (stdout, "Calculating the Shell:");

  if (calcnodline (omin, ShellyArgs, &list1) != 0)
    exit (5);

  while (O <= omax)
    {
      calcnewo (ShellyArgs, O, &newO);
      O = newO;

      if (calcnodline (O, ShellyArgs, &list2) != 0)
	exit (5);

      fprintf (stdout, ".");
      fflush (stdout);

      if ((*ShellyArgs).output == RPL)
	writerplline (fptemp, list1, list2, 1);
      if ((*ShellyArgs).output == POV)
	writepovtriangles (fptemp, list1, list2, 1);
      if ((*ShellyArgs).output == X3D)
	writex3dline (fptemp, list1, list2, 1);
      if ((*ShellyArgs).output == T3D)
	writet3dline (fptemp, list1, list2, 1);

      if ((*ShellyArgs).output == RAW)
	writerawtriangles (fp, list1, list2, 1);

      myfree (list1);
      list1 = list2;

    }


  if ((*ShellyArgs).output == POV)
    writepovheader (fp);


  if ((*ShellyArgs).output == RPL)
    writerplfinish (fptemp, fp, 1);
  if ((*ShellyArgs).output == POV)
    writepovfinish (fptemp, fp);
  if ((*ShellyArgs).output == X3D)
    writex3dfinish (fptemp, fp, 1);
  if ((*ShellyArgs).output == T3D)
    writet3dfinish (fptemp, fp, 1);

  fprintf (stdout, "\n");

  myfree (list1);
  if ((*ShellyArgs).output == X3D)
    writex3dline (fptemp, NULL, NULL, 2);	/* free temporary pointlist in writex3dline */
  if ((*ShellyArgs).output == T3D)
    writet3dline (fptemp, NULL, NULL, 2);	/* free temporary pointlist in writet3dline */

  if (fclose (fptemp) != 0)
    fprintf (stdout, "Error while closing file: %s!\n", temp);

  if (fclose (fp) != 0)
    fprintf (stdout, "Error while closing file: %s!\n", fout);
  remove (temp);
}				/* CalcNewNod */


/**********************************************/
/* CalcNodule:                                */
/*             SSIA :)                        */
/**********************************************/
void
CalcNodule (struct ShellyArguments *ShellyArgs, char *fout)
{
  struct punkt *list1 = NULL, *list2;

  double O, newO, omin, omax;
  FILE *fptemp, *fp;
  char *hilf, temp[laenge];

  omin = (*ShellyArgs).omin * pi / 180;
  omax = (*ShellyArgs).omax * pi / 180;

  O = omin;

  mycopystr (fout, temp, '\0');
  hilf = strchr (temp, '\0');
  if (hilf != NULL)
    mycopystr (".tmp", hilf, '\0');


  if ((fptemp = fopen (temp, "w+")) == NULL)
    {
      fprintf (stdout, "Could not open outfile: %s!\n", temp);
      exit (5);
    }

  if ((fp = fopen (fout, "w")) == NULL)
    {
      fprintf (stdout, "Could not open outfile: %s!\n", fout);
      exit (5);
    }


  fprintf (stdout, "Calculating the Shell:");

  if (calcline (omin, ShellyArgs, &list1) != 0)
    exit (5);

  if ((*ShellyArgs).output == RPL)
    writerplline (fptemp, list1, NULL, 0);
  if ((*ShellyArgs).output == T3D)
    writet3dline (fptemp, list1, NULL, 0);
  if ((*ShellyArgs).output == X3D)
    writex3dline (fptemp, list1, NULL, 0);


  while (O <= omax)
    {

      calcnewo (ShellyArgs, O, &newO);
      O = newO;

      if (calcline (O, ShellyArgs, &list2) != 0)
	exit (5);

      fprintf (stdout, ".");
      fflush (stdout);

      if ((*ShellyArgs).output == RPL)
	writerplline (fptemp, list1, NULL, 0);
      if ((*ShellyArgs).output == POV)
	writepovtriangles (fptemp, list1, list2, 0);
      if ((*ShellyArgs).output == T3D)
	writet3dline (fptemp, list1, NULL, 0);
      if ((*ShellyArgs).output == X3D)
	writex3dline (fptemp, list1, NULL, 0);
      if ((*ShellyArgs).output == RAW)
	writerawtriangles (fp, list1, list2, 0);

      myfree (list1);
      list1 = list2;
    }

  if ((*ShellyArgs).output == POV)
    writepovheader (fp);
  if ((*ShellyArgs).output == T3D)
    writet3dheader (fp);
  if ((*ShellyArgs).output == X3D)
    writex3dheader (fp);


  if ((*ShellyArgs).output == RPL)
    writerplfinish (fptemp, fp, 0);
  if ((*ShellyArgs).output == T3D)
    writet3dfinish (fptemp, fp, 0);
  if ((*ShellyArgs).output == POV)
    writepovfinish (fptemp, fp);
  if ((*ShellyArgs).output == X3D)
    writex3dfinish (fptemp, fp, 0);

  fprintf (stdout, "\n");

  myfree (list1);


  if (fclose (fptemp) != 0)
    fprintf (stdout, "Error while closing file: %s!\n", temp);

  if (fclose (fp) != 0)
    fprintf (stdout, "Error while closing file: %s!\n", fout);
  remove (temp);
}				/* CalcNodule */


/**********************************************/
/* CalcShell:                                 */
/*             SSIA :)                        */
/**********************************************/
void
CalcShell (struct ShellyArguments *ShellyArgs, char *fout)
{
  struct punkt *list1 = NULL, *list2;

  double O, omin, omax, od;
  FILE *fptemp, *fp;
  char temp[laenge], *hilf;

  omin = (*ShellyArgs).omin * pi / 180;
  omax = (*ShellyArgs).omax * pi / 180;
  od = (*ShellyArgs).od * pi / 180;


  mycopystr (fout, temp, '\0');
  hilf = strchr (temp, '\0');
  if (hilf != NULL)
    mycopystr (".tmp", hilf, '\0');

  if ((fptemp = fopen (temp, "w+")) == NULL)
    {
      fprintf (stdout, "Could not open outfile: %s!\n", temp);
      exit (5);
    }

  if ((fp = fopen (fout, "w")) == NULL)
    {
      fprintf (stdout, "Could not open outfile: %s!\n", fout);
      exit (5);
    }




  fprintf (stdout, "Calculating the Shell:");

  if (calcline (omin, ShellyArgs, &list1) != 0)
    exit (5);


  if ((*ShellyArgs).output == RPL)
    writerplline (fptemp, list1, NULL, 0);
  if ((*ShellyArgs).output == T3D)
    writet3dline (fptemp, list1, NULL, 0);
  if ((*ShellyArgs).output == X3D)
    writex3dline (fptemp, list1, NULL, 0);

  for (O = omin + od; (O + od) < omax; O = O + od)
    {

      counth = 0;

      if (calcline (O, ShellyArgs, &list2) != 0)
	exit (5);

      fprintf (stdout, ".");
      fflush (stdout);


      if ((*ShellyArgs).output == RPL)
	writerplline (fptemp, list1, NULL, 0);
      if ((*ShellyArgs).output == POV)
	writepovtriangles (fptemp, list1, list2, 0);
      if ((*ShellyArgs).output == T3D)
	writet3dline (fptemp, list1, NULL, 0);
      if ((*ShellyArgs).output == RAW)
	writerawtriangles (fp, list1, list2, 0);
      if ((*ShellyArgs).output == X3D)
	writex3dline (fptemp, list1, NULL, 0);


      myfree (list1);
      list1 = list2;

    }				/* for */

  if ((*ShellyArgs).output == POV)
    writepovheader (fp);
  if ((*ShellyArgs).output == T3D)
    writet3dheader (fp);
  if ((*ShellyArgs).output == X3D)
    writex3dheader (fp);


  if ((*ShellyArgs).output == RPL)
    writerplfinish (fptemp, fp, 0);
  if ((*ShellyArgs).output == T3D)
    writet3dfinish (fptemp, fp, 0);
  if ((*ShellyArgs).output == POV)
    writepovfinish (fptemp, fp);
  if ((*ShellyArgs).output == X3D)
    writex3dfinish (fptemp, fp, 0);

  fprintf (stdout, "\n");

  myfree (list1);


  if (fclose (fptemp) != 0)
    fprintf (stdout, "Error while closing file: %s!\n", temp);

  if (fclose (fp) != 0)
    fprintf (stdout, "Error while closing file: %s!\n", fout);
  remove (temp);
}				/* CalcShell */


/**********************************************/
/* RenderPov:                                 */
/*           invoke pov for rendering         */
/**********************************************/
void
RenderPov (struct ShellyArguments *ShellyArgs, char *fout)
{
  char call[laenge];

  printf ("Rendering...\n");

  mycopystr ("pov ", call, '\0');
  mycopystr ((*ShellyArgs).povargs, &call[4], '\0');
  strcat (call, " +i");
  strcat (call, fout);
  system (call);


}				/* RenderPov */


/********************************************/
/*main:                                     */
/********************************************/
int
main (int ac, char **av)
{
  struct ShellyArguments *ShellyArgs;

  fprintf (stdout, "ShellyV1.5, the ShellShapeGenerator by RANDi\n");

  if (ac != 3)
    {
      fprintf (stdout, "USAGE:\n\n");
      fprintf (stdout, "   'shelly infilename outfilename'\n\n");
      exit (1);
    }				/* if */


  if ((ShellyArgs = calloc (1, sizeof (struct ShellyArguments))) != NULL);
  {
    ReadInfile (ShellyArgs, av[1]);

    if (ShellyArgs->mode == NORMAL)
      CalcShell (ShellyArgs, av[2]);
    if (ShellyArgs->mode == NODULE)
      CalcNodule (ShellyArgs, av[2]);
    if (ShellyArgs->mode == NEWNOD)
      CalcNewNod (ShellyArgs, av[2]);

    if (ShellyArgs->Render == YES)
      if (ShellyArgs->output != POV)
	fprintf (stdout, "Rendering is only available for POV-output!\n(Ever tried to feed a RPL-Macro into POV? ;))\n");
      else
	RenderPov (ShellyArgs, av[2]);
  }
  exit (0);
}
