📄 grid.c
字号:
if (axis == x_axis) Text(buf, graph->viewportxoff + i - strlen(buf) / 2 * graph->fontwidth, (int) (graph->fontheight * 2.5)); else Text(buf, graph->viewportxoff - graph->fontwidth * (strlen(buf)), graph->viewportyoff + i - graph->fontheight / 2); /* This is to make sure things work when delta > hi - lo. */ if (nsp == 1) j += 1000; } if (axis == x_axis) Text(units, (int) (graph->absolute.width * 0.6), graph->fontheight); else Text(units, graph->fontwidth, (int) (graph->absolute.height - 2 * graph->fontheight)); Update();}/* Plot a log grid. Note that we pay no attention to x- and y-delta here. */static double *loggrid(GRAPH *graph, double lo, double hi, int type, Axis axis){ static double dd[2]; int margin; int max; int subs, pp, decsp, lmt, hmt; int i, j; double k; double decs; char buf[LABEL_CHARS], *s; if (axis == x_axis && graph->grid.xsized) { lmt = graph->grid.xaxis.log.lmt; hmt = graph->grid.xaxis.log.hmt; dd[0] = pow(10.0, (double) lmt); dd[1] = pow(10.0, (double) hmt); return dd; } else if (axis == y_axis && graph->grid.ysized) { lmt = graph->grid.yaxis.log.lmt; hmt = graph->grid.yaxis.log.hmt; dd[0] = pow(10.0, (double) lmt); dd[1] = pow(10.0, (double) hmt); return dd; } if (axis == x_axis) { margin = graph->viewportxoff; max = graph->absolute.width - graph->viewportxoff; } else { margin = graph->viewportyoff; max = graph->absolute.height - graph->viewportyoff; } /* How many orders of magnitude. We are already guaranteed that hi * and lo are positive. */ lmt = floor(mylog10(lo)); hmt = ceil(mylog10(hi)); decs = hmt - lmt; pp = 1; decsp = (max - margin) / decs; if (decsp < 20) { pp = ceil(20.0 / decsp); decsp *= pp; subs = 1; } else if (decsp > 50) { static int divs[ ] = { 20, 10, 5, 4, 2, 1 }; k = 5.0 / decsp; for (i = 0; i < NUMELEMS(divs) - 1; i++) { j = divs[i]; if (-log10(((double) j - 1.0) / j) > k) break; } subs = divs[i]; } else subs = 1; /* Start at a line */ lmt = floor((double) lmt / pp) * pp; decs = hmt - lmt; decsp = (max - margin) / decs; dd[0] = pow(10.0, (double) lmt); dd[1] = pow(10.0, (double) hmt); if ((s = ft_typabbrev(type))) { (void) strcpy(buf, s); } else { (void) strcpy(buf, "Units"); } if (axis == x_axis) { (void) strcpy(graph->grid.xaxis.log.units, buf); graph->viewport.width = decs * decsp; graph->grid.xaxis.log.hmt = hmt; graph->grid.xaxis.log.lmt = lmt; graph->grid.xaxis.log.decsp = decsp; graph->grid.xaxis.log.subs = subs; graph->grid.xaxis.log.pp = pp; graph->grid.xsized = 1; } else { (void) strcpy(graph->grid.yaxis.log.units, buf); graph->viewport.height = decs * decsp; graph->grid.yaxis.log.hmt = hmt; graph->grid.yaxis.log.lmt = lmt; graph->grid.yaxis.log.decsp = decsp; graph->grid.yaxis.log.subs = subs; graph->grid.yaxis.log.pp = pp; graph->grid.ysized = 1; } return (dd);}/* PN static */voiddrawloggrid(GRAPH *graph, char *units, int hmt, int lmt, int decsp, int subs, int pp, Axis axis){ int i, j, k, m; double t; char buf[LABEL_CHARS]; /* Now plot every pp'th decade line, with subs lines between them. */ if (subs > 1) SetLinestyle(0); for (i = 0, j = lmt; j <= hmt; i += decsp * pp, j += pp) { /* Draw the decade line */ if (graph->grid.gridtype != GRID_NONE) { if (axis == x_axis) DrawLine(graph->viewportxoff + i, graph->viewportyoff, graph->viewportxoff + i, graph->viewport.height +graph->viewportyoff); else DrawLine(graph->viewportxoff, graph->viewportyoff + i, graph->viewport.width + graph->viewportxoff, graph->viewportyoff + i); } if (j == -2) (void) sprintf(buf, "0.01"); else if (j == -1) (void) sprintf(buf, "0.1"); else if (j == 0) (void) sprintf(buf, "1"); else if (j == 1) (void) sprintf(buf, "10"); else if (j == 2) (void) sprintf(buf, "100"); else (void) sprintf(buf, "10^%d", j); if (axis == x_axis) Text(buf, graph->viewportxoff + i - strlen(buf) / 2, (int) (graph->fontheight * 2.5)); else Text(buf, graph->viewportxoff - graph->fontwidth * (strlen(buf) + 1), graph->viewportyoff + i - graph->fontheight / 2); if (j >= hmt) break; /* Now draw the subdivision lines */ if (subs > 1) { SetLinestyle(1); t = 10.0 / subs; for (k = ceil(subs / 10.0) + 1; k < subs; k++) { m = i + decsp * log10((double) t * k); if (graph->grid.gridtype != GRID_NONE) { if (axis == x_axis) DrawLine(graph->viewportxoff + m, graph->viewportyoff, graph->viewportxoff + m, graph->viewport.height + graph->viewportyoff); else DrawLine(graph->viewportxoff, graph->viewportyoff + m, graph->viewport.width + graph->viewportxoff, graph->viewportyoff + m); } } SetLinestyle(0); } } if (axis == x_axis) Text(units, (int) (graph->absolute.width * 0.6), graph->fontheight); else Text(units, graph->fontwidth, (int) (graph->absolute.height - 2 * graph->fontheight)); Update();}/* Polar grids */static voidpolargrid(GRAPH *graph){ double d, mx, my, tenpowmag; int hmt, lmt, mag; double minrad, maxrad; bool centered = FALSE; /* Make sure that our area is square. */ if (graph->viewport.width > graph->viewport.height) { graph->viewport.width = graph->viewport.height; } else { graph->viewport.height = graph->viewport.width; } /* Make sure that the borders are even */ if (graph->viewport.width & 1) { graph->viewport.width += 1; graph->viewport.height += 1; } graph->grid.xaxis.circular.center = graph->viewport.width / 2 + graph->viewportxoff; graph->grid.yaxis.circular.center = graph->viewport.height / 2 + graph->viewportyoff; graph->grid.xaxis.circular.radius = graph->viewport.width / 2; /* Figure out the minimum and maximum radii we're dealing with. */ mx = (graph->data.xmin + graph->data.xmax) / 2; my = (graph->data.ymin + graph->data.ymax) / 2; d = sqrt(mx * mx + my * my); maxrad = d + (graph->data.xmax - graph->data.xmin) / 2; minrad = d - (graph->data.xmax - graph->data.xmin) / 2; if (maxrad == 0.0) { fprintf(cp_err, "Error: 0 radius in polargrid\n"); return; } if ((graph->data.xmin < 0) && (graph->data.ymin < 0) && (graph->data.xmax > 0) && (graph->data.ymax > 0)) minrad = 0; if ((graph->data.xmin == - graph->data.xmax) && (graph->data.ymin == -graph->data.ymax) && (graph->data.xmin == graph->data.ymin)) centered = TRUE; mag = floor(mylog10(maxrad)); tenpowmag = pow(10.0, (double) mag); hmt = maxrad / tenpowmag; lmt = minrad / tenpowmag; if (hmt * tenpowmag < maxrad) hmt++; if (lmt * tenpowmag > minrad) lmt--; maxrad = hmt * tenpowmag; minrad = lmt * tenpowmag; /* Make sure that the range is square */ mx = graph->data.xmax - graph->data.xmin; my = graph->data.ymax - graph->data.ymin; graph->datawindow.xmin = graph->data.xmin; graph->datawindow.xmax = graph->data.xmax; graph->datawindow.ymin = graph->data.ymin; graph->datawindow.ymax = graph->data.ymax; if (mx > my) { graph->datawindow.ymin -= (mx - my) / 2; graph->datawindow.ymax += (mx - my) / 2; } else if (mx < my) { graph->datawindow.xmin -= (my - mx) / 2; graph->datawindow.xmax += (my - mx) / 2; } /* Range is square with upper bound maxrad */ graph->grid.xaxis.circular.hmt = hmt; graph->grid.xaxis.circular.lmt = lmt; graph->grid.xaxis.circular.mag = mag;}static voiddrawpolargrid(GRAPH *graph){ double tenpowmag, theta; int hmt, lmt, i, step, mag; int relcx, relcy, relrad, dist, degs; int x1, y1, x2, y2; double minrad, maxrad, pixperunit; char buf[64]; hmt = graph->grid.xaxis.circular.hmt; lmt = graph->grid.xaxis.circular.lmt; mag = graph->grid.xaxis.circular.mag; tenpowmag = pow(10.0, (double) mag); maxrad = hmt * tenpowmag; minrad = lmt * tenpowmag; if ((minrad == 0) && ((hmt - lmt) > 5)) { if (!((hmt - lmt) % 2)) step = 2; else if (!((hmt - lmt) % 3)) step = 3; else step = 1; } else step = 1; pixperunit = graph->grid.xaxis.circular.radius * 2 / (graph->datawindow.xmax - graph->datawindow.xmin); relcx = - (graph->datawindow.xmin + graph->datawindow.xmax) / 2 * pixperunit; relcy = - (graph->datawindow.ymin + graph->datawindow.ymax) / 2 * pixperunit; /* The distance from the center of the plotting area to the center of * the logical area. */ dist = sqrt((double) (relcx * relcx + relcy * relcy)); SetLinestyle(0); Arc(graph->grid.xaxis.circular.center, graph->grid.yaxis.circular.center, graph->grid.xaxis.circular.radius, (double) 0.0, (double) 0.0); SetLinestyle(1); /* Now draw the circles. */ for (i = lmt; (relrad = i * tenpowmag * pixperunit) <= dist + graph->grid.xaxis.circular.radius; i += step) { cliparc((double) graph->grid.xaxis.circular.center + relcx, (double) graph->grid.yaxis.circular.center + relcy, (double) relrad, 0.0, 0.0, graph->grid.xaxis.circular.center, graph->grid.yaxis.circular.center, graph->grid.xaxis.circular.radius, 0); /* Toss on the label */ if (relcx || relcy) theta = atan2((double) relcy, (double) relcx); else theta = M_PI; if (i && (relrad > dist - graph->grid.xaxis.circular.radius)) addradlabel(graph, i, theta, (int) (graph->grid.xaxis.circular.center - (relrad - dist) * cos(theta)), (int) (graph->grid.yaxis.circular.center - (relrad - dist) * sin(theta))); } /* Now draw the spokes. We have two possible cases -- first, the * origin may be inside the area -- in this case draw 12 spokes. * Otherwise, draw several spokes at convenient places. */ if ((graph->datawindow.xmin <= 0.0) && (graph->datawindow.xmax >= 0.0) && (graph->datawindow.ymin <= 0.0) && (graph->datawindow.ymax >= 0.0)) { for (i = 0; i < 12; i++) { x1 = graph->grid.xaxis.circular.center + relcx; y1 = graph->grid.yaxis.circular.center + relcy; x2 = x1 + graph->grid.xaxis.circular.radius * 2 * cos(i * M_PI / 6); y2 = y1 + graph->grid.xaxis.circular.radius * 2 * sin(i * M_PI / 6); if (!clip_to_circle(&x1, &y1, &x2, &y2, graph->grid.xaxis.circular.center, graph->grid.yaxis.circular.center, graph->grid.xaxis.circular.radius)) { DrawLine(x1, y1, x2, y2); /* Add a label here */ /*XXXX*/ adddeglabel(graph, i * 30, x2, y2, x1, y1, graph->grid.xaxis.circular.center, graph->grid.yaxis.circular.center); } } } else { /* Figure out the angle that we have to fill up */ theta = 2 * asin((double) graph->grid.xaxis.circular.radius / dist); theta = theta * 180 / M_PI; /* Convert to degrees. */ /* See if we should put lines at 30, 15, 5, or 1 degree * increments. */ if (theta / 30 > 3) degs = 30; else if (theta / 15 > 3) degs = 15; else if (theta / 5 > 3) degs = 5; else degs = 1; /* We'll be cheap */ for (i = 0; i < 360; i+= degs) { x1 = graph->grid.xaxis.circular.center + relcx; y1 = graph->grid.yaxis.circular.center + relcy; x2 = x1 + dist * 2 * cos(i * M_PI / 180); y2 = y1 + dist * 2 * sin(i * M_PI / 180); if (!clip_to_circle(&x1, &y1, &x2, &y2, graph->grid.xaxis.circular.center, graph->grid.yaxis.circular.center, graph->grid.xaxis.circular.radius)) { DrawLine(x1, y1, x2, y2); /* Put on the label */ adddeglabel(graph, i, x2, y2, x1, y1, graph->grid.xaxis.circular.center, graph->grid.yaxis.circular.center); } } } (void) sprintf(buf, "e%d", mag); Text(buf, graph->grid.xaxis.circular.center + graph->grid.xaxis.circular.radius, graph->grid.yaxis.circular.center - graph->grid.xaxis.circular.radius); Update(); return;}/* Put a degree label on the screen, with 'deg' as the label, near point (x, y) * such that the perpendicular to (cx, cy) and (x, y) doesn't overwrite the * label. If the distance between the center and the point is * too small, don't put the label on. */#define LOFF 5#define MINDIST 10static voidadddeglabel(GRAPH *graph, int deg, int x, int y, int cx, int cy, int lx, int ly){ char buf[8]; int d, w, h; double angle; if (sqrt((double) (x - cx) * (x - cx) + (y - cy) * (y - cy)) < MINDIST) return; (void) sprintf(buf, "%d", deg); w = graph->fontwidth * (strlen(buf) + 1); h = graph->fontheight * 1.5; angle = atan2((double) (y - ly), (double) (x - lx)); d = fabs(cos(angle)) * w / 2 + fabs(sin(angle)) * h / 2 + LOFF; x = x + d * cos(angle) - w / 2; y = y + d * sin(angle) - h / 2; Text(buf, x, y); Text("o", x + strlen(buf) * graph->fontwidth, y + graph->fontheight / 2); return;}/* This is kind of wierd. If dist = 0, then this is the normal case, where * the labels should go along the positive X-axis. Otherwise, to make * sure that all circles drawn have labels, put the label near the circle * along the line from the logical center to the physical center. */static voidaddradlabel(GRAPH *graph, int lab, double theta, int x, int y){ char buf[32]; (void) sprintf(buf, "%d", lab); if (theta == M_PI) { y = y - graph->fontheight - 2; x = x - graph->fontwidth * strlen(buf) - 3; } else x = x - graph->fontwidth * strlen(buf) - 3; Text(buf, x, y); return;}/* Smith charts. */#define gr_xcenter graph->grid.xaxis.circular.center#define gr_ycenter graph->grid.yaxis.circular.center#define gr_radius graph->grid.xaxis.circular.radius#define gi_fntwidth graph->fontwidth#define gi_fntheight graph->fontheight#define gi_maxx graph->viewport.width+graph->viewportxoff#define gr_xmargin graph->viewportxoff#define gr_ymargin graph->viewportyoffstatic voidsmithgrid(GRAPH *graph){ double mx, my;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -