📄 miarc.c
字号:
if ((prevphase == 0 || isDoubleDash) && !arc->selfJoin) { addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps, &capSize[prevphase], LEFT_END, k); arc->cap = arcs[prevphase].ncaps; } if (isDashed && !arcsJoin) { iDash = iDashStart; iphase = iphaseStart; dashRemaining = dashRemainingStart; } nextk = arcs[iphase].narcs; if (nexti == start) { nextk = 0; iDash = iDashStart; iphase = iphaseStart; dashRemaining = dashRemainingStart; } /* * cap the right end of the next arc. If the * next arc is actually the first arc, only * cap it if it joins with this arc. This * case will occur when the final dash segment * of an on/off dash is off. Of course, this * cap will be drawn at a strange time, but that * hardly matters... */ if ((iphase == 0 || isDoubleDash) && (nexti != start || (arcsJoin && isDashed))) addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, &capSize[iphase], RIGHT_END, nextk); } i = nexti; if (i == start) break; } /* * make sure the last section is rendered */ for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) if (arcs[iphase].narcs > 0) { arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1; arcs[iphase].arcs[arcs[iphase].narcs-1].join = arcs[iphase].njoins; arcs[iphase].arcs[arcs[iphase].narcs-1].cap = arcs[iphase].ncaps; } DEALLOCATE_LOCAL(data); return arcs;arcfail: miFreeArcs(arcs, pGC); DEALLOCATE_LOCAL(data); return (miPolyArcPtr)NULL;}static doubleangleToLength (angle, map) int angle; dashMap *map;{ double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen; int di; int excess; Bool oddSide = FALSE; totallen = 0; if (angle >= 0) { while (angle >= 90 * 64) { angle -= 90 * 64; totallen += sidelen; oddSide = !oddSide; } } else { while (angle < 0) { angle += 90 * 64; totallen -= sidelen; oddSide = !oddSide; } } if (oddSide) angle = 90 * 64 - angle; di = xAngleToDashIndex (angle); excess = angle - dashIndexToXAngle (di); len = map->map[di]; /* * linearly interpolate between this point and the next */ if (excess > 0) { excesslen = (map->map[di + 1] - map->map[di]) * ((double) excess) / dashXAngleStep; len += excesslen; } if (oddSide) totallen += (sidelen - len); else totallen += len; return totallen;}/* * len is along the arc, but may be more than one rotation */static intlengthToAngle (len, map) double len; dashMap *map;{ double sidelen = map->map[DASH_MAP_SIZE - 1]; int angle, angleexcess; Bool oddSide = FALSE; int a0, a1, a; angle = 0; /* * step around the ellipse, subtracting sidelens and * adding 90 degrees. oddSide will tell if the * map should be interpolated in reverse */ if (len >= 0) { if (sidelen == 0) return 2 * FULLCIRCLE; /* infinity */ while (len >= sidelen) { angle += 90 * 64; len -= sidelen; oddSide = !oddSide; } } else { if (sidelen == 0) return -2 * FULLCIRCLE; /* infinity */ while (len < 0) { angle -= 90 * 64; len += sidelen; oddSide = !oddSide; } } if (oddSide) len = sidelen - len; a0 = 0; a1 = DASH_MAP_SIZE - 1; /* * binary search for the closest pre-computed length */ while (a1 - a0 > 1) { a = (a0 + a1) / 2; if (len > map->map[a]) a0 = a; else a1 = a; } angleexcess = dashIndexToXAngle (a0); /* * linearly interpolate to the next point */ angleexcess += (len - map->map[a0]) / (map->map[a0+1] - map->map[a0]) * dashXAngleStep; if (oddSide) angle += (90 * 64) - angleexcess; else angle += angleexcess; return angle;}/* * compute the angle of an ellipse which cooresponds to * the given path length. Note that the correct solution * to this problem is an eliptic integral, we'll punt and * approximate (it's only for dashes anyway). This * approximation uses a polygon. * * The remaining portion of len is stored in *lenp - * this will be negative if the arc extends beyond * len and positive if len extends beyond the arc. */static intcomputeAngleFromPath (startAngle, endAngle, map, lenp, backwards) int startAngle, endAngle; /* normalized absolute angles in *64 degrees */ dashMap *map; int *lenp; int backwards;{ int a0, a1, a; double len0; int len; a0 = startAngle; a1 = endAngle; len = *lenp; if (backwards) { /* * flip the problem around to always be * forwards */ a0 = FULLCIRCLE - a0; a1 = FULLCIRCLE - a1; } if (a1 < a0) a1 += FULLCIRCLE; len0 = angleToLength (a0, map); a = lengthToAngle (len0 + len, map); if (a > a1) { a = a1; len -= angleToLength (a1, map) - len0; } else len = 0; if (backwards) a = FULLCIRCLE - a; *lenp = len; return a;}/* * scan convert wide arcs. *//* * draw zero width/height arcs */static voiddrawZeroArc (pDraw, pGC, tarc, lw, left, right) DrawablePtr pDraw; GCPtr pGC; xArc *tarc; int lw; miArcFacePtr right, left;{ double x0, y0, x1, y1, w, h, x, y; double xmax, ymax, xmin, ymin; int a0, a1; double a, startAngle, endAngle; double l, lx, ly; l = lw / 2.0; a0 = tarc->angle1; a1 = tarc->angle2; if (a1 > FULLCIRCLE) a1 = FULLCIRCLE; else if (a1 < -FULLCIRCLE) a1 = -FULLCIRCLE; w = (double)tarc->width / 2.0; h = (double)tarc->height / 2.0; /* * play in X coordinates right away */ startAngle = - ((double) a0 / 64.0); endAngle = - ((double) (a0 + a1) / 64.0); xmax = -w; xmin = w; ymax = -h; ymin = h; a = startAngle; for (;;) { x = w * miDcos(a); y = h * miDsin(a); if (a == startAngle) { x0 = x; y0 = y; } if (a == endAngle) { x1 = x; y1 = y; } if (x > xmax) xmax = x; if (x < xmin) xmin = x; if (y > ymax) ymax = y; if (y < ymin) ymin = y; if (a == endAngle) break; if (a1 < 0) /* clockwise */ { if (floor (a / 90.0) == floor (endAngle / 90.0)) a = endAngle; else a = 90 * (floor (a/90.0) + 1); } else { if (ceil (a / 90.0) == ceil (endAngle / 90.0)) a = endAngle; else a = 90 * (ceil (a/90.0) - 1); } } lx = ly = l; if ((x1 - x0) + (y1 - y0) < 0) lx = ly = -l; if (h) { ly = 0.0; lx = -lx; } else lx = 0.0; if (right) { right->center.x = x0; right->center.y = y0; right->clock.x = x0 - lx; right->clock.y = y0 - ly; right->counterClock.x = x0 + lx; right->counterClock.y = y0 + ly; } if (left) { left->center.x = x1; left->center.y = y1; left->clock.x = x1 + lx; left->clock.y = y1 + ly; left->counterClock.x = x1 - lx; left->counterClock.y = y1 - ly; } x0 = xmin; x1 = xmax; y0 = ymin; y1 = ymax; if (ymin != y1) { xmin = -l; xmax = l; } else { ymin = -l; ymax = l; } if (xmax != xmin && ymax != ymin) { int minx, maxx, miny, maxy; xRectangle rect; minx = ICEIL (xmin + w) + tarc->x; maxx = ICEIL (xmax + w) + tarc->x; miny = ICEIL (ymin + h) + tarc->y; maxy = ICEIL (ymax + h) + tarc->y; rect.x = minx; rect.y = miny; rect.width = maxx - minx; rect.height = maxy - miny; (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); }}/* * this computes the ellipse y value associated with the * bottom of the tail. */static voidtailEllipseY (def, acc) struct arc_def *def; struct accelerators *acc;{ double t; acc->tail_y = 0.0; if (def->w == def->h) return; t = def->l * def->w; if (def->w > def->h) { if (t < acc->h2) return; } else { if (t > acc->h2) return; } t = 2.0 * def->h * t; t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2; if (t > 0.0) acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t);}/* * inverse functions -- compute edge coordinates * from the ellipse */static doubleouterXfromXY (x, y, def, acc) double x, y; struct arc_def *def; struct accelerators *acc;{ return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);}static doubleouterYfromXY (x, y, def, acc) double x, y; struct arc_def *def; struct accelerators *acc;{ return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);}static doubleinnerXfromXY (x, y, def, acc) double x, y; struct arc_def *def; struct accelerators *acc;{ return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);}static doubleinnerYfromXY (x, y, def, acc) double x, y; struct arc_def *def; struct accelerators *acc;{ return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);}static doubleinnerYfromY (y, def, acc) double y; struct arc_def *def; struct accelerators *acc;{ double x; x = (def->w / def->h) * sqrt (acc->h2 - y*y); return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);}static voidcomputeLine (x1, y1, x2, y2, line) double x1, y1, x2, y2; struct line *line;{ if (y1 == y2) line->valid = 0; else { line->m = (x1 - x2) / (y1 - y2); line->b = x1 - y1 * line->m; line->valid = 1; }}/* * compute various accelerators for an ellipse. These * are simply values that are used repeatedly in * the computations */static voidcomputeAcc (tarc, lw, def, acc) xArc *tarc; int lw; struct arc_def *def; struct accelerators *acc;{ def->w = ((double) tarc->width) / 2.0; def->h = ((double) tarc->height) / 2.0; def->l = ((double) lw) / 2.0; acc->h2 = def->h * def->h; acc->w2 = def->w * def->w; acc->h4 = acc->h2 * acc->h2; acc->w4 = acc->w2 * acc->w2; acc->h2l = acc->h2 * def->l; acc->w2l = acc->w2 * def->l; acc->h2mw2 = acc->h2 - acc->w2; acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0; acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0; acc->xorg = tarc->x + (tarc->width >> 1); acc->yorgu = tarc->y + (tarc->height >> 1); acc->yorgl = acc->yorgu + (tarc->height & 1); tailEllipseY (def, acc);} /* * compute y value bounds of various portions of the arc, * the outer edge, the ellipse and the inner edge. */static voidcomputeBound (def, bound, acc, right, left) struct arc_def *def; struct arc_bound *bound; struct accelerators *acc; miArcFacePtr right, left;{ double t; double innerTaily; double tail_y; struct bound innerx, outerx; struct bound ellipsex; bound->ellipse.min = Dsin (def->a0) * def->h; bound->ellipse.max = Dsin (def->a1) * def->h; if (def->a0 == 45 && def->w == def->h) ellipsex.min = bound->ellipse.min; else ellipsex.min = Dcos (def->a0) * def->w; if (def->a1 == 45 && def->w == def->h) ellipsex.max = bound->ellipse.max; else ellipsex.max = Dcos (def->a1) * def->w; bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc); bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc); outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc); innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc); /* * save the line end points for the * cap code to use. Careful here, these are * in cartesean coordinates (y increasing upwards) * while the cap code uses inverted coordinates * (y increasing downwards) */ if (right) { right->counterClock.y = bound->outer.min; right->counterClock.x = outerx.min; right->center.y = bound->ellipse.min; right->center.x = ellipsex.min; right->clock.y = bound->inner.min; right->clock.x = innerx.min; } if (left) { left->clock.y = bound->outer.max; left->clock.x = outerx.max; left->center.y = bound->ellipse.max; left->center.x = ellipsex.max; left->counterClock.y = bound->inner.max; left->counterClock.x = innerx.max; } bound->left.min = bound->inner.max; bound->left.max = bound->outer.max; bound->right.min = bound->inner.min; bound->right.max = bound->outer.min; computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min, &acc->right); computeLine (innerx.max, bound->inner.m
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -