📄 miarc.c
字号:
fTricky = FALSE; pDrawTo = pDraw; pGCTo = pGC; break; default: fTricky = TRUE; /* find bounding box around arcs */ xMin = yMin = MAXSHORT; xMax = yMax = MINSHORT; for(i = narcs, parc = parcs; --i >= 0; parc++) { xMin = min (xMin, parc->x); yMin = min (yMin, parc->y); xMax = max (xMax, (parc->x + (int) parc->width)); yMax = max (yMax, (parc->y + (int) parc->height)); } /* expand box to deal with line widths */ halfWidth = (width + 1)/2; xMin -= halfWidth; yMin -= halfWidth; xMax += halfWidth; yMax += halfWidth; /* compute pixmap size; limit it to size of drawable */ xOrg = max(xMin, 0); yOrg = max(yMin, 0); pixmapWidth = min(xMax, pDraw->width) - xOrg; pixmapHeight = min(yMax, pDraw->height) - yOrg; /* if nothing left, return */ if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return; for(i = narcs, parc = parcs; --i >= 0; parc++) { parc->x -= xOrg; parc->y -= yOrg; } if (pGC->miTranslate) { xOrg += pDraw->x; yOrg += pDraw->y; } /* set up scratch GC */ pGCTo = GetScratchGC(1, pDraw->pScreen); if (!pGCTo) return; gcvals[GCValsFunction] = GXcopy; gcvals[GCValsForeground] = 1; gcvals[GCValsBackground] = 0; gcvals[GCValsLineWidth] = pGC->lineWidth; gcvals[GCValsCapStyle] = pGC->capStyle; gcvals[GCValsJoinStyle] = pGC->joinStyle; dixChangeGC(NullClient, pGCTo, GCValsMask, gcvals, NULL); /* allocate a 1 bit deep pixmap of the appropriate size, and * validate it */ pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap) (pDraw->pScreen, pixmapWidth, pixmapHeight, 1); if (!pDrawTo) { FreeScratchGC(pGCTo); return; } ValidateGC(pDrawTo, pGCTo); miClearDrawable(pDrawTo, pGCTo); } fg = pGC->fgPixel; bg = pGC->bgPixel; if ((pGC->fillStyle == FillTiled) || (pGC->fillStyle == FillOpaqueStippled)) bg = fg; /* the protocol sez these don't cause color changes */ polyArcs = miComputeArcs (parcs, narcs, pGC); if (!polyArcs) { if (fTricky) { (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo); FreeScratchGC (pGCTo); } return; } cap[0] = cap[1] = 0; join[0] = join[1] = 0; for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0); iphase >= 0; iphase--) { if (iphase == 1) { dixChangeGC (NullClient, pGC, GCForeground, &bg, NULL); ValidateGC (pDraw, pGC); } else if (pGC->lineStyle == LineDoubleDash) { dixChangeGC (NullClient, pGC, GCForeground, &fg, NULL); ValidateGC (pDraw, pGC); } for (i = 0; i < polyArcs[iphase].narcs; i++) { miArcDataPtr arcData; arcData = &polyArcs[iphase].arcs[i]; miArcSegment(pDrawTo, pGCTo, arcData->arc, &arcData->bounds[RIGHT_END], &arcData->bounds[LEFT_END]); if (polyArcs[iphase].arcs[i].render) { fillSpans (pDrawTo, pGCTo); /* * don't cap self-joining arcs */ if (polyArcs[iphase].arcs[i].selfJoin && cap[iphase] < polyArcs[iphase].arcs[i].cap) cap[iphase]++; while (cap[iphase] < polyArcs[iphase].arcs[i].cap) { int arcIndex, end; miArcDataPtr arcData0; arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex; end = polyArcs[iphase].caps[cap[iphase]].end; arcData0 = &polyArcs[iphase].arcs[arcIndex]; miArcCap (pDrawTo, pGCTo, &arcData0->bounds[end], end, arcData0->arc.x, arcData0->arc.y, (double) arcData0->arc.width / 2.0, (double) arcData0->arc.height / 2.0); ++cap[iphase]; } while (join[iphase] < polyArcs[iphase].arcs[i].join) { int arcIndex0, arcIndex1, end0, end1; int phase0, phase1; miArcDataPtr arcData0, arcData1; miArcJoinPtr joinp; joinp = &polyArcs[iphase].joins[join[iphase]]; arcIndex0 = joinp->arcIndex0; end0 = joinp->end0; arcIndex1 = joinp->arcIndex1; end1 = joinp->end1; phase0 = joinp->phase0; phase1 = joinp->phase1; arcData0 = &polyArcs[phase0].arcs[arcIndex0]; arcData1 = &polyArcs[phase1].arcs[arcIndex1]; miArcJoin (pDrawTo, pGCTo, &arcData0->bounds[end0], &arcData1->bounds[end1], arcData0->arc.x, arcData0->arc.y, (double) arcData0->arc.width / 2.0, (double) arcData0->arc.height / 2.0, arcData1->arc.x, arcData1->arc.y, (double) arcData1->arc.width / 2.0, (double) arcData1->arc.height / 2.0); ++join[iphase]; } if (fTricky) { if (pGC->serialNumber != pDraw->serialNumber) ValidateGC (pDraw, pGC); (*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo, pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg); miClearDrawable ((DrawablePtr) pDrawTo, pGCTo); } } } } miFreeArcs(polyArcs, pGC); if(fTricky) { (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo); FreeScratchGC(pGCTo); } }}static doubleangleBetween (center, point1, point2) SppPointRec center, point1, point2;{ double a1, a2, a; /* * reflect from X coordinates back to ellipse * coordinates -- y increasing upwards */ a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x); a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x); a = a2 - a1; if (a <= -180.0) a += 360.0; else if (a > 180.0) a -= 360.0; return a;}static voidtranslateBounds (b, x, y, fx, fy)miArcFacePtr b;int x, y;double fx, fy;{ fx += x; fy += y; b->clock.x -= fx; b->clock.y -= fy; b->center.x -= fx; b->center.y -= fy; b->counterClock.x -= fx; b->counterClock.y -= fy;}static voidmiArcJoin (pDraw, pGC, pLeft, pRight, xOrgLeft, yOrgLeft, xFtransLeft, yFtransLeft, xOrgRight, yOrgRight, xFtransRight, yFtransRight) DrawablePtr pDraw; GCPtr pGC; miArcFacePtr pRight, pLeft; int xOrgRight, yOrgRight; double xFtransRight, yFtransRight; int xOrgLeft, yOrgLeft; double xFtransLeft, yFtransLeft;{ SppPointRec center, corner, otherCorner; SppPointRec poly[5], e; SppPointPtr pArcPts; int cpt; SppArcRec arc; miArcFaceRec Right, Left; int polyLen; int xOrg, yOrg; double xFtrans, yFtrans; double a; double ae, ac2, ec2, bc2, de; double width; xOrg = (xOrgRight + xOrgLeft) / 2; yOrg = (yOrgRight + yOrgLeft) / 2; xFtrans = (xFtransLeft + xFtransRight) / 2; yFtrans = (yFtransLeft + yFtransRight) / 2; Right = *pRight; translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight, xFtrans - xFtransRight, yFtrans - yFtransRight); Left = *pLeft; translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft, xFtrans - xFtransLeft, yFtrans - yFtransLeft); pRight = &Right; pLeft = &Left; if (pRight->clock.x == pLeft->counterClock.x && pRight->clock.y == pLeft->counterClock.y) return; center = pRight->center; if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock)) && a <= 180.0) { corner = pRight->clock; otherCorner = pLeft->counterClock; } else { a = angleBetween (center, pLeft->clock, pRight->counterClock); corner = pLeft->clock; otherCorner = pRight->counterClock; } switch (pGC->joinStyle) { case JoinRound: width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); arc.x = center.x - width/2; arc.y = center.y - width/2; arc.width = width; arc.height = width; arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x); arc.angle2 = a; pArcPts = (SppPointPtr) xalloc (3 * sizeof (SppPointRec)); if (!pArcPts) return; pArcPts[0].x = otherCorner.x; pArcPts[0].y = otherCorner.y; pArcPts[1].x = center.x; pArcPts[1].y = center.y; pArcPts[2].x = corner.x; pArcPts[2].y = corner.y; if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) ) { /* by drawing with miFillSppPoly and setting the endpoints of the arc * to be the corners, we assure that the cap will meet up with the * rest of the line */ miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans); } xfree(pArcPts); return; case JoinMiter: /* * don't miter arcs with less than 11 degrees between them */ if (a < 169.0) { poly[0] = corner; poly[1] = center; poly[2] = otherCorner; bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) + (corner.y - otherCorner.y) * (corner.y - otherCorner.y); ec2 = bc2 / 4; ac2 = (corner.x - center.x) * (corner.x - center.x) + (corner.y - center.y) * (corner.y - center.y); ae = sqrt (ac2 - ec2); de = ec2 / ae; e.x = (corner.x + otherCorner.x) / 2; e.y = (corner.y + otherCorner.y) / 2; poly[3].x = e.x + de * (e.x - center.x) / ae; poly[3].y = e.y + de * (e.y - center.y) / ae; poly[4] = corner; polyLen = 5; break; } case JoinBevel: poly[0] = corner; poly[1] = center; poly[2] = otherCorner; poly[3] = corner; polyLen = 4; break; } miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);}/*ARGSUSED*/static voidmiArcCap (pDraw, pGC, pFace, end, xOrg, yOrg, xFtrans, yFtrans) DrawablePtr pDraw; GCPtr pGC; miArcFacePtr pFace; int end; int xOrg, yOrg; double xFtrans, yFtrans;{ SppPointRec corner, otherCorner, center, endPoint, poly[5]; corner = pFace->clock; otherCorner = pFace->counterClock; center = pFace->center; switch (pGC->capStyle) { case CapProjecting: poly[0].x = otherCorner.x; poly[0].y = otherCorner.y; poly[1].x = corner.x; poly[1].y = corner.y; poly[2].x = corner.x - (center.y - corner.y); poly[2].y = corner.y + (center.x - corner.x); poly[3].x = otherCorner.x - (otherCorner.y - center.y); poly[3].y = otherCorner.y + (otherCorner.x - center.x); poly[4].x = otherCorner.x; poly[4].y = otherCorner.y; miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans); break; case CapRound: /* * miRoundCap just needs these to be unequal. */ endPoint = center; endPoint.x = endPoint.x + 100; miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0, -xOrg, -yOrg, xFtrans, yFtrans); break; }}/* MIROUNDCAP -- a private helper function * Put Rounded cap on end. pCenter is the center of this end of the line * pEnd is the center of the other end of the line. pCorner is one of the * two corners at this end of the line. * NOTE: pOtherCorner must be counter-clockwise from pCorner. *//*ARGSUSED*/static voidmiRoundCap(pDraw, pGC, pCenter, pEnd, pCorner, pOtherCorner, fLineEnd, xOrg, yOrg, xFtrans, yFtrans) DrawablePtr pDraw; GCPtr pGC; SppPointRec pCenter, pEnd; SppPointRec pCorner, pOtherCorner; int fLineEnd, xOrg, yOrg; double xFtrans, yFtrans;{ int cpt; double width; double miDatan2 (); SppArcRec arc; SppPointPtr pArcPts; width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1); arc.x = pCenter.x - width/2; arc.y = pCenter.y - width/2; arc.width = width; arc.height = width; arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x); if(PTISEQUAL(pCenter, pEnd)) arc.angle2 = - 180.0; else { arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1; if (arc.angle2 < 0) arc.angle2 += 360.0; } pArcPts = (SppPointPtr) NULL; if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) ) { /* by drawing with miFillSppPoly and setting the endpoints of the arc * to be the corners, we assure that the cap will meet up with the * rest of the line */ miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans); } xfree(pArcPts);}/* * To avoid inaccuracy at the cardinal points, use trig functions * which are exact for those angles */#ifndef M_PI#define M_PI 3.14159265358979323846#endif#ifndef M_PI_2#define M_PI_2 1.57079632679489661923#endif# define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))# define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))# define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))static doublemiDcos (a)double a;{ int i; if (floor (a/90) == a/90) { i = (int) (a/90.0); switch (mod (i, 4)) { case 0: return 1; case 1: return 0; case 2: return -1; case 3: return 0; } } return cos (a * M_PI / 180.0);}static doublemiDsin (a)double a;{ int i; if (floor (a/90) == a/90) { i = (int) (a/90.0); switch (mod (i, 4)) { case 0: return 0; case 1: return 1; case 2: return 0; case 3: return -1; } } return sin (a * M_PI / 180.0);}static doublemiDasin (v)double v;{ if (v == 0) return 0.0; if (v == 1.0) return 90.0; if (v == -1.0) return -90.0; return asin(v) * (180.0 / M_PI);}static doublemiDatan2 (dy, dx)double dy, dx;{ if (dy == 0) { if (dx >= 0) return 0.0; return 180.0; } else if (dx == 0) { if (dy > 0) return 90.0; return -90.0; } else if (Fabs (dy) == Fabs (dx)) { if (dy > 0) { if (dx > 0) return 45.0; return 135.0; } else { if (dx > 0) return 315.0; return 225.0; } } else { return atan2 (dy, dx) * (180.0 / M_PI); }}/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper * routine for filled arc and line (round cap) code. * Returns the number of points in the arc. Note that it takes a pointer * to a pointer to where it should put the points and an index (cpt). * This procedure allocates the space necessary to fit the arc points. * Sometimes it's convenient for those points to be at the end of an existing * array. (For example, if we want to leave a spare point to make sectors * instead of segments.) So we pass in the xalloc()ed chunk that contains the * array and an index saying where we should start stashing the points. * If there isn't an array already, we just pass in a null pointer and * count on xrealloc() to handle the null pointer correctly. */static intmiGetArcPts(parc, cpt, ppPts) SppArcPtr parc; /* points to an arc */ int cpt; /* number of points already in arc list */ SppPointPtr *ppPts; /* pointer to pointer to arc-list -- modified */{ double st, /* Start Theta, start angle */ et, /* End Theta, offset from start theta */ dt, /* Delta Theta, angle to sweep ellipse */ cdt, /* Cos Delta Theta, actually 2 cos(dt) */ x0, y0, /* the recurrence formula needs two points to start */ x1, y1, x2, y2, /* this will be the new point generated */ xc, yc; /* the center point */ int count, i; SppPointPtr poly; DDXPointRec last; /* last point on integer boundaries */ /* The spec says that positive angles indicate counterclockwise motion. * Given our coordinate system (with 0,0 in the upper left corner), * the screen appears flipped in Y. The easiest fix is to negate the * angles given */ st = - parc->angle1; et = - parc->angle2; /* Try to get a delta theta that is within 1/2 pixel. Then adjust it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -