📄 conviso.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;}#endifvoid 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 + -