func valueToArrayIndex(indexValue Value, length uint, negativeIsZero bool) uint { index := toIntegerFloat(indexValue) if !negativeIsZero { if 0 > length { return uint(index) } if 0 > index { index = math.Max(index+float64(length), 0) } else { index = math.Min(index, float64(length)) } return uint(index) } { index := uint(math.Max(index, 0)) if 0 > length { return index } // minimum(index, length) if index > length { return length } return index } }
func (b *Bounds) ExtendPoint(point Point) *Bounds { b.Min.X = math.Min(b.Min.X, point.X) b.Min.Y = math.Min(b.Min.Y, point.Y) b.Max.X = math.Max(b.Max.X, point.X) b.Max.Y = math.Max(b.Max.Y, point.Y) return b }
func (b *Bounds) ExtendPointZM(pointZM PointZM) *Bounds { b.Min.X = math.Min(b.Min.X, pointZM.X) b.Min.Y = math.Min(b.Min.Y, pointZM.Y) b.Max.X = math.Max(b.Max.X, pointZM.X) b.Max.Y = math.Max(b.Max.Y, pointZM.Y) return b }
func (v3 *Vector3) Max(v *Vector3) *Vector3 { v3.X = math.Max(v3.X, v.X) v3.Y = math.Max(v3.Y, v.Y) v3.Z = math.Max(v3.Z, v.Z) return v3 }
// AdjustSigmoid changes the contrast of the image using a sigmoidal function and returns the adjusted image. // It's a non-linear contrast change useful for photo adjustments as it preserves highlight and shadow detail. // The midpoint parameter is the midpoint of contrast that must be between 0 and 1, typically 0.5. // The factor parameter indicates how much to increase or decrease the contrast, typically in range (-10, 10). // If the factor parameter is positive the image contrast is increased otherwise the contrast is decreased. // // Examples: // // dstImage = imaging.AdjustSigmoid(srcImage, 0.5, 3.0) // increase the contrast // dstImage = imaging.AdjustSigmoid(srcImage, 0.5, -3.0) // decrease the contrast // func AdjustSigmoid(img image.Image, midpoint, factor float64) *image.NRGBA { if factor == 0 { return Clone(img) } lut := make([]uint8, 256) a := math.Min(math.Max(midpoint, 0.0), 1.0) b := math.Abs(factor) sig0 := sigmoid(a, b, 0) sig1 := sigmoid(a, b, 1) e := 1.0e-6 if factor > 0 { for i := 0; i < 256; i++ { x := float64(i) / 255.0 sigX := sigmoid(a, b, x) f := (sigX - sig0) / (sig1 - sig0) lut[i] = clamp(f * 255.0) } } else { for i := 0; i < 256; i++ { x := float64(i) / 255.0 arg := math.Min(math.Max((sig1-sig0)*x+sig0, e), 1.0-e) f := a - math.Log(1.0/arg-1.0)/b lut[i] = clamp(f * 255.0) } } fn := func(c color.NRGBA) color.NRGBA { return color.NRGBA{lut[c.R], lut[c.G], lut[c.B], c.A} } return AdjustFunc(img, fn) }
// area returns the value of the largest area from 3 possible areas created // from the 4 given points. // // Based on bullet btPersistentManifold::calcArea4Points func (con *contactPair) area(p0, p1, p2, p3 *lin.V3) float64 { v0, v1, vx := con.v0, con.v1, con.v2 l0 := vx.Cross(v0.Sub(p0, p1), v1.Sub(p2, p3)).LenSqr() l1 := vx.Cross(v0.Sub(p0, p2), v1.Sub(p1, p3)).LenSqr() l2 := vx.Cross(v0.Sub(p0, p3), v1.Sub(p1, p2)).LenSqr() return math.Max(math.Max(l0, l1), l2) }
func normalizeSlice(valuesA []float64, valuesB []float64) ([]float64, []float64) { offsetA := int(math.Max(0, float64(len(valuesA)-len(valuesB)))) offsetB := int(math.Max(0, float64(len(valuesB)-len(valuesB)))) sliceA := valuesA[offsetA:] sliceB := valuesB[offsetB:] return sliceA, sliceB }
func (g *group) getFoldedSize() (w, h float64) { var inWidth, outWidth, inHeight, outHeight float64 for _, t := range g.inputs { t.refineSize() if t.horizontal { inWidth += t.Width() + GroupIOSpacing } else { inHeight += t.Height() + GroupIOSpacing } } for _, t := range g.outputs { t.refineSize() if t.horizontal { outWidth += t.Width() + GroupIOSpacing } else { outHeight += t.Height() + GroupIOSpacing } } inWidth -= GroupIOSpacing inHeight -= GroupIOSpacing outWidth -= GroupIOSpacing outHeight -= GroupIOSpacing w, h = math.Max(math.Max(inWidth, outWidth), GroupMinSize)+GroupMargin*2, math.Max(math.Max(inHeight, outHeight), GroupMinSize)+GroupMargin*2 return }
// startingStepSize implements the algorithm for estimating the starting step // size as described in: // - Hairer, E., Wanner, G., Nørsett, S.: Solving Ordinary Differential // Equations I: Nonstiff Problems. Springer Berlin Heidelberg (1993) func startingStepSize(rhs Function, init, tmp *State, weight Weighting, w []float64, order float64, s *Settings) float64 { // Store 1 / (rtol * |Y_i| + atol) into w. weight(init.Y, w) d0 := s.Norm(init.Y, w) d1 := s.Norm(init.YDot, w) var h0 float64 if math.Min(d0, d1) < 1e-5 { h0 = 1e-6 } else { // Make the increment of an explicit Euler step small compared to the // size of the initial value. h0 = 0.01 * d0 / d1 } // Perform one explicit Euler step. floats.AddScaledTo(tmp.Y, init.Y, h0, init.YDot) // Evaluate the right-hand side f(init.Time+h, tmp.Y). rhs(tmp.YDot, init.Time+h0, tmp.Y) // Estimate the second derivative of the solution. floats.Sub(tmp.YDot, init.YDot) d2 := s.Norm(tmp.YDot, w) / h0 var h1 float64 if math.Max(d1, d2) < 1e-15 { h1 = math.Max(1e-6, 1e-3*h0) } else { h1 = math.Pow(0.01/math.Max(d1, d2), 1/(order+1)) } return math.Min(100*h0, h1) }
func (v *typeView) reform() { const spacing = 2 maxWidth := float64(0) h1 := float64(0) for i, c := range v.elems.left { h1 += Height(c) if i > 0 { h1 += spacing } if w := Width(c); w > maxWidth { maxWidth = w } } h2 := float64(0) for i, c := range v.elems.right { h2 += Height(c) if i > 0 { h2 += spacing } } if v.unexported != nil { if h2 > 0 { h2 += spacing } h2 += Height(v.unexported) } x := 0.0 if v.name != nil { v.name.Move(Pt(0, (math.Max(h1, h2)-Height(v.name))/2)) x += Width(v.name) + spacing } y := math.Max(0, h2-h1) / 2 for i := len(v.elems.left) - 1; i >= 0; i-- { c := v.elems.left[i] c.Move(Pt(x+maxWidth-Width(c), y)) y += Height(c) + spacing } x += maxWidth + spacing if v.pkg != nil { v.pkg.Move(Pt(x, (math.Max(h1, h2)-Height(v.pkg))/2)) x += Width(v.pkg) } v.text.Move(Pt(x, (math.Max(h1, h2)-Height(v.text))/2)) x += Width(v.text) + spacing y = math.Max(0, h1-h2) / 2 if v.unexported != nil { v.unexported.Move(Pt(x, y)) y += Height(v.unexported) + spacing } for i := len(v.elems.right) - 1; i >= 0; i-- { c := v.elems.right[i] c.Move(Pt(x, y)) y += Height(c) + spacing } ResizeToFit(v, 2) if p, ok := Parent(v).(*typeView); ok { p.reform() } }
func extractImage(image *C.struct__VipsImage, o Options) (*C.struct__VipsImage, error) { var err error = nil inWidth := int(image.Xsize) inHeight := int(image.Ysize) switch { case o.Crop: width := int(math.Min(float64(inWidth), float64(o.Width))) height := int(math.Min(float64(inHeight), float64(o.Height))) left, top := calculateCrop(inWidth, inHeight, o.Width, o.Height, o.Gravity) left, top = int(math.Max(float64(left), 0)), int(math.Max(float64(top), 0)) image, err = vipsExtract(image, left, top, width, height) break case o.Embed: left, top := (o.Width-inWidth)/2, (o.Height-inHeight)/2 image, err = vipsEmbed(image, left, top, o.Width, o.Height, o.Extend) break case o.Top > 0 || o.Left > 0: if o.AreaWidth == 0 { o.AreaHeight = o.Width } if o.AreaHeight == 0 { o.AreaHeight = o.Height } if o.AreaWidth == 0 || o.AreaHeight == 0 { return nil, errors.New("Extract area width/height params are required") } image, err = vipsExtract(image, o.Left, o.Top, o.AreaWidth, o.AreaHeight) break } return image, err }
// generateValidatedLengthExample generates a random size array of examples based on what's given. func (eg *exampleGenerator) generateValidatedLengthExample() interface{} { minlength, maxlength := math.Inf(1), math.Inf(-1) for _, v := range eg.a.Validations { switch actual := v.(type) { case *dslengine.MinLengthValidationDefinition: minlength = math.Min(minlength, float64(actual.MinLength)) maxlength = math.Max(maxlength, float64(actual.MinLength)) case *dslengine.MaxLengthValidationDefinition: minlength = math.Min(minlength, float64(actual.MaxLength)) maxlength = math.Max(maxlength, float64(actual.MaxLength)) } } count := 0 if math.IsInf(minlength, 1) { count = int(maxlength) - (eg.r.Int() % 3) } else if math.IsInf(maxlength, -1) { count = int(minlength) + (eg.r.Int() % 3) } else if minlength < maxlength { count = int(minlength) + (eg.r.Int() % int(maxlength-minlength)) } else if minlength == maxlength { count = int(minlength) } else { panic("Validation: MinLength > MaxLength") } if !eg.a.Type.IsArray() { return eg.r.faker.Characters(count) } res := make([]interface{}, count) for i := 0; i < count; i++ { res[i] = eg.a.Type.ToArray().ElemType.GenerateExample(eg.r) } return res }
func GenerateMap(width, depth int, gridSize int) *Map { m := new(Map) m.width = width m.depth = depth m.gridSize = gridSize m.minHeight = 1000000 m.maxHeight = 0 diag := math.Hypot(float64(m.width/2), float64(m.depth/2)) for z := 0; z < depth; z++ { for x := 0; x < width; x++ { fx := float64(x) + float64(z%2)*0.5 fz := float64(z) d := math.Hypot(float64(m.width/2)-fx, float64(m.depth/2)-fz) d = 1.0 - d/diag h := noise.OctaveNoise2d(fx, fz, 4, 0.25, 1.0/28) h = (h + 1.0) * 0.5 h = math.Sqrt(h) * 1024 * (math.Pow(d, 2)) h = math.Max(h, 120) m.heightMap = append(m.heightMap, float32(h)) m.minHeight = math.Min(m.minHeight, h) m.maxHeight = math.Max(m.maxHeight, h) } } return m }
func (pm *ProjectileManager) CheckCollision(p pM.Projectiler, dx, dy float64) (bool, gameObjectsBase.Activer) { center := p.GetCenter() newCenter := geometry.MakePoint(center.X+dx, center.Y+dy) rects := make([]*geometry.Rectangle, 0, 100) rect2obj := make(map[*geometry.Rectangle]gameObjectsBase.Activer) for i := int(math.Min(center.Y, newCenter.Y)); i <= int(math.Max(center.Y, newCenter.Y)); i++ { for j := int(math.Min(center.X, newCenter.X)); j <= int(math.Max(center.X, newCenter.X)); j++ { if pm.field.IsBlocked(j, i) { rects = append(rects, pm.field.GetCellRectangle(j, i)) } else { for _, actor := range pm.field.GetActors(j, i) { r := actor.GetRectangle() rects = append(rects, &r) rect2obj[&r] = actor } } } } s := geometry.MakeSegment(center.X, center.Y, center.X+dx, center.Y+dy) for _, rect := range rects { if rect.CrossedBySegment(s) { return true, rect2obj[rect] } } return false, nil }
// GetStringBounds returns the approximate pixel bounds of the string s at x, y. // The left edge of the em square of the first character of s // and the baseline intersect at 0, 0 in the returned coordinates. // Therefore the top and left coordinates may well be negative. func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bottom float64) { font, err := gc.loadCurrentFont() if err != nil { log.Println(err) return 0, 0, 0, 0 } top, left, bottom, right = 10e6, 10e6, -10e6, -10e6 cursor := 0.0 prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := font.Index(rune) if hasPrev { cursor += fUnitsToFloat64(font.Kerning(int32(gc.Current.Scale), prev, index)) } if err := gc.glyphBuf.Load(gc.Current.Font, int32(gc.Current.Scale), index, truetype.NoHinting); err != nil { log.Println(err) return 0, 0, 0, 0 } e0 := 0 for _, e1 := range gc.glyphBuf.End { ps := gc.glyphBuf.Point[e0:e1] for _, p := range ps { x, y := pointToF64Point(p) top = math.Min(top, y) bottom = math.Max(bottom, y) left = math.Min(left, x+cursor) right = math.Max(right, x+cursor) } } cursor += fUnitsToFloat64(font.HMetric(int32(gc.Current.Scale), index).AdvanceWidth) prev, hasPrev = index, true } return left, top, right, bottom }
// PointArea returns the area on the unit sphere for the triangle defined by the // given points. // // This method is based on l'Huilier's theorem, // // tan(E/4) = sqrt(tan(s/2) tan((s-a)/2) tan((s-b)/2) tan((s-c)/2)) // // where E is the spherical excess of the triangle (i.e. its area), // a, b, c are the side lengths, and // s is the semiperimeter (a + b + c) / 2. // // The only significant source of error using l'Huilier's method is the // cancellation error of the terms (s-a), (s-b), (s-c). This leads to a // *relative* error of about 1e-16 * s / min(s-a, s-b, s-c). This compares // to a relative error of about 1e-15 / E using Girard's formula, where E is // the true area of the triangle. Girard's formula can be even worse than // this for very small triangles, e.g. a triangle with a true area of 1e-30 // might evaluate to 1e-5. // // So, we prefer l'Huilier's formula unless dmin < s * (0.1 * E), where // dmin = min(s-a, s-b, s-c). This basically includes all triangles // except for extremely long and skinny ones. // // Since we don't know E, we would like a conservative upper bound on // the triangle area in terms of s and dmin. It's possible to show that // E <= k1 * s * sqrt(s * dmin), where k1 = 2*sqrt(3)/Pi (about 1). // Using this, it's easy to show that we should always use l'Huilier's // method if dmin >= k2 * s^5, where k2 is about 1e-2. Furthermore, // if dmin < k2 * s^5, the triangle area is at most k3 * s^4, where // k3 is about 0.1. Since the best case error using Girard's formula // is about 1e-15, this means that we shouldn't even consider it unless // s >= 3e-4 or so. func PointArea(a, b, c Point) float64 { sa := float64(b.Angle(c.Vector)) sb := float64(c.Angle(a.Vector)) sc := float64(a.Angle(b.Vector)) s := 0.5 * (sa + sb + sc) if s >= 3e-4 { // Consider whether Girard's formula might be more accurate. dmin := s - math.Max(sa, math.Max(sb, sc)) if dmin < 1e-2*s*s*s*s*s { // This triangle is skinny enough to use Girard's formula. ab := a.PointCross(b) bc := b.PointCross(c) ac := a.PointCross(c) area := math.Max(0.0, float64(ab.Angle(ac.Vector)-ab.Angle(bc.Vector)+bc.Angle(ac.Vector))) if dmin < s*0.1*area { return area } } } // Use l'Huilier's formula. return 4 * math.Atan(math.Sqrt(math.Max(0.0, math.Tan(0.5*s)*math.Tan(0.5*(s-sa))* math.Tan(0.5*(s-sb))*math.Tan(0.5*(s-sc))))) }
// RGBToHSV converts an RGB triple to a HSV triple. // // Ported from http://goo.gl/Vg1h9 func RGBToHSV(r, g, b uint8) (h, s, v float64) { fR := float64(r) / 255 fG := float64(g) / 255 fB := float64(b) / 255 max := math.Max(math.Max(fR, fG), fB) min := math.Min(math.Min(fR, fG), fB) d := max - min s, v = 0, max if max > 0 { s = d / max } if max == min { // Achromatic. h = 0 } else { // Chromatic. switch max { case fR: h = (fG - fB) / d if fG < fB { h += 6 } case fG: h = (fB-fR)/d + 2 case fB: h = (fR-fG)/d + 4 } h /= 6 } return }
// Expand returns a bounding box that holds both bounding box and a vector. func (b BB) Expand(v Vect) BB { return BB{ math.Min(b.l, v.X), math.Min(b.b, v.Y), math.Max(b.r, v.X), math.Max(b.t, v.Y)} }
func subtractPSF(psf []float32, psfWidth uint64, residual []float32, residualWidth uint64, peakPos uint64, psfPeakPos uint64, absPeakVal float32, gain float32) { var rx = float64(xpos(peakPos, residualWidth)) var ry = float64(ypos(peakPos, residualWidth)) var px = float64(xpos(psfPeakPos, psfWidth)) var py = float64(ypos(psfPeakPos, psfWidth)) var diffx uint64 = uint64(rx - px) var diffy uint64 = uint64(ry - py) var startx = math.Max(0, float64(rx-px)) var starty = math.Max(0, float64(ry-py)) var stopx = math.Min(float64(residualWidth-1), rx+(float64(psfWidth)-px-1)) var stopy = math.Min(float64(residualWidth-1), ry+(float64(psfWidth)-py-1)) factor := gain * absPeakVal for y := uint64(starty); y <= uint64(stopy); y++ { for x := uint64(startx); x <= uint64(stopx); x++ { residual[posToIdx(residualWidth, x, y)] -= factor * psf[posToIdx(psfWidth, x-diffx, y-diffy)] } } }
// Merge returns a bounding box that holds both bounding boxes. func (a BB) Merge(b BB) BB { return BB{ math.Min(a.l, b.l), math.Min(a.b, b.b), math.Max(a.r, b.r), math.Max(a.t, b.t)} }
func cellIDFromFaceIJWrap(f, i, j int) CellID { // Convert i and j to the coordinates of a leaf cell just beyond the // boundary of this face. This prevents 32-bit overflow in the case // of finding the neighbors of a face cell. i = clamp(i, -1, maxSize) j = clamp(j, -1, maxSize) // We want to wrap these coordinates onto the appropriate adjacent face. // The easiest way to do this is to convert the (i,j) coordinates to (x,y,z) // (which yields a point outside the normal face boundary), and then call // xyzToFaceUV to project back onto the correct face. // // The code below converts (i,j) to (si,ti), and then (si,ti) to (u,v) using // the linear projection (u=2*s-1 and v=2*t-1). (The code further below // converts back using the inverse projection, s=0.5*(u+1) and t=0.5*(v+1). // Any projection would work here, so we use the simplest.) We also clamp // the (u,v) coordinates so that the point is barely outside the // [-1,1]x[-1,1] face rectangle, since otherwise the reprojection step // (which divides by the new z coordinate) might change the other // coordinates enough so that we end up in the wrong leaf cell. const scale = 1.0 / maxSize limit := math.Nextafter(1, 2) u := math.Max(-limit, math.Min(limit, scale*float64((i<<1)+1-maxSize))) v := math.Max(-limit, math.Min(limit, scale*float64((j<<1)+1-maxSize))) // Find the leaf cell coordinates on the adjacent face, and convert // them to a cell id at the appropriate level. f, u, v = xyzToFaceUV(faceUVToXYZ(f, u, v)) return cellIDFromFaceIJ(f, stToIJ(0.5*(u+1)), stToIJ(0.5*(v+1))) }
// MMIDistance calculates the MMI at distance for New Zealand. Distance and depth are in km. func MMIDistance(distance, depth, mmi float64) float64 { // Minimum depth of 5 for numerical instability. d := math.Max(math.Abs(depth), 5.0) s := math.Hypot(d, distance) return math.Max(mmi-1.18*math.Log(s/d)-0.0044*(s-d), -1.0) }
func (v3 *Vector3) Clamp(min, max *Vector3) *Vector3 { v3.X = math.Max(min.X, math.Min(max.X, v3.X)) v3.Y = math.Max(min.Y, math.Min(max.Y, v3.Y)) v3.Z = math.Max(min.Z, math.Min(max.Z, v3.Z)) return v3 }
// RGBToHSL converts an RGB triple to a HSL triple. // // Ported from http://goo.gl/Vg1h9 func RGBToHSL(r, g, b uint8) (h, s, l float64) { fR := float64(r) / 255 fG := float64(g) / 255 fB := float64(b) / 255 max := math.Max(math.Max(fR, fG), fB) min := math.Min(math.Min(fR, fG), fB) l = (max + min) / 2 if max == min { // Achromatic. h, s = 0, 0 } else { // Chromatic. d := max - min if l > 0.5 { s = d / (2.0 - max - min) } else { s = d / (max + min) } switch max { case fR: h = (fG - fB) / d if fG < fB { h += 6 } case fG: h = (fB-fR)/d + 2 case fB: h = (fR-fG)/d + 4 } h /= 6 } return }
// A simple comparison checking if minimum and maximums in both datasets are within allowedVariance // If this function changes, PrintToStdout should be updated accordingly. func isResourceUsageSimilarEnough(left, right percentileUsageData, allowedVariance float64) bool { if len(left.cpuData) == 0 || len(left.memData) == 0 || len(right.cpuData) == 0 || len(right.memData) == 0 { glog.V(4).Infof("Length of at least one data vector is zero. Returning false for the lack of data.") return false } sort.Float64s(left.cpuData) sort.Float64s(right.cpuData) sort.Sort(int64arr(left.memData)) sort.Sort(int64arr(right.memData)) leftCPUMin := math.Max(left.cpuData[0], minCPU) leftCPUMax := math.Max(left.cpuData[len(left.cpuData)-1], minCPU) leftMemMin := max(left.memData[0], minMem) leftMemMax := max(left.memData[len(left.memData)-1], minMem) rightCPUMin := math.Max(right.cpuData[0], minCPU) rightCPUMax := math.Max(right.cpuData[len(right.cpuData)-1], minCPU) rightMemMin := max(right.memData[0], minMem) rightMemMax := max(right.memData[len(right.memData)-1], minMem) return leq(leftCPUMin, allowedVariance*rightCPUMin) && leq(rightCPUMin, allowedVariance*leftCPUMin) && leq(leftCPUMax, allowedVariance*rightCPUMax) && leq(rightCPUMax, allowedVariance*leftCPUMax) && leq(float64(leftMemMin), allowedVariance*float64(rightMemMin)) && leq(float64(rightMemMin), allowedVariance*float64(leftMemMin)) && leq(float64(leftMemMax), allowedVariance*float64(rightMemMax)) && leq(float64(rightMemMax), allowedVariance*float64(leftMemMax)) }
func RectsIntersection(r1, r2 Rect) (ri Rect) { ri.Min.X = math.Max(r1.Min.X, r2.Min.X) ri.Min.Y = math.Max(r1.Min.Y, r2.Min.Y) ri.Max.X = math.Min(r1.Max.X, r2.Max.X) ri.Max.Y = math.Min(r1.Max.Y, r2.Max.Y) return }
func (b *Bounds) ExtendPointZ(pointZ PointZ) *Bounds { b.Min.X = math.Min(b.Min.X, pointZ.X) b.Min.Y = math.Min(b.Min.Y, pointZ.Y) b.Max.X = math.Max(b.Max.X, pointZ.X) b.Max.Y = math.Max(b.Max.Y, pointZ.Y) return b }
func (h *Histogram) Percentiles(percentiles ...float64) []int { result := make([]int, len(percentiles)) if percentiles == nil || len(percentiles) == 0 { return result } sort.Sort(sort.Float64Slice(percentiles)) accum := 0 p_idx := int(math.Max(1.0, percentiles[0]*float64(h.n))) for i, j := 0, 0; i < len(percentiles) && j < len(h.values); j++ { accum += h.values[j] for accum >= p_idx { result[i] = j i++ if i >= len(percentiles) { break } p_idx = int(math.Max(1.0, percentiles[i]*float64(h.n))) } } return result }
// Calculate a Kolmogorov-Smirnov test statistic. func KsStat(vector govector.Vector, conf AnomalyzerConf) float64 { reference, active, err := extractWindows(vector, conf.referenceSize, conf.ActiveSize, conf.ActiveSize) if err != nil { return NA } n1 := len(reference) n2 := len(active) if n1%n2 != 0 { return NA } // First sort the active data and generate a cummulative distribution function // using that data. Do the same for the reference data. activeEcdf := active.Ecdf() refEcdf := reference.Ecdf() // We want the reference and active vectors to have the same length n, so we // consider the min and max for each and interpolated the points between. min := math.Min(reference.Min(), active.Min()) max := math.Max(reference.Max(), active.Max()) interpolated := interpolate(min, max, n1+n2) // Then we apply the distribution function over the interpolated data. activeDist := interpolated.Apply(activeEcdf) refDist := interpolated.Apply(refEcdf) // Find the maximum displacement between both distributions. d := 0.0 for i := 0; i < n1+n2; i++ { d = math.Max(d, math.Abs(activeDist[i]-refDist[i])) } return d }
// Change the aspect ratio of a rectangle. // The mode can be "area", "width", "height", "fit", "fill" or "stretch". // Panics if mode is empty or unrecognized. func SetAspect(w, h, aspect float64, mode string) (float64, float64) { switch mode { case "area": // aspect = width / height // width = height * aspect // width^2 = width * height * aspect // height = width / aspect // height^2 = width * height / aspect w, h = math.Sqrt(w*h*aspect), math.Sqrt(w*h/aspect) case "width": // Set height from width. h = w / aspect case "height": // Set width from height. w = h * aspect case "fit": // Shrink one dimension. w, h = math.Min(w, h*aspect), math.Min(h, w/aspect) case "fill": // Grow one dimension. w, h = math.Max(w, h*aspect), math.Max(h, w/aspect) case "stretch": // Do nothing. case "": panic("no mode specified") default: panic("unknown mode: " + mode) } return w, h }