github.com/searKing/golang/go@v1.2.117/image/geom.go (about)

     1  // Copyright 2022 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package image
     6  
     7  import (
     8  	"image"
     9  	"math"
    10  )
    11  
    12  // UnionPoints returns the smallest rectangle that contains all points.
    13  // an empty rectangle is a empty set, Not a point
    14  func UnionPoints(pts ...image.Point) image.Rectangle {
    15  	if len(pts) == 0 {
    16  		return image.Rectangle{}
    17  	}
    18  
    19  	r := image.Rectangle{
    20  		Min: pts[0],
    21  		Max: pts[0],
    22  	}
    23  	for _, p := range pts[1:] {
    24  		if p.X < r.Min.X {
    25  			r.Min.X = p.X
    26  		}
    27  		if p.Y < r.Min.Y {
    28  			r.Min.Y = p.Y
    29  		}
    30  		if p.X > r.Max.X {
    31  			r.Max.X = p.X
    32  		}
    33  		if p.Y > r.Max.Y {
    34  			r.Max.Y = p.Y
    35  		}
    36  	}
    37  	return r
    38  }
    39  
    40  // UnionRectangles returns the smallest rectangle that contains all rectangles, empty rectangles excluded.
    41  func UnionRectangles(rs ...image.Rectangle) image.Rectangle {
    42  	var ur image.Rectangle
    43  	for _, r := range rs {
    44  		ur = ur.Union(r)
    45  	}
    46  	return ur
    47  }
    48  
    49  // ScaleLineSegment segment's size to length flexible in limit
    50  func ScaleLineSegment(segment image.Point, length int, limit image.Point) image.Point {
    51  	var swapped = segment.X > segment.Y
    52  	if swapped { // swap (X,Y) -> (Y,X)
    53  		segment.X, segment.Y = segment.Y, segment.X
    54  		limit.X, limit.Y = limit.Y, limit.X
    55  	}
    56  
    57  	dx := length - (segment.Y - segment.X)
    58  	segment.X -= int(math.Round(float64(dx) / 2.0))
    59  	if segment.X < limit.X {
    60  		segment.X = limit.X
    61  	}
    62  	segment.Y = segment.X + length
    63  	if segment.Y > limit.Y {
    64  		segment.Y = limit.Y
    65  		segment.X = segment.Y - length
    66  		if segment.X < limit.X {
    67  			segment.X = limit.X
    68  		}
    69  	}
    70  
    71  	if swapped {
    72  		segment.X, segment.Y = segment.Y, segment.X
    73  	}
    74  	return segment
    75  }
    76  
    77  // ScaleRectangleBySize scale rect to size flexible in limit
    78  func ScaleRectangleBySize(rect image.Rectangle, size image.Point, limit image.Rectangle) image.Rectangle {
    79  	// padding in x direction
    80  	x := ScaleLineSegment(image.Pt(rect.Min.X, rect.Max.X), size.X, image.Pt(limit.Min.X, limit.Max.X))
    81  	// padding in y direction
    82  	y := ScaleLineSegment(image.Pt(rect.Min.Y, rect.Max.Y), size.Y, image.Pt(limit.Min.Y, limit.Max.Y))
    83  
    84  	return limit.Intersect(image.Rect(x.X, y.X, x.Y, y.Y))
    85  }