/* ARGSUSED */ int TkThickPolyLineToArea( double *coordPtr, /* Points to an array of coordinates for the * polyline: x0, y0, x1, y1, ... */ int numPoints, /* Total number of points at *coordPtr. */ double width, /* Width of each line segment. */ int capStyle, /* How are end-points of polyline drawn? * CapRound, CapButt, or CapProjecting. */ int joinStyle, /* How are joints in polyline drawn? * JoinMiter, JoinRound, or JoinBevel. */ double *rectPtr) /* Rectangular area to check against. */ { double radius, poly[10]; int count; int changedMiterToBevel; /* Non-zero means that a mitered corner had to * be treated as beveled after all because the * angle was < 11 degrees. */ int inside; /* Tentative guess about what to return, based * on all points seen so far: one means * everything seen so far was inside the area; * -1 means everything was outside the area. * 0 means overlap has been found. */ radius = width/2.0; inside = -1; if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2]) && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) { inside = 1; } /* * Iterate through all of the edges of the line, computing a polygon for * each edge and testing the area against that polygon. In addition, there * are additional tests to deal with rounded joints and caps. */ changedMiterToBevel = 0; for (count = numPoints; count >= 2; count--, coordPtr += 2) { /* * If rounding is done around the first point of the edge then test a * circular region around the point with the area. */ if (((capStyle == CapRound) && (count == numPoints)) || ((joinStyle == JoinRound) && (count != numPoints))) { poly[0] = coordPtr[0] - radius; poly[1] = coordPtr[1] - radius; poly[2] = coordPtr[0] + radius; poly[3] = coordPtr[1] + radius; if (TkOvalToArea(poly, rectPtr) != inside) { return 0; } } /* * Compute the polygonal shape corresponding to this edge, consisting * of two points for the first point of the edge and two points for * the last point of the edge. */ if (count == numPoints) { TkGetButtPoints(coordPtr+2, coordPtr, width, capStyle == CapProjecting, poly, poly+2); } else if ((joinStyle == JoinMiter) && !changedMiterToBevel) { poly[0] = poly[6]; poly[1] = poly[7]; poly[2] = poly[4]; poly[3] = poly[5]; } else { TkGetButtPoints(coordPtr+2, coordPtr, width, 0, poly, poly+2); /* * If the last joint was beveled, then also check a polygon * comprising the last two points of the previous polygon and the * first two from this polygon; this checks the wedges that fill * the beveled joint. */ if ((joinStyle == JoinBevel) || changedMiterToBevel) { poly[8] = poly[0]; poly[9] = poly[1]; if (TkPolygonToArea(poly, 5, rectPtr) != inside) { return 0; } changedMiterToBevel = 0; } } if (count == 2) { TkGetButtPoints(coordPtr, coordPtr+2, width, capStyle == CapProjecting, poly+4, poly+6); } else if (joinStyle == JoinMiter) { if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, (double) width, poly+4, poly+6) == 0) { changedMiterToBevel = 1; TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6); } } else { TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6); } poly[8] = poly[0]; poly[9] = poly[1]; if (TkPolygonToArea(poly, 5, rectPtr) != inside) { return 0; } } /* * If caps are rounded, check the cap around the final point of the line. */ if (capStyle == CapRound) { poly[0] = coordPtr[0] - radius; poly[1] = coordPtr[1] - radius; poly[2] = coordPtr[0] + radius; poly[3] = coordPtr[1] + radius; if (TkOvalToArea(poly, rectPtr) != inside) { return 0; } } return inside; }
/* ARGSUSED */ static int OvalToArea( Tk_Canvas canvas, /* Canvas containing item. */ Tk_Item *itemPtr, /* Item to check against oval. */ double *areaPtr) /* Pointer to array of four coordinates (x1, * y1, x2, y2) describing rectangular area. */ { RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; double oval[4], halfWidth, width; int result; Tk_State state = itemPtr->state; if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; } width = ovalPtr->outline.width; if (Canvas(canvas)->currentItemPtr == itemPtr) { if (ovalPtr->outline.activeWidth > width) { width = ovalPtr->outline.activeWidth; } } else if (state == TK_STATE_DISABLED) { if (ovalPtr->outline.disabledWidth > 0) { width = ovalPtr->outline.disabledWidth; } } /* * Expand the oval to include the width of the outline, if any. */ halfWidth = width/2.0; if (ovalPtr->outline.gc == None) { halfWidth = 0.0; } oval[0] = ovalPtr->bbox[0] - halfWidth; oval[1] = ovalPtr->bbox[1] - halfWidth; oval[2] = ovalPtr->bbox[2] + halfWidth; oval[3] = ovalPtr->bbox[3] + halfWidth; result = TkOvalToArea(oval, areaPtr); /* * If the rectangle appears to overlap the oval and the oval isn't filled, * do one more check to see if perhaps all four of the rectangle's corners * are totally inside the oval's unfilled center, in which case we should * return "outside". */ if ((result == 0) && (ovalPtr->outline.gc != None) && (ovalPtr->fillGC == None)) { double centerX, centerY, height; double xDelta1, yDelta1, xDelta2, yDelta2; centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0; width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth; height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth; xDelta1 = (areaPtr[0] - centerX)/width; xDelta1 *= xDelta1; yDelta1 = (areaPtr[1] - centerY)/height; yDelta1 *= yDelta1; xDelta2 = (areaPtr[2] - centerX)/width; xDelta2 *= xDelta2; yDelta2 = (areaPtr[3] - centerY)/height; yDelta2 *= yDelta2; if (((xDelta1 + yDelta1) < 1.0) && ((xDelta1 + yDelta2) < 1.0) && ((xDelta2 + yDelta1) < 1.0) && ((xDelta2 + yDelta2) < 1.0)) { return -1; } } return result; }
/* ARGSUSED */ static int BLineToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr) { register BLineItem *linePtr = (BLineItem *) itemPtr; register double *coordPtr; double staticSpace[2*MAX_STATIC_POINTS]; double *linePoints, poly[10]; double radius; int numPoints, count; int changedMiterToBevel; /* Non-zero means that a mitered corner * had to be treated as beveled after all * because the angle was < 11 degrees. */ int inside; /* Tentative guess about what to return, * based on all points seen so far: one * means everything seen so far was * inside the area; -1 means everything * was outside the area. 0 means overlap * has been found. */ radius = linePtr->width/2.0; inside = -1; numPoints = linePtr->numPoints; linePoints = linePtr->coordPtr; coordPtr = linePoints; if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2]) && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) { inside = 1; } /* * Iterate through all of the edges of the line, computing a polygon * for each edge and testing the area against that polygon. In * addition, there are additional tests to deal with rounded joints * and caps. */ changedMiterToBevel = 0; for (count = numPoints; count >= 2; count--, coordPtr += 2) { /* * If rounding is done around the first point of the edge * then test a circular region around the point with the * area. */ if (((linePtr->capStyle == CapRound) && (count == numPoints)) || ((linePtr->joinStyle == JoinRound) && (count != numPoints))) { poly[0] = coordPtr[0] - radius; poly[1] = coordPtr[1] - radius; poly[2] = coordPtr[0] + radius; poly[3] = coordPtr[1] + radius; if (TkOvalToArea(poly, rectPtr) != inside) { inside = 0; goto done; } } /* * Compute the polygonal shape corresponding to this edge, * consisting of two points for the first point of the edge * and two points for the last point of the edge. */ if (count == numPoints) { TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, linePtr->capStyle == CapProjecting, poly, poly+2); } else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) { poly[0] = poly[6]; poly[1] = poly[7]; poly[2] = poly[4]; poly[3] = poly[5]; } else { TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, 0, poly, poly+2); /* * If the last joint was beveled, then also check a * polygon comprising the last two points of the previous * polygon and the first two from this polygon; this checks * the wedges that fill the beveled joint. */ if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) { poly[8] = poly[0]; poly[9] = poly[1]; if (TkPolygonToArea(poly, 5, rectPtr) != inside) { inside = 0; goto done; } changedMiterToBevel = 0; } } if (count == 2) { TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, linePtr->capStyle == CapProjecting, poly+4, poly+6); } else if (linePtr->joinStyle == JoinMiter) { if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, (double) linePtr->width, poly+4, poly+6) == 0) { changedMiterToBevel = 1; TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0, poly+4, poly+6); } } else { TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0, poly+4, poly+6); } poly[8] = poly[0]; poly[9] = poly[1]; if (TkPolygonToArea(poly, 5, rectPtr) != inside) { inside = 0; goto done; } } /* * If caps are rounded, check the cap around the final point * of the line. */ if (linePtr->capStyle == CapRound) { poly[0] = coordPtr[0] - radius; poly[1] = coordPtr[1] - radius; poly[2] = coordPtr[0] + radius; poly[3] = coordPtr[1] + radius; if (TkOvalToArea(poly, rectPtr) != inside) { inside = 0; goto done; } } done: if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) { ckfree((char *) linePoints); } return inside; }