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 }