📄 tkcanvline.c
字号:
char *value; /* Textual specification of arrow shape. */ char *recordPtr; /* Pointer to item record in which to * store arrow information. */ int offset; /* Offset of shape information in widget * record. */{ LineItem *linePtr = (LineItem *) recordPtr; double a, b, c; int argc; char **argv = NULL; if (offset != Tk_Offset(LineItem, arrowShapeA)) { panic("ParseArrowShape received bogus offset"); } if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { syntaxError: Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad arrow shape \"", value, "\": must be list with three numbers", (char *) NULL); if (argv != NULL) { ckfree((char *) argv); } return TCL_ERROR; } if (argc != 3) { goto syntaxError; } if ((Tk_CanvasGetCoord(interp, linePtr->canvas, argv[0], &a) != TCL_OK) || (Tk_CanvasGetCoord(interp, linePtr->canvas, argv[1], &b) != TCL_OK) || (Tk_CanvasGetCoord(interp, linePtr->canvas, argv[2], &c) != TCL_OK)) { goto syntaxError; } linePtr->arrowShapeA = (float)a; linePtr->arrowShapeB = (float)b; linePtr->arrowShapeC = (float)c; ckfree((char *) argv); return TCL_OK;}/* *-------------------------------------------------------------- * * PrintArrowShape -- * * This procedure is a callback invoked by the configuration * code to return a printable value describing an arrow shape. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ /* ARGSUSED */static char *PrintArrowShape(clientData, tkwin, recordPtr, offset, freeProcPtr) ClientData clientData; /* Not used. */ Tk_Window tkwin; /* Window associated with linePtr's widget. */ char *recordPtr; /* Pointer to item record containing current * shape information. */ int offset; /* Offset of arrow information in record. */ Tcl_FreeProc **freeProcPtr; /* Store address of procedure to call to * free string here. */{ LineItem *linePtr = (LineItem *) recordPtr; char *buffer; buffer = (char *) ckalloc(120); sprintf(buffer, "%.5g %.5g %.5g", linePtr->arrowShapeA, linePtr->arrowShapeB, linePtr->arrowShapeC); *freeProcPtr = TCL_DYNAMIC; return buffer;}/* *-------------------------------------------------------------- * * ConfigureArrows -- * * If arrowheads have been requested for a line, this * procedure makes arrangements for the arrowheads. * * Results: * Always returns TCL_OK. * * Side effects: * Information in linePtr is set up for one or two arrowheads. * the firstArrowPtr and lastArrowPtr polygons are allocated * and initialized, if need be, and the end points of the line * are adjusted so that a thick line doesn't stick out past * the arrowheads. * *-------------------------------------------------------------- */ /* ARGSUSED */static intConfigureArrows(canvas, linePtr) Tk_Canvas canvas; /* Canvas in which arrows will be * displayed (interp and tkwin * fields are needed). */ LineItem *linePtr; /* Item to configure for arrows. */{ double *poly, *coordPtr; double dx, dy, length, sinTheta, cosTheta, temp; double fracHeight; /* Line width as fraction of * arrowhead width. */ double backup; /* Distance to backup end points * so the line ends in the middle * of the arrowhead. */ double vertX, vertY; /* Position of arrowhead vertex. */ double shapeA, shapeB, shapeC; /* Adjusted coordinates (see * explanation below). */ /* * The code below makes a tiny increase in the shape parameters * for the line. This is a bit of a hack, but it seems to result * in displays that more closely approximate the specified parameters. * Without the adjustment, the arrows come out smaller than expected. */ shapeA = linePtr->arrowShapeA + 0.001; shapeB = linePtr->arrowShapeB + 0.001; shapeC = linePtr->arrowShapeC + linePtr->width/2.0 + 0.001; /* * If there's an arrowhead on the first point of the line, compute * its polygon and adjust the first point of the line so that the * line doesn't stick out past the leading edge of the arrowhead. */ fracHeight = (linePtr->width/2.0)/shapeC; backup = fracHeight*shapeB + shapeA*(1.0 - fracHeight)/2.0; if (linePtr->arrow != lastUid) { poly = linePtr->firstArrowPtr; if (poly == NULL) { poly = (double *) ckalloc((unsigned) (2*PTS_IN_ARROW*sizeof(double))); poly[0] = poly[10] = linePtr->coordPtr[0]; poly[1] = poly[11] = linePtr->coordPtr[1]; linePtr->firstArrowPtr = poly; } dx = poly[0] - linePtr->coordPtr[2]; dy = poly[1] - linePtr->coordPtr[3]; length = hypot(dx, dy); if (length == 0) { sinTheta = cosTheta = 0.0; } else { sinTheta = dy/length; cosTheta = dx/length; } vertX = poly[0] - shapeA*cosTheta; vertY = poly[1] - shapeA*sinTheta; temp = shapeC*sinTheta; poly[2] = poly[0] - shapeB*cosTheta + temp; poly[8] = poly[2] - 2*temp; temp = shapeC*cosTheta; poly[3] = poly[1] - shapeB*sinTheta - temp; poly[9] = poly[3] + 2*temp; poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight); poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight); poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight); poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight); /* * Polygon done. Now move the first point towards the second so * that the corners at the end of the line are inside the * arrowhead. */ linePtr->coordPtr[0] = poly[0] - backup*cosTheta; linePtr->coordPtr[1] = poly[1] - backup*sinTheta; } /* * Similar arrowhead calculation for the last point of the line. */ if (linePtr->arrow != firstUid) { coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2); poly = linePtr->lastArrowPtr; if (poly == NULL) { poly = (double *) ckalloc((unsigned) (2*PTS_IN_ARROW*sizeof(double))); poly[0] = poly[10] = coordPtr[2]; poly[1] = poly[11] = coordPtr[3]; linePtr->lastArrowPtr = poly; } dx = poly[0] - coordPtr[0]; dy = poly[1] - coordPtr[1]; length = hypot(dx, dy); if (length == 0) { sinTheta = cosTheta = 0.0; } else { sinTheta = dy/length; cosTheta = dx/length; } vertX = poly[0] - shapeA*cosTheta; vertY = poly[1] - shapeA*sinTheta; temp = shapeC*sinTheta; poly[2] = poly[0] - shapeB*cosTheta + temp; poly[8] = poly[2] - 2*temp; temp = shapeC*cosTheta; poly[3] = poly[1] - shapeB*sinTheta - temp; poly[9] = poly[3] + 2*temp; poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight); poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight); poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight); poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight); coordPtr[2] = poly[0] - backup*cosTheta; coordPtr[3] = poly[1] - backup*sinTheta; } return TCL_OK;}/* *-------------------------------------------------------------- * * LineToPostscript -- * * This procedure is called to generate Postscript for * line items. * * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is * left in interp->result, replacing whatever used * to be there. If no error occurs, then Postscript for the * item is appended to the result. * * Side effects: * None. * *-------------------------------------------------------------- */static intLineToPostscript(interp, canvas, itemPtr, prepass) Tcl_Interp *interp; /* Leave Postscript or error message * here. */ Tk_Canvas canvas; /* Information about overall canvas. */ Tk_Item *itemPtr; /* Item for which Postscript is * wanted. */ int prepass; /* 1 means this is a prepass to * collect font information; 0 means * final Postscript is being created. */{ LineItem *linePtr = (LineItem *) itemPtr; char buffer[200]; char *style; if (linePtr->fg == NULL) { return TCL_OK; } /* * Generate a path for the line's center-line (do this differently * for straight lines and smoothed lines). */ if ((!linePtr->smooth) || (linePtr->numPoints <= 2)) { Tk_CanvasPsPath(interp, canvas, linePtr->coordPtr, linePtr->numPoints); } else { if (linePtr->fillStipple == None) { TkMakeBezierPostscript(interp, canvas, linePtr->coordPtr, linePtr->numPoints); } else { /* * Special hack: Postscript printers don't appear to be able * to turn a path drawn with "curveto"s into a clipping path * without exceeding resource limits, so TkMakeBezierPostscript * won't work for stippled curves. Instead, generate all of * the intermediate points here and output them into the * Postscript file with "lineto"s instead. */ double staticPoints[2*MAX_STATIC_POINTS]; double *pointPtr; int numPoints; numPoints = 1 + linePtr->numPoints*linePtr->splineSteps; pointPtr = staticPoints; if (numPoints > MAX_STATIC_POINTS) { pointPtr = (double *) ckalloc((unsigned) (numPoints * 2 * sizeof(double))); } numPoints = TkMakeBezierCurve(canvas, linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps, (XPoint *) NULL, pointPtr); Tk_CanvasPsPath(interp, canvas, pointPtr, numPoints); if (pointPtr != staticPoints) { ckfree((char *) pointPtr); } } } /* * Set other line-drawing parameters and stroke out the line. */ sprintf(buffer, "%d setlinewidth\n", linePtr->width); Tcl_AppendResult(interp, buffer, (char *) NULL); style = "0 setlinecap\n"; if (linePtr->capStyle == CapRound) { style = "1 setlinecap\n"; } else if (linePtr->capStyle == CapProjecting) { style = "2 setlinecap\n"; } Tcl_AppendResult(interp, style, (char *) NULL); style = "0 setlinejoin\n"; if (linePtr->joinStyle == JoinRound) { style = "1 setlinejoin\n"; } else if (linePtr->joinStyle == JoinBevel) { style = "2 setlinejoin\n"; } Tcl_AppendResult(interp, style, (char *) NULL); if (Tk_CanvasPsColor(interp, canvas, linePtr->fg) != TCL_OK) { return TCL_ERROR; }; if (linePtr->fillStipple != None) { Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL); if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendResult(interp, "stroke\n", (char *) NULL); } /* * Output polygons for the arrowheads, if there are any. */ if (linePtr->firstArrowPtr != NULL) { if (linePtr->fillStipple != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } if (ArrowheadPostscript(interp, canvas, linePtr, linePtr->firstArrowPtr) != TCL_OK) { return TCL_ERROR; } } if (linePtr->lastArrowPtr != NULL) { if (linePtr->fillStipple != None) { Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL); } if (ArrowheadPostscript(interp, canvas, linePtr, linePtr->lastArrowPtr) != TCL_OK) { return TCL_ERROR; } } return TCL_OK;}/* *-------------------------------------------------------------- * * ArrowheadPostscript -- * * This procedure is called to generate Postscript for * an arrowhead for a line item. * * Results: * The return value is a standard Tcl result. If an error * occurs in generating Postscript then an error message is * left in interp->result, replacing whatever used * to be there. If no error occurs, then Postscript for the * arrowhead is appended to the result. * * Side effects: * None. * *-------------------------------------------------------------- */static intArrowheadPostscript(interp, canvas, linePtr, arrowPtr) Tcl_Interp *interp; /* Leave Postscript or error message * here. */ Tk_Canvas canvas; /* Information about overall canvas. */ LineItem *linePtr; /* Line item for which Postscript is * being generated. */ double *arrowPtr; /* Pointer to first of five points * describing arrowhead polygon. */{ Tk_CanvasPsPath(interp, canvas, arrowPtr, PTS_IN_ARROW); if (linePtr->fillStipple != None) { Tcl_AppendResult(interp, "clip ", (char *) NULL); if (Tk_CanvasPsStipple(interp, canvas, linePtr->fillStipple) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendResult(interp, "fill\n", (char *) NULL); } return TCL_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -