github.com/searKing/golang/go@v1.2.117/image/rectangle.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  	"image/color"
    10  	"math"
    11  )
    12  
    13  type Rectangle2f struct {
    14  	Min, Max Point2f
    15  }
    16  
    17  // String returns a string representation of r like "(3,4)-(6,5)".
    18  func (r Rectangle2f) String() string {
    19  	return r.Min.String() + "-" + r.Max.String()
    20  }
    21  
    22  // Dx returns r's width.
    23  func (r Rectangle2f) Dx() float32 {
    24  	return r.Max.X - r.Min.X
    25  }
    26  
    27  // Dy returns r's height.
    28  func (r Rectangle2f) Dy() float32 {
    29  	return r.Max.Y - r.Min.Y
    30  }
    31  
    32  // Size returns r's width and height.
    33  func (r Rectangle2f) Size() Point2f {
    34  	return Point2f{
    35  		r.Max.X - r.Min.X,
    36  		r.Max.Y - r.Min.Y,
    37  	}
    38  }
    39  
    40  // Add returns the rectangle r translated by p.
    41  func (r Rectangle2f) Add(p Point2f) Rectangle2f {
    42  	return Rectangle2f{
    43  		Point2f{r.Min.X + p.X, r.Min.Y + p.Y},
    44  		Point2f{r.Max.X + p.X, r.Max.Y + p.Y},
    45  	}
    46  }
    47  
    48  // Sub returns the rectangle r translated by -p.
    49  func (r Rectangle2f) Sub(p Point2f) Rectangle2f {
    50  	return Rectangle2f{
    51  		Point2f{r.Min.X - p.X, r.Min.Y - p.Y},
    52  		Point2f{r.Max.X - p.X, r.Max.Y - p.Y},
    53  	}
    54  }
    55  
    56  // Inset returns the rectangle r inset by n, which may be negative. If either
    57  // of r's dimensions is less than 2*n then an empty rectangle near the center
    58  // of r will be returned.
    59  func (r Rectangle2f) Inset(n float32) Rectangle2f {
    60  	if r.Dx() < 2*n {
    61  		r.Min.X = (r.Min.X + r.Max.X) / 2
    62  		r.Max.X = r.Min.X
    63  	} else {
    64  		r.Min.X += n
    65  		r.Max.X -= n
    66  	}
    67  	if r.Dy() < 2*n {
    68  		r.Min.Y = (r.Min.Y + r.Max.Y) / 2
    69  		r.Max.Y = r.Min.Y
    70  	} else {
    71  		r.Min.Y += n
    72  		r.Max.Y -= n
    73  	}
    74  	return r
    75  }
    76  
    77  // Intersect returns the largest rectangle contained by both r and s. If the
    78  // two rectangles do not overlap then the zero rectangle will be returned.
    79  func (r Rectangle2f) Intersect(s Rectangle2f) Rectangle2f {
    80  	if r.Min.X < s.Min.X {
    81  		r.Min.X = s.Min.X
    82  	}
    83  	if r.Min.Y < s.Min.Y {
    84  		r.Min.Y = s.Min.Y
    85  	}
    86  	if r.Max.X > s.Max.X {
    87  		r.Max.X = s.Max.X
    88  	}
    89  	if r.Max.Y > s.Max.Y {
    90  		r.Max.Y = s.Max.Y
    91  	}
    92  	// Letting r0 and s0 be the values of r and s at the time that the method
    93  	// is called, this next line is equivalent to:
    94  	//
    95  	// if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc }
    96  	if r.Empty() {
    97  		return ZR2f
    98  	}
    99  	return r
   100  }
   101  
   102  // Union returns the smallest rectangle that contains both r and s.
   103  func (r Rectangle2f) Union(s Rectangle2f) Rectangle2f {
   104  	if r.Empty() {
   105  		return s
   106  	}
   107  	if s.Empty() {
   108  		return r
   109  	}
   110  	if r.Min.X > s.Min.X {
   111  		r.Min.X = s.Min.X
   112  	}
   113  	if r.Min.Y > s.Min.Y {
   114  		r.Min.Y = s.Min.Y
   115  	}
   116  	if r.Max.X < s.Max.X {
   117  		r.Max.X = s.Max.X
   118  	}
   119  	if r.Max.Y < s.Max.Y {
   120  		r.Max.Y = s.Max.Y
   121  	}
   122  	return r
   123  }
   124  
   125  // Empty reports whether the rectangle contains no points.
   126  func (r Rectangle2f) Empty() bool {
   127  	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
   128  }
   129  
   130  // Eq reports whether r and s contain the same set of points. All empty
   131  // rectangles are considered equal.
   132  func (r Rectangle2f) Eq(s Rectangle2f) bool {
   133  	return r == s || r.Empty() && s.Empty()
   134  }
   135  
   136  // Overlaps reports whether r and s have a non-empty intersection.
   137  func (r Rectangle2f) Overlaps(s Rectangle2f) bool {
   138  	return !r.Empty() && !s.Empty() &&
   139  		r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
   140  		r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
   141  }
   142  
   143  // In reports whether every point in r is in s.
   144  func (r Rectangle2f) In(s Rectangle2f) bool {
   145  	if r.Empty() {
   146  		return true
   147  	}
   148  	// Note that r.Max is an exclusive bound for r, so that r.In(s)
   149  	// does not require that r.Max.In(s).
   150  	return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
   151  		s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
   152  }
   153  
   154  // Canon returns the canonical version of r. The returned rectangle has minimum
   155  // and maximum coordinates swapped if necessary so that it is well-formed.
   156  func (r Rectangle2f) Canon() Rectangle2f {
   157  	if r.Max.X < r.Min.X {
   158  		r.Min.X, r.Max.X = r.Max.X, r.Min.X
   159  	}
   160  	if r.Max.Y < r.Min.Y {
   161  		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
   162  	}
   163  	return r
   164  }
   165  
   166  // At implements the Image interface.
   167  func (r Rectangle2f) At(x, y float32) color.Color {
   168  	if (Point2f{x, y}).In(r) {
   169  		return color.Opaque
   170  	}
   171  	return color.Transparent
   172  }
   173  
   174  // RGBA64At implements the RGBA64Image interface.
   175  func (r Rectangle2f) RGBA64At(x, y float32) color.RGBA64 {
   176  	if (Point2f{x, y}).In(r) {
   177  		return color.RGBA64{R: 0xffff, G: 0xffff, B: 0xffff, A: 0xffff}
   178  	}
   179  	return color.RGBA64{}
   180  }
   181  
   182  // Bounds implements the Image interface.
   183  func (r Rectangle2f) Bounds() Rectangle2f {
   184  	return r
   185  }
   186  
   187  // ColorModel implements the Image interface.
   188  func (r Rectangle2f) ColorModel() color.Model {
   189  	return color.Alpha16Model
   190  }
   191  
   192  func (r Rectangle2f) RoundRectangle() image.Rectangle {
   193  	return image.Rect(round(r.Min.X), round(r.Min.Y), round(r.Max.X), round(r.Max.Y))
   194  }
   195  
   196  // UnionPoints returns the smallest rectangle that contains all points.
   197  func (r Rectangle2f) UnionPoints(pts ...Point2f) Rectangle2f {
   198  	if len(pts) == 0 {
   199  		return r
   200  	}
   201  	var pos int
   202  	if r.Empty() { // an empty rectangle is a empty set, Not a point
   203  		r.Min = pts[0]
   204  		r.Max = pts[0]
   205  		pos = 1
   206  	}
   207  	for _, p := range pts[pos:] {
   208  		if p.X < r.Min.X {
   209  			r.Min.X = p.X
   210  		}
   211  		if p.Y < r.Min.Y {
   212  			r.Min.Y = p.Y
   213  		}
   214  		if p.X > r.Max.X {
   215  			r.Max.X = p.X
   216  		}
   217  		if p.Y > r.Max.Y {
   218  			r.Max.Y = p.Y
   219  		}
   220  	}
   221  	return r
   222  }
   223  
   224  // ScaleByFactor scale rect to factor*size
   225  func (r Rectangle2f) ScaleByFactor(factor Point2f) Rectangle2f {
   226  	if r.Empty() {
   227  		return r
   228  	}
   229  	factor = factor.Sub(Pt2f(1, 1))
   230  	minOffset := Point2f{
   231  		X: r.Dx() * factor.X / 2,
   232  		Y: r.Dy() * factor.Y / 2,
   233  	}
   234  	maxOffset := Point2f{
   235  		X: r.Dx() * factor.X,
   236  		Y: r.Dy() * factor.Y,
   237  	}.Sub(minOffset)
   238  
   239  	return Rectangle2f{
   240  		Min: Point2f{X: r.Min.X - minOffset.X, Y: r.Min.Y - minOffset.Y},
   241  		Max: Point2f{X: r.Max.X + maxOffset.X, Y: r.Max.Y + maxOffset.Y},
   242  	}
   243  }
   244  
   245  // ZR2f is the zero Rectangle2f.
   246  //
   247  // Deprecated: Use a literal image.Rectangle2f{} instead.
   248  var ZR2f Rectangle2f
   249  
   250  // Rect2f is shorthand for Rectangle2f{Pt(x0, y0), Pt(x1, y1)}. The returned
   251  // rectangle has minimum and maximum coordinates swapped if necessary so that
   252  // it is well-formed.
   253  func Rect2f(x0, y0, x1, y1 float32) Rectangle2f {
   254  	if x0 > x1 {
   255  		x0, x1 = x1, x0
   256  	}
   257  	if y0 > y1 {
   258  		y0, y1 = y1, y0
   259  	}
   260  	return Rectangle2f{Point2f{x0, y0}, Point2f{x1, y1}}
   261  }
   262  
   263  func Rect2fFromRect(rect image.Rectangle) Rectangle2f {
   264  	return Rect2f(float32(rect.Min.X), float32(rect.Min.Y), float32(rect.Max.X), float32(rect.Max.Y))
   265  }
   266  
   267  func round(x float32) int {
   268  	return int(math.Round(float64(x)))
   269  }