From bf851b7accfe65e18edffaa7eceaa0a7bf409e79 Mon Sep 17 00:00:00 2001 From: fvogel Date: Wed, 3 Apr 2019 20:49:28 +0000 Subject: Remove the error that was triggering with very small arcs while still preventing NaN and Inf values to leak in the computations. Add a new test canvas-21.1 checking results for zero-length arcs. --- generic/tkCanvArc.c | 33 ++++++++++++++++++--------------- tests/canvas.test | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/generic/tkCanvArc.c b/generic/tkCanvArc.c index ead03bf..608caf7 100644 --- a/generic/tkCanvArc.c +++ b/generic/tkCanvArc.c @@ -185,7 +185,7 @@ 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 int ComputeArcFromHeight(ArcItem *arcPtr); +static void ComputeArcFromHeight(ArcItem *arcPtr); static int CreateArc(Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, int objc, Tcl_Obj *const objv[]); @@ -475,14 +475,7 @@ ConfigureArc( * overridden. */ if (arcPtr->height != 0) { - int ret = ComputeArcFromHeight(arcPtr); - if (ret != TCL_OK) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "coordinates too close to define a chord")); - Tcl_SetErrorCode(interp, "TK", "CANVAS", "COORDS", "ARC", - NULL); - return ret; - } + ComputeArcFromHeight(arcPtr); ComputeArcBbox(canvas, arcPtr); } @@ -604,7 +597,7 @@ ConfigureArc( * end-point and height (!= 0). * * Results: - * TCL_ERROR if the chord length is zero, TCL_OK otherwise. + * None. * * Side effects: * The height parameter is set to 0 on exit. @@ -612,7 +605,7 @@ ConfigureArc( *-------------------------------------------------------------- */ -static int +static void ComputeArcFromHeight( ArcItem* arcPtr) { @@ -625,8 +618,20 @@ ComputeArcFromHeight( chordLen = hypot(arcPtr->endPoint[1] - arcPtr->startPoint[1], arcPtr->startPoint[0] - arcPtr->endPoint[0]); - if (chordLen < DBL_EPSILON) - return TCL_ERROR; + if (chordLen < DBL_EPSILON) { + + /* + * Specialize computations for zero-length arc to avoid NaN or Inf. + */ + + arcPtr->start = arcPtr->extent = 0; + arcPtr->bbox[0] = arcPtr->bbox[2] = + (arcPtr->startPoint[0] + arcPtr->endPoint[0]) / 2; + arcPtr->bbox[1] = arcPtr->bbox[3] = + (arcPtr->startPoint[1] + arcPtr->endPoint[1]) / 2; + arcPtr->height = 0; + return; + } chordDir[0] = (arcPtr->endPoint[0] - arcPtr->startPoint[0]) / chordLen; chordDir[1] = (arcPtr->endPoint[1] - arcPtr->startPoint[1]) / chordLen; @@ -681,8 +686,6 @@ ComputeArcFromHeight( */ arcPtr->height = 0; - - return TCL_OK; } /* diff --git a/tests/canvas.test b/tests/canvas.test index e8dc332..dafce90 100644 --- a/tests/canvas.test +++ b/tests/canvas.test @@ -1040,6 +1040,24 @@ test canvas-20.3 {canvas image with subsample and zoom} -setup { 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 -- cgit v0.12