Index: generic/tkCanvArc.c ================================================================== --- generic/tkCanvArc.c +++ generic/tkCanvArc.c @@ -11,10 +11,12 @@ */ #include "tkInt.h" #include "tkCanvas.h" +#include "float.h" + /* * The structure below defines the record for each arc item. */ typedef enum { @@ -181,11 +183,11 @@ static void ComputeArcBbox(Tk_Canvas canvas, ArcItem *arcPtr); static int ConfigureArc(Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[], int flags); -static void ComputeArcFromHeight(ArcItem *arcPtr); +static void ComputeArcParametersFromHeight(ArcItem *arcPtr); static int CreateArc(Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); static void DeleteArc(Tk_Canvas canvas, Tk_Item *itemPtr, Display *display); @@ -467,17 +469,16 @@ } else { itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; } /* - * If either the height is provided then the start and extent will be - * overridden. + * Override the start and extent if the height is given. */ - if (arcPtr->height != 0) { - ComputeArcFromHeight(arcPtr); - ComputeArcBbox(canvas, arcPtr); - } + + ComputeArcParametersFromHeight(arcPtr); + + ComputeArcBbox(canvas, arcPtr); i = (int) (arcPtr->start/360.0); arcPtr->start -= i*360.0; if (arcPtr->start < 0) { arcPtr->start += 360.0; @@ -587,11 +588,11 @@ } /* *-------------------------------------------------------------- * - * ComputeArcFromHeight -- + * ComputeArcParametersFromHeight -- * * This function calculates the arc parameters given start-point, * end-point and height (!= 0). * * Results: @@ -602,21 +603,34 @@ * *-------------------------------------------------------------- */ static void -ComputeArcFromHeight( +ComputeArcParametersFromHeight( ArcItem* arcPtr) { double chordLen, chordDir[2], chordCen[2], arcCen[2], d, radToDeg, radius; /* - * The chord. + * Do nothing if no height has been specified. + */ + + if (arcPtr->height == 0) + return; + + /* + * Calculate the chord length, return early if it is too small. */ chordLen = hypot(arcPtr->endPoint[1] - arcPtr->startPoint[1], arcPtr->startPoint[0] - arcPtr->endPoint[0]); + + if (chordLen < DBL_EPSILON) { + arcPtr->start = arcPtr->extent = arcPtr->height = 0; + return; + } + chordDir[0] = (arcPtr->endPoint[0] - arcPtr->startPoint[0]) / chordLen; chordDir[1] = (arcPtr->endPoint[1] - arcPtr->startPoint[1]) / chordLen; chordCen[0] = (arcPtr->startPoint[0] + arcPtr->endPoint[0]) / 2; chordCen[1] = (arcPtr->startPoint[1] + arcPtr->endPoint[1]) / 2; @@ -789,11 +803,11 @@ } ComputeArcOutline(canvas,arcPtr); /* - * To compute the bounding box, start with the the bbox formed by the two + * To compute the bounding box, start with the bbox formed by the two * endpoints of the arc. Then add in the center of the arc's oval (if * relevant) and the 3-o'clock, 6-o'clock, 9-o'clock, and 12-o'clock * positions, if they are relevant. */ Index: tests/canvas.test ================================================================== --- tests/canvas.test +++ tests/canvas.test @@ -1037,10 +1037,28 @@ {#c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0 #c0c0c0}} } -cleanup { destroy .c image delete testimage } -result 1 + +test canvas-21.1 {canvas very small arc} -setup { + catch {destroy .c} + canvas .c +} -body { + # no Inf or NaN must be generated even for very small arcs + .c create arc 0 100 0 100 -height 100 -style arc -outline "" -tags arc1 + set arcBox [.c bbox arc1] + .c create arc 0 100 0 100 -height 100 -style arc -outline blue -tags arc2 + set outlinedArcBox [.c bbox arc2] + set coords [.c coords arc1] + set start [.c itemcget arc1 -start] + set extent [.c itemcget arc1 -extent] + set width [.c itemcget arc1 -width] + set height [.c itemcget arc1 -height] + list $arcBox $outlinedArcBox $coords $start $extent $width $height +} -result {{-1 99 1 101} {-2 98 2 102} {0.0 100.0 0.0 100.0} 0.0 0.0 1.0 0.0} + # cleanup imageCleanup cleanupTests return