📄 tkcanvline.c
字号:
linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; ckfree((char *) linePtr->firstArrowPtr); linePtr->firstArrowPtr = NULL; } if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != lastUid) && (linePtr->arrow != bothUid)) { int index; index = 2*(linePtr->numPoints-1); linePtr->coordPtr[index] = linePtr->lastArrowPtr[0]; linePtr->coordPtr[index+1] = linePtr->lastArrowPtr[1]; ckfree((char *) linePtr->lastArrowPtr); linePtr->lastArrowPtr = NULL; } if (linePtr->arrow != noneUid) { if ((linePtr->arrow != firstUid) && (linePtr->arrow != lastUid) && (linePtr->arrow != bothUid)) { Tcl_AppendResult(canvasPtr->interp, "bad arrow spec \"", linePtr->arrow, "\": must be none, first, last, or both", (char *) NULL); linePtr->arrow = noneUid; return TCL_ERROR; } ConfigureArrows(canvasPtr, linePtr); } /* * Recompute bounding box for line. */ ComputeLineBbox(canvasPtr, linePtr); return TCL_OK;}/* *-------------------------------------------------------------- * * DeleteLine -- * * This procedure is called to clean up the data structure * associated with a line item. * * Results: * None. * * Side effects: * Resources associated with itemPtr are released. * *-------------------------------------------------------------- */static voidDeleteLine(canvasPtr, itemPtr) Tk_Canvas *canvasPtr; /* Info about overall canvas widget. */ Tk_Item *itemPtr; /* Item that is being deleted. */{ register LineItem *linePtr = (LineItem *) itemPtr; if (linePtr->coordPtr != NULL) { ckfree((char *) linePtr->coordPtr); } if (linePtr->fg != NULL) { Tk_FreeColor(linePtr->fg); } if (linePtr->fillStipple != None) { Tk_FreeBitmap(canvasPtr->display, linePtr->fillStipple); } if (linePtr->gc != None) { Tk_FreeGC(canvasPtr->display, linePtr->gc); } if (linePtr->firstArrowPtr != NULL) { ckfree((char *) linePtr->firstArrowPtr); } if (linePtr->lastArrowPtr != NULL) { ckfree((char *) linePtr->lastArrowPtr); }}/* *-------------------------------------------------------------- * * ComputeLineBbox -- * * This procedure is invoked to compute the bounding box of * all the pixels that may be drawn as part of a line. * * Results: * None. * * Side effects: * The fields x1, y1, x2, and y2 are updated in the header * for itemPtr. * *-------------------------------------------------------------- */static voidComputeLineBbox(canvasPtr, linePtr) register Tk_Canvas *canvasPtr; /* Canvas that contains item. */ LineItem *linePtr; /* Item whose bbos is to be * recomputed. */{ register double *coordPtr; int i; coordPtr = linePtr->coordPtr; linePtr->header.x1 = linePtr->header.x2 = *coordPtr; linePtr->header.y1 = linePtr->header.y2 = coordPtr[1]; /* * Compute the bounding box of all the points in the line, * then expand in all directions by the line's width to take * care of butting or rounded corners and projecting or * rounded caps. This expansion is an overestimate (worst-case * is square root of two over two) but it's simple. Don't do * anything special for curves. This causes an additional * overestimate in the bounding box, but is faster. */ for (i = 1, coordPtr = linePtr->coordPtr+2; i < linePtr->numPoints; i++, coordPtr += 2) { TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, coordPtr); } linePtr->header.x1 -= linePtr->width; linePtr->header.x2 += linePtr->width; linePtr->header.y1 -= linePtr->width; linePtr->header.y2 += linePtr->width; /* * For mitered lines, make a second pass through all the points. * Compute the locations of the two miter vertex points and add * those into the bounding box. */ if (linePtr->joinStyle == JoinMiter) { for (i = linePtr->numPoints, coordPtr = linePtr->coordPtr; i >= 3; i--, coordPtr += 2) { double miter[4]; int j; if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, (double) linePtr->width, miter, miter+2)) { for (j = 0; j < 4; j += 2) { TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, miter+j); } } } } /* * Add in the sizes of arrowheads, if any. */ if (linePtr->arrow != noneUid) { if (linePtr->arrow != lastUid) { for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, coordPtr); } } if (linePtr->arrow != firstUid) { for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; i++, coordPtr += 2) { TkIncludePoint(canvasPtr, (Tk_Item *) linePtr, coordPtr); } } } /* * Add one more pixel of fudge factor just to be safe (e.g. * X may round differently than we do). */ linePtr->header.x1 -= 1; linePtr->header.x2 += 1; linePtr->header.y1 -= 1; linePtr->header.y2 += 1;}/* *-------------------------------------------------------------- * * DisplayLine -- * * This procedure is invoked to draw a line item in a given * drawable. * * Results: * None. * * Side effects: * ItemPtr is drawn in drawable using the transformation * information in canvasPtr. * *-------------------------------------------------------------- */static voidDisplayLine(canvasPtr, itemPtr, drawable) register Tk_Canvas *canvasPtr; /* Canvas that contains item. */ Tk_Item *itemPtr; /* Item to be displayed. */ Drawable drawable; /* Pixmap or window in which to draw * item. */{ register LineItem *linePtr = (LineItem *) itemPtr; XPoint staticPoints[MAX_STATIC_POINTS]; XPoint *pointPtr; register XPoint *pPtr; register double *coordPtr; int i, numPoints; if (linePtr->gc == None) { return; } /* * Build up an array of points in screen coordinates. Use a * static array unless the line has an enormous number of points; * in this case, dynamically allocate an array. For smoothed lines, * generate the curve points on each redisplay. */ if ((linePtr->smooth) && (linePtr->numPoints > 2)) { numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; } else { numPoints = linePtr->numPoints; } if (numPoints <= MAX_STATIC_POINTS) { pointPtr = staticPoints; } else { pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); } if (linePtr->smooth) { numPoints = TkMakeBezierCurve(canvasPtr, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, pointPtr, (double *) NULL); } else { for (i = 0, coordPtr = linePtr->coordPtr, pPtr = pointPtr; i < linePtr->numPoints; i += 1, coordPtr += 2, pPtr++) { pPtr->x = SCREEN_X(canvasPtr, *coordPtr); pPtr->y = SCREEN_Y(canvasPtr, coordPtr[1]); } } /* * Display line, the free up line storage if it was dynamically * allocated. If we're stippling, then modify the stipple offset * in the GC. Be sure to reset the offset when done, since the * GC is supposed to be read-only. */ if (linePtr->fillStipple != None) { XSetTSOrigin(Tk_Display(canvasPtr->tkwin), linePtr->gc, -canvasPtr->drawableXOrigin, -canvasPtr->drawableYOrigin); } XDrawLines(Tk_Display(canvasPtr->tkwin), drawable, linePtr->gc, pointPtr, numPoints, CoordModeOrigin); if (pointPtr != staticPoints) { ckfree((char *) pointPtr); } /* * Display arrowheads, if they are wanted. */ if (linePtr->arrow != noneUid) { if (linePtr->arrow != lastUid) { TkFillPolygon(canvasPtr, linePtr->firstArrowPtr, PTS_IN_ARROW, drawable, linePtr->gc); } if (linePtr->arrow != firstUid) { TkFillPolygon(canvasPtr, linePtr->lastArrowPtr, PTS_IN_ARROW, drawable, linePtr->gc); } } if (linePtr->fillStipple != None) { XSetTSOrigin(Tk_Display(canvasPtr->tkwin), linePtr->gc, 0, 0); }}/* *-------------------------------------------------------------- * * LineToPoint -- * * Computes the distance from a given point to a given * line, in canvas units. * * Results: * The return value is 0 if the point whose x and y coordinates * are pointPtr[0] and pointPtr[1] is inside the line. If the * point isn't inside the line then the return value is the * distance from the point to the line. * * Side effects: * None. * *-------------------------------------------------------------- */ /* ARGSUSED */static doubleLineToPoint(canvasPtr, itemPtr, pointPtr) Tk_Canvas *canvasPtr; /* Canvas containing item. */ Tk_Item *itemPtr; /* Item to check against point. */ double *pointPtr; /* Pointer to x and y coordinates. */{ register LineItem *linePtr = (LineItem *) itemPtr; register double *coordPtr, *linePoints; double staticSpace[2*MAX_STATIC_POINTS]; double poly[10]; double bestDist, dist; 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. */ bestDist = 1.0e40; /* * Handle smoothed lines by generating an expanded set of points * against which to do the check. */ if ((linePtr->smooth) && (linePtr->numPoints > 2)) { numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; if (numPoints <= MAX_STATIC_POINTS) { linePoints = staticSpace; } else { linePoints = (double *) ckalloc((unsigned) (2*numPoints*sizeof(double))); } numPoints = TkMakeBezierCurve(canvasPtr, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, linePoints); } else { numPoints = linePtr->numPoints; linePoints = linePtr->coordPtr; } /* * The overall idea is to iterate through all of the edges of * the line, computing a polygon for each edge and testing the * point against that polygon. In addition, there are additional * tests to deal with rounded joints and caps. */ changedMiterToBevel = 0; for (count = numPoints, coordPtr = linePoints; count >= 2; count--, coordPtr += 2) { /* * If rounding is done around the first point then compute * the distance between the point and the point. */ if (((linePtr->capStyle == CapRound) && (count == numPoints)) || ((linePtr->joinStyle == JoinRound) && (count != numPoints))) { dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) - linePtr->width/2.0; if (dist <= 0.0) { bestDist = 0.0; goto done; } else if (dist < bestDist) { bestDist = dist; } } /* * 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 this line uses beveled joints, then check the distance * to 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 mitered joint. */ if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) { poly[8] = poly[0]; poly[9] = poly[1]; dist = TkPolygonToPoint(poly, 5, pointPtr); if (dist <= 0.0) { bestDist = 0.0; goto done; } else if (dist < bestDist) { bestDist = dist; } 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]; dist = TkPolygonToPoint(poly, 5, pointPtr); if (dist <= 0.0) { bestDist = 0.0; goto done; } else if (dist < bestDist) { bestDist = dist; } } /* * If caps are rounded, check the distance to the cap around the * final end point of the line. */ if (linePtr->capStyle == CapRound) { dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) - linePtr->width/2.0; if (dist <= 0.0) { bestDist = 0.0; goto done; } else if (dist < bestDist) { bestDist = dist; } } /* * If there are arrowheads, check the distance to the arrowheads. */ if (linePtr->arrow != noneUid) { if (linePtr->arrow != lastUid) { dist = TkPolygonToPoint(linePtr->firstArrowPtr, PTS_IN_ARROW, pointPtr); if (dist <= 0.0) { bestDist = 0.0; goto done; } else if (dist < bestDist) { bestDist = dist; } } if (linePtr->arrow != firstUid) { dist = TkPolygonToPoint(linePtr->lastArrowPtr, PTS_IN_ARROW, pointPtr); if (dist <= 0.0) { bestDist = 0.0; goto done; } else if (dist < bestDist) { bestDist = dist; } } } done: if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) { ckfree((char *) linePoints); } return bestDist;}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -