📄 miarc.c
字号:
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, GDK_DRAWABLE_FBDATA(pDraw)->width) - xOrg; pixmapHeight = MIN(yMax, GDK_DRAWABLE_FBDATA(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; } /* set up scratch GC */ /* allocate a 1 bit deep pixmap of the appropriate size, and * validate it */ pDrawTo = gdk_pixmap_new(NULL, pixmapWidth, pixmapHeight, 1); if (!pDrawTo) return; pGCTo = gdk_gc_new(pDrawTo); if (!pGCTo) { gdk_pixmap_unref(pDrawTo); return; } gdk_gc_set_function(pGCTo, GDK_COPY); memset(&gcv.background, 0, sizeof(GdkColor)); gcv.foreground.pixel = 1; gcv.foreground.red = gcv.foreground.green = gcv.foreground.blue = 1; gdk_gc_set_foreground(pGCTo, &gcv.foreground); gdk_gc_set_background(pGCTo, &gcv.background); gdk_gc_set_line_attributes(pGCTo, GDK_GC_FBDATA(pGC)->values.line_width, GDK_GC_FBDATA(pGC)->values.line_style, GDK_GC_FBDATA(pGC)->values.cap_style, GDK_GC_FBDATA(pGC)->values.join_style); gdk_fb_drawable_clear(pDrawTo); } fg = GDK_GC_FBDATA(pGC)->values.foreground; bg = GDK_GC_FBDATA(pGC)->values.background; if ((GDK_GC_FBDATA(pGC)->values.fill == GDK_TILED) || (GDK_GC_FBDATA(pGC)->values.fill == GDK_OPAQUE_STIPPLED)) bg = fg; /* the protocol sez these don't cause color changes */ polyArcs = miComputeArcs (parcs, narcs, pGC); if (!polyArcs) { if (fTricky) { gdk_pixmap_unref(pDrawTo); gdk_gc_unref(pGCTo); } return; } cap[0] = cap[1] = 0; join[0] = join[1] = 0; for (iphase = ((GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH) ? 1 : 0); iphase >= 0; iphase--) { if (iphase == 1) gdk_gc_set_foreground(pGC, &bg); else if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH) gdk_gc_set_foreground(pGC, &fg); 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) { gdk_fb_draw_drawable(pDraw, pGC, pDrawTo, 0, 0, xOrg, yOrg, pixmapWidth, pixmapHeight); gdk_fb_drawable_clear(pDrawTo); } } } } miFreeArcs(polyArcs, pGC); if(fTricky) { gdk_pixmap_unref(pDrawTo); gdk_gc_unref(pGCTo); } }}static doubleangleBetween (SppPointRec center, SppPointRec point1, SppPointRec 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 (miArcFacePtr b, int x, int y, double fx, double 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 (GdkDrawable *pDraw, GdkGC *pGC, miArcFacePtr pLeft, miArcFacePtr pRight, int xOrgLeft, int yOrgLeft, double xFtransLeft, double yFtransLeft, int xOrgRight, int yOrgRight, double xFtransRight, double yFtransRight){ SppPointRec center, corner, otherCorner; SppPointRec poly[5], e; SppPointPtr pArcPts; int cpt; SppArcRec arc; miArcFaceRec Right, Left; int polyLen = 0; 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 (GDK_GC_FBDATA(pGC)->values.join_style) { case GDK_JOIN_ROUND: width = (GDK_GC_FBDATA(pGC)->values.line_width ? (double)GDK_GC_FBDATA(pGC)->values.line_width : (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) g_malloc (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); } g_free(pArcPts); return; case GDK_JOIN_MITER: /* * 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 GDK_JOIN_BEVEL: 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 (GdkDrawable *pDraw, GdkGC *pGC, miArcFacePtr pFace, int end, int xOrg, int yOrg, double xFtrans, double yFtrans){ SppPointRec corner, otherCorner, center, endPoint, poly[5]; corner = pFace->clock; otherCorner = pFace->counterClock; center = pFace->center; switch (GDK_GC_FBDATA(pGC)->values.cap_style) { case GDK_CAP_PROJECTING: 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 GDK_CAP_ROUND: /* * 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; default: 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 void miRoundCap(GdkDrawable *pDraw, GdkGC *pGC, SppPointRec pCenter, SppPointRec pEnd, SppPointRec pCorner, SppPointRec pOtherCorner, int fLineEnd, int xOrg, int yOrg, double xFtrans, double yFtrans){ int cpt; double width; SppArcRec arc; SppPointPtr pArcPts; width = (GDK_GC_FBDATA(pGC)->values.line_width ? (double)GDK_GC_FBDATA(pGC)->values.line_width : (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); } g_free(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 (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 (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 (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 (double dy, double 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 g_malloc()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 g_realloc() to handle the null pointer correctly. */static intmiGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts)#if 0 SppArcPtr parc; /* points to an arc */ int cpt; /* number of points already in arc list */ SppPointPtr *ppPts; /* pointer to pointer to arc-list -- modified */#endif{ 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; GdkPoint 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 * 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -