📄 miarc.c
字号:
* so that it divides evenly into the total. * I'm just using cdt 'cause I'm lazy. */ cdt = parc->width; if (parc->height > cdt) cdt = parc->height; cdt /= 2.0; if(cdt <= 0) return 0; if (cdt < 1.0) cdt = 1.0; dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */ count = et/dt; count = abs(count) + 1; dt = et/count; count++; cdt = 2 * miDcos(dt); if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts, (cpt + count) * sizeof(SppPointRec)))) return(0); *ppPts = poly; xc = parc->width/2.0; /* store half width and half height */ yc = parc->height/2.0; x0 = xc * miDcos(st); y0 = yc * miDsin(st); x1 = xc * miDcos(st + dt); y1 = yc * miDsin(st + dt); xc += parc->x; /* by adding initial point, these become */ yc += parc->y; /* the center point */ poly[cpt].x = (xc + x0); poly[cpt].y = (yc + y0); last.x = ROUNDTOINT( poly[cpt + 1].x = (xc + x1) ); last.y = ROUNDTOINT( poly[cpt + 1].y = (yc + y1) ); for(i = 2; i < count; i++) { x2 = cdt * x1 - x0; y2 = cdt * y1 - y0; poly[cpt + i].x = (xc + x2); poly[cpt + i].y = (yc + y2); x0 = x1; y0 = y1; x1 = x2; y1 = y2; } /* adjust the last point */ if (abs(parc->angle2) >= 360.0) poly[cpt +i -1] = poly[0]; else { poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc); poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc); } return(count);}struct arcData { double x0, y0, x1, y1; int selfJoin;};# define ADD_REALLOC_STEP 20static voidaddCap (capsp, ncapsp, sizep, end, arcIndex) miArcCapPtr *capsp; int *ncapsp, *sizep; int end, arcIndex;{ int newsize; miArcCapPtr cap; if (*ncapsp == *sizep) { newsize = *sizep + ADD_REALLOC_STEP; cap = (miArcCapPtr) xrealloc (*capsp, newsize * sizeof (**capsp)); if (!cap) return; *sizep = newsize; *capsp = cap; } cap = &(*capsp)[*ncapsp]; cap->end = end; cap->arcIndex = arcIndex; ++*ncapsp;}static voidaddJoin (joinsp, njoinsp, sizep, end0, index0, phase0, end1, index1, phase1) miArcJoinPtr *joinsp; int *njoinsp, *sizep; int end0, index0, phase0, end1, index1, phase1;{ int newsize; miArcJoinPtr join; if (*njoinsp == *sizep) { newsize = *sizep + ADD_REALLOC_STEP; join = (miArcJoinPtr) xrealloc (*joinsp, newsize * sizeof (**joinsp)); if (!join) return; *sizep = newsize; *joinsp = join; } join = &(*joinsp)[*njoinsp]; join->end0 = end0; join->arcIndex0 = index0; join->phase0 = phase0; join->end1 = end1; join->arcIndex1 = index1; join->phase1 = phase1; ++*njoinsp;}static miArcDataPtraddArc (arcsp, narcsp, sizep, xarc) miArcDataPtr *arcsp; int *narcsp, *sizep; xArc *xarc;{ int newsize; miArcDataPtr arc; if (*narcsp == *sizep) { newsize = *sizep + ADD_REALLOC_STEP; arc = (miArcDataPtr) xrealloc (*arcsp, newsize * sizeof (**arcsp)); if (!arc) return (miArcDataPtr)NULL; *sizep = newsize; *arcsp = arc; } arc = &(*arcsp)[*narcsp]; arc->arc = *xarc; ++*narcsp; return arc;}static voidmiFreeArcs(arcs, pGC) miPolyArcPtr arcs; GCPtr pGC;{ int iphase; for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); iphase >= 0; iphase--) { if (arcs[iphase].narcs > 0) xfree(arcs[iphase].arcs); if (arcs[iphase].njoins > 0) xfree(arcs[iphase].joins); if (arcs[iphase].ncaps > 0) xfree(arcs[iphase].caps); } xfree(arcs);}/* * map angles to radial distance. This only deals with the first quadrant *//* * a polygonal approximation to the arc for computing arc lengths */# define DASH_MAP_SIZE 91# define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))# define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))# define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))# define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))typedef struct { double map[DASH_MAP_SIZE];} dashMap;static voidcomputeDashMap (arcp, map) xArc *arcp; dashMap *map;{ int di; double a, x, y, prevx, prevy, dist; for (di = 0; di < DASH_MAP_SIZE; di++) { a = dashIndexToAngle (di); x = ((double) arcp->width / 2.0) * miDcos (a); y = ((double) arcp->height / 2.0) * miDsin (a); if (di == 0) { map->map[di] = 0.0; } else { dist = hypot (x - prevx, y - prevy); map->map[di] = map->map[di - 1] + dist; } prevx = x; prevy = y; }}typedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes;/* this routine is a bit gory */static miPolyArcPtrmiComputeArcs (parcs, narcs, pGC) xArc *parcs; int narcs; GCPtr pGC;{ int isDashed, isDoubleDash; int dashOffset; miPolyArcPtr arcs; int start, i, j, k, nexti, nextk; int joinSize[2]; int capSize[2]; int arcSize[2]; int angle2; double a0, a1; struct arcData *data; miArcDataPtr arc; xArc xarc; int iphase, prevphase, joinphase; int arcsJoin; int selfJoin; int iDash, dashRemaining; int iDashStart, dashRemainingStart, iphaseStart; int startAngle, spanAngle, endAngle, backwards; int prevDashAngle, dashAngle; dashMap map; isDashed = !(pGC->lineStyle == LineSolid); isDoubleDash = (pGC->lineStyle == LineDoubleDash); dashOffset = pGC->dashOffset; data = (struct arcData *) ALLOCATE_LOCAL (narcs * sizeof (struct arcData)); if (!data) return (miPolyArcPtr)NULL; arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1)); if (!arcs) { DEALLOCATE_LOCAL(data); return (miPolyArcPtr)NULL; } for (i = 0; i < narcs; i++) { a0 = todeg (parcs[i].angle1); angle2 = parcs[i].angle2; if (angle2 > FULLCIRCLE) angle2 = FULLCIRCLE; else if (angle2 < -FULLCIRCLE) angle2 = -FULLCIRCLE; data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE; a1 = todeg (parcs[i].angle1 + angle2); data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0)); data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0)); data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1)); data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1)); } for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) { arcs[iphase].njoins = 0; arcs[iphase].joins = 0; joinSize[iphase] = 0; arcs[iphase].ncaps = 0; arcs[iphase].caps = 0; capSize[iphase] = 0; arcs[iphase].narcs = 0; arcs[iphase].arcs = 0; arcSize[iphase] = 0; } iphase = 0; if (isDashed) { iDash = 0; dashRemaining = pGC->dash[0]; while (dashOffset > 0) { if (dashOffset >= dashRemaining) { dashOffset -= dashRemaining; iphase = iphase ? 0 : 1; iDash++; if (iDash == pGC->numInDashList) iDash = 0; dashRemaining = pGC->dash[iDash]; } else { dashRemaining -= dashOffset; dashOffset = 0; } } iDashStart = iDash; dashRemainingStart = dashRemaining; } iphaseStart = iphase; for (i = narcs - 1; i >= 0; i--) { j = i + 1; if (j == narcs) j = 0; if (data[i].selfJoin || i == j || (UNEQUAL (data[i].x1, data[j].x0) || UNEQUAL (data[i].y1, data[j].y0))) { if (iphase == 0 || isDoubleDash) addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, &capSize[iphase], RIGHT_END, 0); break; } } start = i + 1; if (start == narcs) start = 0; i = start; for (;;) { j = i + 1; if (j == narcs) j = 0; nexti = i+1; if (nexti == narcs) nexti = 0; if (isDashed) { /* ** deal with dashed arcs. Use special rules for certain 0 area arcs. ** Presumably, the other 0 area arcs still aren't done right. */ arcTypes arcType = OTHER; CARD16 thisLength; if (parcs[i].height == 0 && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00 && parcs[i].angle2 == 0x2d00) arcType = HORIZONTAL; else if (parcs[i].width == 0 && (parcs[i].angle1 % FULLCIRCLE) == 0x1680 && parcs[i].angle2 == 0x2d00) arcType = VERTICAL; if (arcType == OTHER) { /* * precompute an approximation map */ computeDashMap (&parcs[i], &map); /* * compute each individual dash segment using the path * length function */ startAngle = parcs[i].angle1; spanAngle = parcs[i].angle2; if (spanAngle > FULLCIRCLE) spanAngle = FULLCIRCLE; else if (spanAngle < -FULLCIRCLE) spanAngle = -FULLCIRCLE; if (startAngle < 0) startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; if (startAngle >= FULLCIRCLE) startAngle = startAngle % FULLCIRCLE; endAngle = startAngle + spanAngle; backwards = spanAngle < 0; } else { xarc = parcs[i]; if (arcType == VERTICAL) { xarc.angle1 = 0x1680; startAngle = parcs[i].y; endAngle = startAngle + parcs[i].height; } else { xarc.angle1 = 0x2d00; startAngle = parcs[i].x; endAngle = startAngle + parcs[i].width; } } dashAngle = startAngle; selfJoin = data[i].selfJoin && (iphase == 0 || isDoubleDash); /* * add dashed arcs to each bucket */ arc = 0; while (dashAngle != endAngle) { prevDashAngle = dashAngle; if (arcType == OTHER) { dashAngle = computeAngleFromPath (prevDashAngle, endAngle, &map, &dashRemaining, backwards); /* avoid troubles with huge arcs and small dashes */ if (dashAngle == prevDashAngle) { if (backwards) dashAngle--; else dashAngle++; } } else { thisLength = (dashAngle + dashRemaining <= endAngle) ? dashRemaining : endAngle - dashAngle; if (arcType == VERTICAL) { xarc.y = dashAngle; xarc.height = thisLength; } else { xarc.x = dashAngle; xarc.width = thisLength; } dashAngle += thisLength; dashRemaining -= thisLength; } if (iphase == 0 || isDoubleDash) { if (arcType == OTHER) { xarc = parcs[i]; spanAngle = prevDashAngle; if (spanAngle < 0) spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE; if (spanAngle >= FULLCIRCLE) spanAngle = spanAngle % FULLCIRCLE; xarc.angle1 = spanAngle; spanAngle = dashAngle - prevDashAngle; if (backwards) { if (dashAngle > prevDashAngle) spanAngle = - FULLCIRCLE + spanAngle; } else { if (dashAngle < prevDashAngle) spanAngle = FULLCIRCLE + spanAngle; } if (spanAngle > FULLCIRCLE) spanAngle = FULLCIRCLE; if (spanAngle < -FULLCIRCLE) spanAngle = -FULLCIRCLE; xarc.angle2 = spanAngle; } arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, &arcSize[iphase], &xarc); if (!arc) goto arcfail; /* * cap each end of an on/off dash */ if (!isDoubleDash) { if (prevDashAngle != startAngle) { addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, &capSize[iphase], RIGHT_END, arc - arcs[iphase].arcs); } if (dashAngle != endAngle) { addCap (&arcs[iphase].caps, &arcs[iphase].ncaps, &capSize[iphase], LEFT_END, arc - arcs[iphase].arcs); } } arc->cap = arcs[iphase].ncaps; arc->join = arcs[iphase].njoins; arc->render = 0; arc->selfJoin = 0; if (dashAngle == endAngle) arc->selfJoin = selfJoin; } prevphase = iphase; if (dashRemaining <= 0) { ++iDash; if (iDash == pGC->numInDashList) iDash = 0; iphase = iphase ? 0:1; dashRemaining = pGC->dash[iDash]; } } /* * make sure a place exists for the position data when * drawing a zero-length arc */ if (startAngle == endAngle) { prevphase = iphase; if (!isDoubleDash && iphase == 1) prevphase = 0; arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs, &arcSize[prevphase], &parcs[i]); if (!arc) goto arcfail; arc->join = arcs[prevphase].njoins; arc->cap = arcs[prevphase].ncaps; arc->selfJoin = data[i].selfJoin; } } else { arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs, &arcSize[iphase], &parcs[i]); if (!arc) goto arcfail; arc->join = arcs[iphase].njoins; arc->cap = arcs[iphase].ncaps; arc->selfJoin = data[i].selfJoin; prevphase = iphase; } if (prevphase == 0 || isDoubleDash) k = arcs[prevphase].narcs - 1; if (iphase == 0 || isDoubleDash) nextk = arcs[iphase].narcs; if (nexti == start) { nextk = 0; if (isDashed) { iDash = iDashStart; iphase = iphaseStart; dashRemaining = dashRemainingStart; } } arcsJoin = narcs > 1 && i != j && ISEQUAL (data[i].x1, data[j].x0) && ISEQUAL (data[i].y1, data[j].y0) && !data[i].selfJoin && !data[j].selfJoin; if (arc) { if (arcsJoin) arc->render = 0; else arc->render = 1; } if (arcsJoin && (prevphase == 0 || isDoubleDash) && (iphase == 0 || isDoubleDash)) { joinphase = iphase; if (isDoubleDash) { if (nexti == start) joinphase = iphaseStart; /* * if the join is right at the dash, * draw the join in foreground * This is because the foreground * arcs are computed second, the results * of which are needed to draw the join */ if (joinphase != prevphase) joinphase = 0; } if (joinphase == 0 || isDoubleDash) { addJoin (&arcs[joinphase].joins, &arcs[joinphase].njoins, &joinSize[joinphase], LEFT_END, k, prevphase, RIGHT_END, nextk, iphase); arc->join = arcs[prevphase].njoins; } } else { /* * cap the left end of this arc * unless it joins itself */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -