diff options
Diffstat (limited to 'Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go')
-rw-r--r-- | Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go | 696 |
1 files changed, 696 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go new file mode 100644 index 000000000..a888b22a1 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/draw2d/draw2d/curve/cubic_float64_others.go @@ -0,0 +1,696 @@ +// Copyright 2010 The draw2d Authors. All rights reserved. +// created: 17/05/2011 by Laurent Le Goff +package curve + +import ( + "math" +) + +const ( + CurveCollinearityEpsilon = 1e-30 + CurveAngleToleranceEpsilon = 0.01 +) + +//mu ranges from 0 to 1, start to end of curve +func (c *CubicCurveFloat64) ArbitraryPoint(mu float64) (x, y float64) { + + mum1 := 1 - mu + mum13 := mum1 * mum1 * mum1 + mu3 := mu * mu * mu + + x = mum13*c[0] + 3*mu*mum1*mum1*c[2] + 3*mu*mu*mum1*c[4] + mu3*c[6] + y = mum13*c[1] + 3*mu*mum1*mum1*c[3] + 3*mu*mu*mum1*c[5] + mu3*c[7] + return +} + +func (c *CubicCurveFloat64) SubdivideAt(c1, c2 *CubicCurveFloat64, t float64) (x23, y23 float64) { + inv_t := (1 - t) + c1[0], c1[1] = c[0], c[1] + c2[6], c2[7] = c[6], c[7] + + c1[2] = inv_t*c[0] + t*c[2] + c1[3] = inv_t*c[1] + t*c[3] + + x23 = inv_t*c[2] + t*c[4] + y23 = inv_t*c[3] + t*c[5] + + c2[4] = inv_t*c[4] + t*c[6] + c2[5] = inv_t*c[5] + t*c[7] + + c1[4] = inv_t*c1[2] + t*x23 + c1[5] = inv_t*c1[3] + t*y23 + + c2[2] = inv_t*x23 + t*c2[4] + c2[3] = inv_t*y23 + t*c2[5] + + c1[6] = inv_t*c1[4] + t*c2[2] + c1[7] = inv_t*c1[5] + t*c2[3] + + c2[0], c2[1] = c1[6], c1[7] + return +} + +func (c *CubicCurveFloat64) EstimateDistance() float64 { + dx1 := c[2] - c[0] + dy1 := c[3] - c[1] + dx2 := c[4] - c[2] + dy2 := c[5] - c[3] + dx3 := c[6] - c[4] + dy3 := c[7] - c[5] + return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3) +} + +// subdivide the curve in straight lines using line approximation and Casteljau recursive subdivision +func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) { + c.segmentRec(t, flattening_threshold) + t.LineTo(c[6], c[7]) +} + +func (c *CubicCurveFloat64) segmentRec(t LineTracer, flattening_threshold float64) { + var c1, c2 CubicCurveFloat64 + c.Subdivide(&c1, &c2) + + // Try to approximate the full cubic curve by a single straight line + //------------------ + dx := c[6] - c[0] + dy := c[7] - c[1] + + d2 := math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) + d3 := math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) + + if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) { + t.LineTo(c[6], c[7]) + return + } + // Continue subdivision + //---------------------- + c1.segmentRec(t, flattening_threshold) + c2.segmentRec(t, flattening_threshold) +} + +/* + The function has the following parameters: + approximationScale : + Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one. + It always has some scaling coefficient. + The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels. + Usually it looks as follows: + curved.approximationScale(transform.scale()); + where transform is the affine matrix that includes all the transformations, including viewport and zoom. + angleTolerance : + You set it in radians. + The less this value is the more accurate will be the approximation at sharp turns. + But 0 means that we don't consider angle conditions at all. + cuspLimit : + An angle in radians. + If 0, only the real cusps will have bevel cuts. + If more than 0, it will restrict the sharpness. + The more this value is the less sharp turns will be cut. + Typically it should not exceed 10-15 degrees. +*/ +func (c *CubicCurveFloat64) AdaptiveSegmentRec(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) { + cuspLimit = computeCuspLimit(cuspLimit) + distanceToleranceSquare := 0.5 / approximationScale + distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare + c.adaptiveSegmentRec(t, 0, distanceToleranceSquare, angleTolerance, cuspLimit) + t.LineTo(c[6], c[7]) +} + +func computeCuspLimit(v float64) (r float64) { + if v == 0.0 { + r = 0.0 + } else { + r = math.Pi - v + } + return +} + +func squareDistance(x1, y1, x2, y2 float64) float64 { + dx := x2 - x1 + dy := y2 - y1 + return dx*dx + dy*dy +} + +/** + * http://www.antigrain.com/research/adaptive_bezier/index.html + */ +func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) { + if level > CurveRecursionLimit { + return + } + var c1, c2 CubicCurveFloat64 + x23, y23 := c.Subdivide(&c1, &c2) + + // Try to approximate the full cubic curve by a single straight line + //------------------ + dx := c[6] - c[0] + dy := c[7] - c[1] + + d2 := math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) + d3 := math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) + switch { + case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + // All collinear OR p1==p4 + //---------------------- + k := dx*dx + dy*dy + if k == 0 { + d2 = squareDistance(c[0], c[1], c[2], c[3]) + d3 = squareDistance(c[6], c[7], c[4], c[5]) + } else { + k = 1 / k + da1 := c[2] - c[0] + da2 := c[3] - c[1] + d2 = k * (da1*dx + da2*dy) + da1 = c[4] - c[0] + da2 = c[5] - c[1] + d3 = k * (da1*dx + da2*dy) + if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { + // Simple collinear case, 1---2---3---4 + // We can leave just two endpoints + return + } + if d2 <= 0 { + d2 = squareDistance(c[2], c[3], c[0], c[1]) + } else if d2 >= 1 { + d2 = squareDistance(c[2], c[3], c[6], c[7]) + } else { + d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy) + } + + if d3 <= 0 { + d3 = squareDistance(c[4], c[5], c[0], c[1]) + } else if d3 >= 1 { + d3 = squareDistance(c[4], c[5], c[6], c[7]) + } else { + d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy) + } + } + if d2 > d3 { + if d2 < distanceToleranceSquare { + t.LineTo(c[2], c[3]) + return + } + } else { + if d3 < distanceToleranceSquare { + t.LineTo(c[4], c[5]) + return + } + } + + case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + // p1,p2,p4 are collinear, p3 is significant + //---------------------- + if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + return + } + + // Angle Condition + //---------------------- + da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + return + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[4], c[5]) + return + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + // p1,p3,p4 are collinear, p2 is significant + //---------------------- + if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + return + } + + // Angle Condition + //---------------------- + da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + return + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + return + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + // Regular case + //----------------- + if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { + // If the curvature doesn't exceed the distanceTolerance value + // we tend to finish subdivisions. + //---------------------- + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + return + } + + // Angle & Cusp Condition + //---------------------- + k := math.Atan2(c[5]-c[3], c[4]-c[2]) + da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) + da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + if da2 >= math.Pi { + da2 = 2*math.Pi - da2 + } + + if da1+da2 < angleTolerance { + // Finally we can stop the recursion + //---------------------- + t.LineTo(x23, y23) + return + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + return + } + + if da2 > cuspLimit { + t.LineTo(c[4], c[5]) + return + } + } + } + } + + // Continue subdivision + //---------------------- + c1.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) + c2.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) + +} + +func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) { + cuspLimit = computeCuspLimit(cuspLimit) + distanceToleranceSquare := 0.5 / approximationScale + distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare + + var curves [CurveRecursionLimit]CubicCurveFloat64 + curves[0] = *curve + i := 0 + // current curve + var c *CubicCurveFloat64 + var c1, c2 CubicCurveFloat64 + var dx, dy, d2, d3, k, x23, y23 float64 + for i >= 0 { + c = &curves[i] + x23, y23 = c.Subdivide(&c1, &c2) + + // Try to approximate the full cubic curve by a single straight line + //------------------ + dx = c[6] - c[0] + dy = c[7] - c[1] + + d2 = math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) + d3 = math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) + switch { + case i == len(curves)-1: + t.LineTo(c[6], c[7]) + i-- + continue + case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + // All collinear OR p1==p4 + //---------------------- + k = dx*dx + dy*dy + if k == 0 { + d2 = squareDistance(c[0], c[1], c[2], c[3]) + d3 = squareDistance(c[6], c[7], c[4], c[5]) + } else { + k = 1 / k + da1 := c[2] - c[0] + da2 := c[3] - c[1] + d2 = k * (da1*dx + da2*dy) + da1 = c[4] - c[0] + da2 = c[5] - c[1] + d3 = k * (da1*dx + da2*dy) + if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { + // Simple collinear case, 1---2---3---4 + // We can leave just two endpoints + i-- + continue + } + if d2 <= 0 { + d2 = squareDistance(c[2], c[3], c[0], c[1]) + } else if d2 >= 1 { + d2 = squareDistance(c[2], c[3], c[6], c[7]) + } else { + d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy) + } + + if d3 <= 0 { + d3 = squareDistance(c[4], c[5], c[0], c[1]) + } else if d3 >= 1 { + d3 = squareDistance(c[4], c[5], c[6], c[7]) + } else { + d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy) + } + } + if d2 > d3 { + if d2 < distanceToleranceSquare { + t.LineTo(c[2], c[3]) + i-- + continue + } + } else { + if d3 < distanceToleranceSquare { + t.LineTo(c[4], c[5]) + i-- + continue + } + } + + case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + // p1,p2,p4 are collinear, p3 is significant + //---------------------- + if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + i-- + continue + } + + // Angle Condition + //---------------------- + da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + i-- + continue + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[4], c[5]) + i-- + continue + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + // p1,p3,p4 are collinear, p2 is significant + //---------------------- + if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + i-- + continue + } + + // Angle Condition + //---------------------- + da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + i-- + continue + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + i-- + continue + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + // Regular case + //----------------- + if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { + // If the curvature doesn't exceed the distanceTolerance value + // we tend to finish subdivisions. + //---------------------- + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + i-- + continue + } + + // Angle & Cusp Condition + //---------------------- + k := math.Atan2(c[5]-c[3], c[4]-c[2]) + da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) + da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + if da2 >= math.Pi { + da2 = 2*math.Pi - da2 + } + + if da1+da2 < angleTolerance { + // Finally we can stop the recursion + //---------------------- + t.LineTo(x23, y23) + i-- + continue + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + i-- + continue + } + + if da2 > cuspLimit { + t.LineTo(c[4], c[5]) + i-- + continue + } + } + } + } + + // Continue subdivision + //---------------------- + curves[i+1], curves[i] = c1, c2 + i++ + } + t.LineTo(curve[6], curve[7]) +} + +/********************** Ahmad thesis *******************/ + +/************************************************************************************** +* This code is the implementation of the Parabolic Approximation (PA). Although * +* it uses recursive subdivision as a safe net for the failing cases, this is an * +* iterative routine and reduces considerably the number of vertices (point) * +* generation. * +**************************************************************************************/ + +func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) { + estimatedIFP := c.numberOfInflectionPoints() + if estimatedIFP == 0 { + // If no inflection points then apply PA on the full Bezier segment. + c.doParabolicApproximation(t, flattening_threshold) + return + } + // If one or more inflection point then we will have to subdivide the curve + numOfIfP, t1, t2 := c.findInflectionPoints() + if numOfIfP == 2 { + // Case when 2 inflection points then divide at the smallest one first + var sub1, tmp1, sub2, sub3 CubicCurveFloat64 + c.SubdivideAt(&sub1, &tmp1, t1) + // Now find the second inflection point in the second curve an subdivide + numOfIfP, t1, t2 = tmp1.findInflectionPoints() + if numOfIfP == 2 { + tmp1.SubdivideAt(&sub2, &sub3, t2) + } else if numOfIfP == 1 { + tmp1.SubdivideAt(&sub2, &sub3, t1) + } else { + return + } + // Use PA for first subsegment + sub1.doParabolicApproximation(t, flattening_threshold) + // Use RS for the second (middle) subsegment + sub2.Segment(t, flattening_threshold) + // Drop the last point in the array will be added by the PA in third subsegment + //noOfPoints--; + // Use PA for the third curve + sub3.doParabolicApproximation(t, flattening_threshold) + } else if numOfIfP == 1 { + // Case where there is one inflection point, subdivide once and use PA on + // both subsegments + var sub1, sub2 CubicCurveFloat64 + c.SubdivideAt(&sub1, &sub2, t1) + sub1.doParabolicApproximation(t, flattening_threshold) + //noOfPoints--; + sub2.doParabolicApproximation(t, flattening_threshold) + } else { + // Case where there is no inflection USA PA directly + c.doParabolicApproximation(t, flattening_threshold) + } +} + +// Find the third control point deviation form the axis +func (c *CubicCurveFloat64) thirdControlPointDeviation() float64 { + dx := c[2] - c[0] + dy := c[3] - c[1] + l2 := dx*dx + dy*dy + if l2 == 0 { + return 0 + } + l := math.Sqrt(l2) + r := (c[3] - c[1]) / l + s := (c[0] - c[2]) / l + u := (c[2]*c[1] - c[0]*c[3]) / l + return math.Abs(r*c[4] + s*c[5] + u) +} + +// Find the number of inflection point +func (c *CubicCurveFloat64) numberOfInflectionPoints() int { + dx21 := (c[2] - c[0]) + dy21 := (c[3] - c[1]) + dx32 := (c[4] - c[2]) + dy32 := (c[5] - c[3]) + dx43 := (c[6] - c[4]) + dy43 := (c[7] - c[5]) + if ((dx21*dy32 - dy21*dx32) * (dx32*dy43 - dy32*dx43)) < 0 { + return 1 // One inflection point + } else if ((dx21*dy32 - dy21*dx32) * (dx21*dy43 - dy21*dx43)) > 0 { + return 0 // No inflection point + } else { + // Most cases no inflection point + b1 := (dx21*dx32 + dy21*dy32) > 0 + b2 := (dx32*dx43 + dy32*dy43) > 0 + if b1 || b2 && !(b1 && b2) { // xor!! + return 0 + } + } + return -1 // cases where there in zero or two inflection points +} + +// This is the main function where all the work is done +func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flattening_threshold float64) { + var c *CubicCurveFloat64 + c = curve + var d, t, dx, dy, d2, d3 float64 + for { + dx = c[6] - c[0] + dy = c[7] - c[1] + + d2 = math.Abs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) + d3 = math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) + + if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) { + // If the subsegment deviation satisfy the flatness then store the last + // point and stop + tracer.LineTo(c[6], c[7]) + break + } + // Find the third control point deviation and the t values for subdivision + d = c.thirdControlPointDeviation() + t = 2 * math.Sqrt(flattening_threshold/d/3) + if t > 1 { + // Case where the t value calculated is invalid so using RS + c.Segment(tracer, flattening_threshold) + break + } + // Valid t value to subdivide at that calculated value + var b1, b2 CubicCurveFloat64 + c.SubdivideAt(&b1, &b2, t) + // First subsegment should have its deviation equal to flatness + dx = b1[6] - b1[0] + dy = b1[7] - b1[1] + + d2 = math.Abs(((b1[2]-b1[6])*dy - (b1[3]-b1[7])*dx)) + d3 = math.Abs(((b1[4]-b1[6])*dy - (b1[5]-b1[7])*dx)) + + if (d2+d3)*(d2+d3) > flattening_threshold*(dx*dx+dy*dy) { + // if not then use RS to handle any mathematical errors + b1.Segment(tracer, flattening_threshold) + } else { + tracer.LineTo(b1[6], b1[7]) + } + // repeat the process for the left over subsegment. + c = &b2 + } +} + +// Find the actual inflection points and return the number of inflection points found +// if 2 inflection points found, the first one returned will be with smaller t value. +func (curve *CubicCurveFloat64) findInflectionPoints() (int, firstIfp, secondIfp float64) { + // For Cubic Bezier curve with equation P=a*t^3 + b*t^2 + c*t + d + // slope of the curve dP/dt = 3*a*t^2 + 2*b*t + c + // a = (float)(-bez.p1 + 3*bez.p2 - 3*bez.p3 + bez.p4); + // b = (float)(3*bez.p1 - 6*bez.p2 + 3*bez.p3); + // c = (float)(-3*bez.p1 + 3*bez.p2); + ax := (-curve[0] + 3*curve[2] - 3*curve[4] + curve[6]) + bx := (3*curve[0] - 6*curve[2] + 3*curve[4]) + cx := (-3*curve[0] + 3*curve[2]) + ay := (-curve[1] + 3*curve[3] - 3*curve[5] + curve[7]) + by := (3*curve[1] - 6*curve[3] + 3*curve[5]) + cy := (-3*curve[1] + 3*curve[3]) + a := (3 * (ay*bx - ax*by)) + b := (3 * (ay*cx - ax*cy)) + c := (by*cx - bx*cy) + r2 := (b*b - 4*a*c) + firstIfp = 0.0 + secondIfp = 0.0 + if r2 >= 0.0 && a != 0.0 { + r := math.Sqrt(r2) + firstIfp = ((-b + r) / (2 * a)) + secondIfp = ((-b - r) / (2 * a)) + if (firstIfp > 0.0 && firstIfp < 1.0) && (secondIfp > 0.0 && secondIfp < 1.0) { + if firstIfp > secondIfp { + tmp := firstIfp + firstIfp = secondIfp + secondIfp = tmp + } + if secondIfp-firstIfp > 0.00001 { + return 2, firstIfp, secondIfp + } else { + return 1, firstIfp, secondIfp + } + } else if firstIfp > 0.0 && firstIfp < 1.0 { + return 1, firstIfp, secondIfp + } else if secondIfp > 0.0 && secondIfp < 1.0 { + firstIfp = secondIfp + return 1, firstIfp, secondIfp + } + return 0, firstIfp, secondIfp + } + return 0, firstIfp, secondIfp +} |