📄 tkcanvarc.c
字号:
newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr); if (newDist < dist) { dist = newDist; } } } else { if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) { if (filled && (polyDist < dist)) { dist = polyDist; } } } return dist;}/* *-------------------------------------------------------------- * * ArcToArea -- * * This procedure is called to determine whether an item * lies entirely inside, entirely outside, or overlapping * a given area. * * Results: * -1 is returned if the item is entirely outside the area * given by rectPtr, 0 if it overlaps, and 1 if it is entirely * inside the given area. * * Side effects: * None. * *-------------------------------------------------------------- */ /* ARGSUSED */static intArcToArea(canvas, itemPtr, rectPtr) Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item to check against arc. */ double *rectPtr; /* Pointer to array of four coordinates * (x1, y1, x2, y2) describing rectangular * area. */{ ArcItem *arcPtr = (ArcItem *) itemPtr; double rx, ry; /* Radii for transformed oval: these define * an oval centered at the origin. */ double tRect[4]; /* Transformed version of x1, y1, x2, y2, * for coord. system where arc is centered * on the origin. */ double center[2], width, angle, tmp; double points[20], *pointPtr; int numPoints, filled; int inside; /* Non-zero means every test so far suggests * that arc is inside rectangle. 0 means * every test so far shows arc to be outside * of rectangle. */ int newInside; if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) { filled = 1; } else { filled = 0; } if (arcPtr->outlineGC == None) { width = 0.0; } else { width = arcPtr->width; } /* * Transform both the arc and the rectangle so that the arc's oval * is centered on the origin. */ center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; tRect[0] = rectPtr[0] - center[0]; tRect[1] = rectPtr[1] - center[1]; tRect[2] = rectPtr[2] - center[0]; tRect[3] = rectPtr[3] - center[1]; rx = arcPtr->bbox[2] - center[0] + width/2.0; ry = arcPtr->bbox[3] - center[1] + width/2.0; /* * Find the extreme points of the arc and see whether these are all * inside the rectangle (in which case we're done), partly in and * partly out (in which case we're done), or all outside (in which * case we have more work to do). The extreme points include the * following, which are checked in order: * * 1. The outside points of the arc, corresponding to start and * extent. * 2. The center of the arc (but only in pie-slice mode). * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc * includes those angles). */ pointPtr = points; angle = -arcPtr->start*(PI/180.0); pointPtr[0] = rx*cos(angle); pointPtr[1] = ry*sin(angle); angle += -arcPtr->extent*(PI/180.0); pointPtr[2] = rx*cos(angle); pointPtr[3] = ry*sin(angle); numPoints = 2; pointPtr += 4; if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) { pointPtr[0] = 0.0; pointPtr[1] = 0.0; numPoints++; pointPtr += 2; } tmp = -arcPtr->start; if (tmp < 0) { tmp += 360.0; } if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { pointPtr[0] = rx; pointPtr[1] = 0.0; numPoints++; pointPtr += 2; } tmp = 90.0 - arcPtr->start; if (tmp < 0) { tmp += 360.0; } if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { pointPtr[0] = 0.0; pointPtr[1] = -ry; numPoints++; pointPtr += 2; } tmp = 180.0 - arcPtr->start; if (tmp < 0) { tmp += 360.0; } if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { pointPtr[0] = -rx; pointPtr[1] = 0.0; numPoints++; pointPtr += 2; } tmp = 270.0 - arcPtr->start; if (tmp < 0) { tmp += 360.0; } if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { pointPtr[0] = 0.0; pointPtr[1] = ry; numPoints++; } /* * Now that we've located the extreme points, loop through them all * to see which are inside the rectangle. */ inside = (points[0] > tRect[0]) && (points[0] < tRect[2]) && (points[1] > tRect[1]) && (points[1] < tRect[3]); for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) { newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2]) && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]); if (newInside != inside) { return 0; } } if (inside) { return 1; } /* * So far, oval appears to be outside rectangle, but can't yet tell * for sure. Next, test each of the four sides of the rectangle * against the bounding region for the arc. If any intersections * are found, then return "overlapping". First, test against the * polygon(s) forming the sides of a chord or pie-slice. */ if (arcPtr->style == pieSliceUid) { if (width >= 1.0) { if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, rectPtr) != -1) { return 0; } if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, PIE_OUTLINE2_PTS, rectPtr) != -1) { return 0; } } else { if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) || (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) { return 0; } } } else if (arcPtr->style == chordUid) { if (width >= 1.0) { if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, rectPtr) != -1) { return 0; } } else { if (TkLineToArea(arcPtr->center1, arcPtr->center2, rectPtr) != -1) { return 0; } } } /* * Next check for overlap between each of the four sides and the * outer perimiter of the arc. If the arc isn't filled, then also * check the inner perimeter of the arc. */ if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, arcPtr->extent) || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, arcPtr->start, arcPtr->extent) || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, arcPtr->start, arcPtr->extent) || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, arcPtr->start, arcPtr->extent)) { return 0; } if ((width > 1.0) && !filled) { rx -= width; ry -= width; if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, arcPtr->extent) || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, arcPtr->start, arcPtr->extent) || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, arcPtr->start, arcPtr->extent) || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, arcPtr->start, arcPtr->extent)) { return 0; } } /* * The arc still appears to be totally disjoint from the rectangle, * but it's also possible that the rectangle is totally inside the arc. * Do one last check, which is to check one point of the rectangle * to see if it's inside the arc. If it is, we've got overlap. If * it isn't, the arc's really outside the rectangle. */ if (ArcToPoint(canvas, itemPtr, rectPtr) == 0.0) { return 0; } return -1;}/* *-------------------------------------------------------------- * * ScaleArc -- * * This procedure is invoked to rescale an arc item. * * Results: * None. * * Side effects: * The arc referred to by itemPtr is rescaled so that the * following transformation is applied to all point * coordinates: * x' = originX + scaleX*(x-originX) * y' = originY + scaleY*(y-originY) * *-------------------------------------------------------------- */static voidScaleArc(canvas, itemPtr, originX, originY, scaleX, scaleY) Tk_Canvas canvas; /* Canvas containing arc. */ Tk_Item *itemPtr; /* Arc to be scaled. */ double originX, originY; /* Origin about which to scale rect. */ double scaleX; /* Amount to scale in X direction. */ double scaleY; /* Amount to scale in Y direction. */{ ArcItem *arcPtr = (ArcItem *) itemPtr; arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX); arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY); arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX); arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY); ComputeArcBbox(canvas, arcPtr);}/* *-------------------------------------------------------------- * * TranslateArc -- * * This procedure is called to move an arc by a given amount. * * Results: * None. * * Side effects: * The position of the arc is offset by (xDelta, yDelta), and * the bounding box is updated in the generic part of the item * structure. * *-------------------------------------------------------------- */static voidTranslateArc(canvas, itemPtr, deltaX, deltaY) Tk_Canvas canvas; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item that is being moved. */ double deltaX, deltaY; /* Amount by which item is to be * moved. */{ ArcItem *arcPtr = (ArcItem *) itemPtr; arcPtr->bbox[0] += deltaX; arcPtr->bbox[1] += deltaY; arcPtr->bbox[2] += deltaX; arcPtr->bbox[3] += deltaY; ComputeArcBbox(canvas, arcPtr);}/* *-------------------------------------------------------------- * * ComputeArcOutline -- * * This procedure creates a polygon describing everything in * the outline for an arc except what's in the curved part. * For a "pie slice" arc this is a V-shaped chunk, and for * a "chord" arc this is a linear chunk (with cutaway corners). * For "arc" arcs, this stuff isn't relevant. * * Results: * None. * * Side effects: * The information at arcPtr->outlinePtr gets modified, and * storage for arcPtr->outlinePtr may be allocated or freed. * *-------------------------------------------------------------- */static voidComputeArcOutline(arcPtr) ArcItem *arcPtr; /* Information about arc. */{ double sin1, cos1, sin2, cos2, angle, halfWidth; double boxWidth, boxHeight; double vertex[2], corner1[2], corner2[2]; double *outlinePtr; /* * Make sure that the outlinePtr array is large enough to hold * either a chord or pie-slice outline. */ if (arcPtr->numOutlinePoints == 0) { arcPtr->outlinePtr = (double *) ckalloc((unsigned) (26 * sizeof(double))); arcPtr->numOutlinePoints = 22; } outlinePtr = arcPtr->outlinePtr; /* * First compute the two points that lie at the centers of * the ends of the curved arc segment, which are marked with * X's in the figure below: * * * * * * * * * * * * * * * * * * * * * * * * * X * * X * * The code is tricky because the arc can be ovular in shape. * It computes the position for a unit circle, and then * scales to fit the shape of the arc's bounding box. * * Also, watch out because angles go counter-clockwise like you * might expect, but the y-coordinate system is inverted. To * handle this, just negate the angles in all the computations. */ boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0]; boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1]; angle = -arcPtr->start*PI/180.0; sin1 = sin(angle); cos1 = cos(angle); angle -= arcPtr->extent*PI/180.0; sin2 = sin(angle); cos2 = cos(angle); vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0; arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0; arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0; arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0; /* * Next compute the "outermost corners" of the arc, which are * marked with X's in the figure below: * * * * * * * * * * * * * * * * * * * X * * X * * * * * The code below is tricky because it has to handle eccentricity * in the shape of the oval. The key in the code below is to * realize that the slope of the line from arcPtr->center1 to corner1 * is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2 * and corner2. These formulas can be computed from the formula for * the oval. */ halfWidth = arcPtr->width/2.0; if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) { angle = 0.0; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -