⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 conviso.c

📁 卷积程序
💻 C
字号:
/****
 *  This files plot a series of contour lines for a 2D array of double.
 *  4/14/92.
 ****/

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <time.h>
#include <string.h>
#include <ctype.h>

#ifndef PI
#define PI 3.1415926
#endif

/****
 *	Return true is val is between Z[i][j] and Z[i+1][j].
 ****/
#define INTERSECTI(val, Z, i, j) \
  (Z[i][j] <= val && val <= Z[i+1][j] || \
   Z[i][j] >= val && val >= Z[i+1][j])

/****
 *	Return true is val is between Z[i][j] and Z[i][j+1].
 ****/
#define INTERSECTJ(val, Z, i, j) \
  (Z[i][j] <= val && val <= Z[i][j+1] || \
   Z[i][j] >= val && val >= Z[i][j+1])

FILE       *GetWriteFile(char *Ext);	/* in conho.c. */

struct XY {
  double      x, y;
};

struct XYpairs {
  double      x, y;
  struct XYpairs *next;
};

typedef struct XYpairs *PairList;

/* set up a que for printing the pairs. */
typedef PairList QDATA;

struct Qlinked_list {
  QDATA       d;
  struct Qlinked_list *next;
};

typedef struct Qlinked_list QELEMENT;
typedef QELEMENT *QLINK;

typedef struct {		/* a que of pairs. */
  QLINK       front, rear;
}           QUE;
/* end of que definition. */


struct Isolines {
  double      iso_val;		/* z value of the contour line. */
  PairList    pairs;
  struct Isolines *next;
};

typedef struct Isolines *IsoList;



double 
ZMin(double **Z,
     long IXmax,
     long IYmax,
     double Dx,
     double Dy,
     struct XY * Pmin_Ptr)
{
  double      zmin;
  long        i, j;

  zmin = Z[0][0];
  for (i = 0; i < IXmax; i++)
    for (j = 0; j < IYmax; j++)
      if (Z[i][j] < zmin) {
	zmin = Z[i][j];
	Pmin_Ptr->x = i * Dx;
	Pmin_Ptr->y = j * Dy;
      }
  return (zmin);
}


double 
ZMax(double **Z,
     long IXmax,
     long IYmax,
     double Dx,
     double Dy,
     struct XY * Pmax_Ptr)
{
  double      zmax;
  long        i, j;

  zmax = Z[0][0];
  for (i = 0; i < IXmax; i++)
    for (j = 0; j < IYmax; j++)
      if (Z[i][j] > zmax) {
	zmax = Z[i][j];
	Pmax_Ptr->x = i * Dx;
	Pmax_Ptr->y = j * Dy;
      }
  return (zmax);
}


/* Get the isovalues from user. */
IsoList 
GetIsoValues(double Z_Min, double Z_Max)
{
  IsoList     head;
  char        in_str[256];

  printf("Input an isovalue or . to stop: ");
  scanf("%s", in_str);
  if (strlen(in_str) == 1 && in_str[0] == '.')
    return (NULL);

  head = (IsoList) malloc(sizeof(struct Isolines));
  if (head == NULL)
    return (NULL);

  /* get the elements for the node. */
  sscanf(in_str, "%lf", &head->iso_val);
  if (head->iso_val < Z_Min)
    head->iso_val = Z_Min;
  else if (head->iso_val > Z_Max)
    head->iso_val = Z_Max;
  head->pairs = NULL;
  head->next = GetIsoValues(Z_Min, Z_Max);
  return (head);
}


/****
 *  The isoposition is between [i][j] & [i+1][j]
 *
 *  Linear interpolation is used to locate the y component of
 *  the iso position.
 ****/
void 
IsoPositionI(PairList pair,
	     double iso_val, double **Z,
	     long i, long j,
	     double Dx, double Dy)
{
  pair->y = (j + 0.5) * Dy;
  if (Z[i][j] != Z[i + 1][j])
    pair->x = (i + 0.5) * Dx + Dx * (iso_val - Z[i][j]) / (Z[i + 1][j] - Z[i][j]);
  else
    pair->x = (i + 1) * Dx;	/* take the mid point. */
}


/****
 *  The isoposition is between [i][j] & [i][j+1]
 *
 *  Linear interpolation is used to locate the y component of
 *  the iso position.
 ****/
void 
IsoPositionJ(PairList pair,
	     double iso_val, double **Z,
	     long i, long j,
	     double Dx, double Dy)
{
  pair->x = (i + 0.5) * Dx;
  if (Z[i][j + 1] != Z[i][j])
    pair->y = (j + 0.5) * Dy + Dy * (iso_val - Z[i][j]) / (Z[i][j + 1] - Z[i][j]);
  else
    pair->y = (j + 1) * Dy;	/* take the mid point. */
}

void 
IsoPosition(PairList pair,
	    double iso_val, double **Z,
	    long i, long j,
	    double Dx, double Dy)
{

  if (INTERSECTI(iso_val, Z, i, j))
    IsoPositionI(pair, iso_val, Z, i, j, Dx, Dy);
  else if (INTERSECTJ(iso_val, Z, i, j))
    IsoPositionJ(pair, iso_val, Z, i, j, Dx, Dy);
}

PairList 
AllocPair(void)
{
  PairList    pair;

  pair = (PairList) malloc(sizeof(struct XYpairs));
  if (pair == NULL)
    puts("...malloc error. Contour lines are not complete");
  return (pair);
}

void 
GetAnIsoLine(IsoList IsoNode, double **Z,
	     long IXmax, long IYmax,
	     double Dx, double Dy)
{
  long        i, j;
  double      ival = IsoNode->iso_val;
  PairList    pair_tail;

  for (j = 0; j < IYmax - 1; j++)
    for (i = 0; i < IXmax - 2; i++)
      if (INTERSECTI(ival, Z, i, j) ||
	  INTERSECTJ(ival, Z, i, j)) {	/* found a pair. */
	if (IsoNode->pairs == NULL) {	/* 1st pair. */
	  if (!(IsoNode->pairs = AllocPair()))
	    return;
	  pair_tail = IsoNode->pairs;
	} else {		/* subsequent  pairs. */
	  if (!(pair_tail->next = AllocPair()))
	    return;
	  pair_tail = pair_tail->next;
	}
	IsoPosition(pair_tail, ival, Z, i, j, Dx, Dy);
      }
  pair_tail->next = NULL;	/* end of the pair list. */
}


/****
 *	Return the quadrant.
 *	For Frz or Arz, the peak point is usually on z axis which is
 *	y here. We want start the isoline from the 4th quadrant.
 *	Therefore, we use -1 for the 4th quadrant instead of 4.
 ****/
short 
GetQuadrant(double x, double y)
{
  if (x > 0 && y >= 0)
    return (1);			/* Include +x-axis. */
  else if (x <= 0 && y > 0)
    return (2);			/* Include +y-axis. */
  else if (x < 0 && y <= 0)
    return (3);			/* Include -x-axis. */
  else if (x >= 0 && y < 0)
    return (-1);		/* Include -y-axis. */
}

/****
 *  Compare the angle wrt Pmax.  If the angle of "This" is larger
 *  than that of the "Next", return 1.  Otherwise, return 0.
 *
 *  Although atan2 returns value in the range -pi to pi, we want
 *	to avoid it because it is slow.  We compare the quadrants of
 *	the two points first.  If they are in the same quadrant, we
 *	compare the relative positions.
 ****/
char 
OutOfOrder(PairList This,	/* current pair. */
	   PairList Next,
	   struct XY Pmax)
{
  double      x0, y0, x1, y1;
  short       q0, q1;		/* Quadrants. */
  char        out_order;

  if (This == NULL || Next == NULL)
    return (0);			/* This shouldn't happen. */
  x0 = This->x - Pmax.x;
  y0 = This->y - Pmax.y;
  q0 = GetQuadrant(x0, y0);
  x1 = Next->x - Pmax.x;
  y1 = Next->y - Pmax.y;
  q1 = GetQuadrant(x1, y1);

  if (q0 < q1)
    out_order = 0;
  else if (q0 > q1)
    out_order = 1;
  else {			/* In the same quadrant. */
    if (y0 * x1 < y1 * x0)
      out_order = 0;
    else
      out_order = 1;
  }

  return (out_order);
}


/****
 *  Sort the isopositions according to the angle with respect to
 *  the position of the maximum value.
 ****/
void 
SortAnIsoLine(PairList * PairHeadPtr,
	      struct XY Pmax)
{
  char        sorted = 0;
  PairList    this, last;	/* this=the pair being compared w/ the
				 * next one. */
  PairList    sorted_head = NULL;	/* the head to the sublist of
					 * sorted pairs. */

  while (!sorted && sorted_head != *PairHeadPtr) {
    sorted = 1;			/* assume sublist is sorted. */
    last = NULL;
    this = *PairHeadPtr;	/* sublist starts at *PairHeadPtr, ends at
				 * sorted_head. */

    while (this->next != sorted_head) {	/* traverse the sublist. */
      if (OutOfOrder(this, this->next, Pmax)) {	/* swap and move to next. */
	sorted = 0;
	if (last == NULL)
	  *PairHeadPtr = this->next;
	else
	  last->next = this->next;

	last = this->next;
	this->next = last->next;
	last->next = this;
      } else {			/* move to next. */
	last = this;
	this = this->next;
      }
    }				/* end of sublist traversing. */

    sorted_head = this;
  }				/* end of big while. */
}

#if 0
/****
 *	Repeat the first pair of the isoline at the end of the list
 *	so that the isoline is a loop.
 *	Sometimes this may not be desired.
 ****/
void 
LoopAnIsoLine(PairList * PairHeadPtr)
{
  PairList    tail;

  tail = *PairHeadPtr;
  while (tail->next != NULL)
    tail = tail->next;

  tail->next = (PairList) malloc(sizeof(struct XYpairs));
  if (tail->next == NULL)
    return;
  tail = tail->next;
  tail->x = (*PairHeadPtr)->x;
  tail->y = (*PairHeadPtr)->y;
  tail->next = NULL;
}
#endif

void 
GetIsoLines(IsoList isos,
	    double **Z,
	    long IXmax,
	    long IYmax,
	    double Dx,
	    double Dy,
	    struct XY Pmax)
{
  IsoList     node = isos;

  while (node != NULL) {
    GetAnIsoLine(node, Z, IXmax, IYmax, Dx, Dy);
    SortAnIsoLine(&node->pairs, Pmax);
    /* LoopAnIsoLine(&node->pairs); */
    node = node->next;
  }
}

char 
IsEmpty(QUE q)
{
  return (q.front == NULL);
}


void 
Deque(QUE * q, QDATA * x)
{
  QLINK       temp = q->front;

  if (!IsEmpty(*q)) {
    *x = temp->d;
    q->front = temp->next;
    free(temp);
  } else
    printf("Empty que.\n");
}

void 
Enque(QUE * q, QDATA x)
{
  QLINK       temp;

  temp = (QLINK) malloc(sizeof(QELEMENT));
  temp->d = x;
  temp->next = NULL;
  if (IsEmpty(*q))
    q->front = q->rear = temp;
  else {
    q->rear->next = temp;
    q->rear = temp;
  }
}


void 
WriteIsoLines(FILE * Isofile,
	      IsoList IsoHead)
{
  QUE         qprint = {NULL, NULL};	/* que to be printed. */
  QUE         qsave = {NULL, NULL};
  QDATA       p;		/* QDATA is PairList. */
  char        all_nulls;

  while (IsoHead != NULL) {
    fprintf(Isofile, "X%-8lG\tY%-8lG\t", IsoHead->iso_val, IsoHead->iso_val);
    Enque(&qprint, IsoHead->pairs);
    IsoHead = IsoHead->next;
  }
  fprintf(Isofile, "\n");

  do {
    all_nulls = 1;
    while (!IsEmpty(qprint)) {
      Deque(&qprint, &p);
      if (p != NULL) {
	fprintf(Isofile, "%9.2lE\t%9.2lE\t", p->x, p->y);
	Enque(&qsave, p->next);	/* add the next to a new que for a new
				 * row. */
	if (all_nulls == 1)
	  all_nulls = 0;
      } else {
	/* fprintf(Isofile, "%9s\t%9s\t", " ", " "); */
	fprintf(Isofile, "\t\t");
	Enque(&qsave, p);	/* add a null to the new que. */
      }
    }
    fprintf(Isofile, "\n");
    qprint = qsave;
    qsave.front = NULL;
    qsave.rear = NULL;
  } while (!all_nulls);
}

void 
FreePairs(PairList Pairs)
{
  PairList    this_pair;

  while (Pairs != NULL) {
    this_pair = Pairs;
    Pairs = Pairs->next;
    free(this_pair);
  }
}

void 
FreeIsoLines(IsoList IsoHead)
{
  IsoList     this_iso;
  PairList    pair_head;

  while (IsoHead != NULL) {
    FreePairs(IsoHead->pairs);
    this_iso = IsoHead;
    IsoHead = IsoHead->next;
    free(this_iso);
  }
}


void 
IsoPlot(double **Z,		/* the 2D array Z[i][j]. */
	long int IXmax,
	long int IYmax,		/* the 0<=i<=IXmax, 0<=j<=IYmax. */
	double Dx,
	double Dy)
{				/* the gridline separations. */
  FILE       *isofile;		/* send isolines to this file. */
  struct XY   pmin, pmax;	/* the xy positions of the min & max. */
  double      zmin, zmax;
  IsoList     isos;
  char        fname[128] = "iso";

  /* Locate the min & max. */
  zmin = ZMin(Z, IXmax, IYmax, Dx, Dy, &pmin);
  zmax = ZMax(Z, IXmax, IYmax, Dx, Dy, &pmax);

  if (zmin == zmax || IXmax * IYmax < 4) {
    printf("...Not enough data for contour plot\n");
    return;
  }
  isofile = GetWriteFile(fname);
  if (isofile == NULL)
    return;

  printf("The range of the value is %lf to %lf.\n", zmin, zmax);
  isos = GetIsoValues(zmin, zmax);

  GetIsoLines(isos, Z, IXmax, IYmax, Dx, Dy, pmax);
  WriteIsoLines(isofile, isos);

  FreeIsoLines(isos);

  fclose(isofile);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -