github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/f32/f32.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  /*
     4  Package f32 is a float32 implementation of package image's
     5  Point and Rectangle.
     6  
     7  The coordinate space has the origin in the top left
     8  corner with the axes extending right and down.
     9  */
    10  package f32
    11  
    12  import "strconv"
    13  
    14  // A Point is a two dimensional point.
    15  type Point struct {
    16  	X, Y float32
    17  }
    18  
    19  // String return a string representation of p.
    20  func (p Point) String() string {
    21  	return "(" + strconv.FormatFloat(float64(p.X), 'f', -1, 32) +
    22  		"," + strconv.FormatFloat(float64(p.Y), 'f', -1, 32) + ")"
    23  }
    24  
    25  // A Rectangle contains the points (X, Y) where Min.X <= X < Max.X,
    26  // Min.Y <= Y < Max.Y.
    27  type Rectangle struct {
    28  	Min, Max Point
    29  }
    30  
    31  // String return a string representation of r.
    32  func (r Rectangle) String() string {
    33  	return r.Min.String() + "-" + r.Max.String()
    34  }
    35  
    36  // Rect is a shorthand for Rectangle{Point{x0, y0}, Point{x1, y1}}.
    37  // The returned Rectangle has x0 and y0 swapped if necessary so that
    38  // it's correctly formed.
    39  func Rect(x0, y0, x1, y1 float32) Rectangle {
    40  	if x0 > x1 {
    41  		x0, x1 = x1, x0
    42  	}
    43  	if y0 > y1 {
    44  		y0, y1 = y1, y0
    45  	}
    46  	return Rectangle{Point{x0, y0}, Point{x1, y1}}
    47  }
    48  
    49  // Pt is shorthand for Point{X: x, Y: y}.
    50  func Pt(x, y float32) Point {
    51  	return Point{X: x, Y: y}
    52  }
    53  
    54  // Add return the point p+p2.
    55  func (p Point) Add(p2 Point) Point {
    56  	return Point{X: p.X + p2.X, Y: p.Y + p2.Y}
    57  }
    58  
    59  // Sub returns the vector p-p2.
    60  func (p Point) Sub(p2 Point) Point {
    61  	return Point{X: p.X - p2.X, Y: p.Y - p2.Y}
    62  }
    63  
    64  // Mul returns p scaled by s.
    65  func (p Point) Mul(s float32) Point {
    66  	return Point{X: p.X * s, Y: p.Y * s}
    67  }
    68  
    69  // In reports whether p is in r.
    70  func (p Point) In(r Rectangle) bool {
    71  	return r.Min.X <= p.X && p.X < r.Max.X &&
    72  		r.Min.Y <= p.Y && p.Y < r.Max.Y
    73  }
    74  
    75  // Size returns r's width and height.
    76  func (r Rectangle) Size() Point {
    77  	return Point{X: r.Dx(), Y: r.Dy()}
    78  }
    79  
    80  // Dx returns r's width.
    81  func (r Rectangle) Dx() float32 {
    82  	return r.Max.X - r.Min.X
    83  }
    84  
    85  // Dy returns r's Height.
    86  func (r Rectangle) Dy() float32 {
    87  	return r.Max.Y - r.Min.Y
    88  }
    89  
    90  // Intersect returns the intersection of r and s.
    91  func (r Rectangle) Intersect(s Rectangle) Rectangle {
    92  	if r.Min.X < s.Min.X {
    93  		r.Min.X = s.Min.X
    94  	}
    95  	if r.Min.Y < s.Min.Y {
    96  		r.Min.Y = s.Min.Y
    97  	}
    98  	if r.Max.X > s.Max.X {
    99  		r.Max.X = s.Max.X
   100  	}
   101  	if r.Max.Y > s.Max.Y {
   102  		r.Max.Y = s.Max.Y
   103  	}
   104  	if r.Empty() {
   105  		return Rectangle{}
   106  	}
   107  	return r
   108  }
   109  
   110  // Union returns the union of r and s.
   111  func (r Rectangle) Union(s Rectangle) Rectangle {
   112  	if r.Empty() {
   113  		return s
   114  	}
   115  	if s.Empty() {
   116  		return r
   117  	}
   118  	if r.Min.X > s.Min.X {
   119  		r.Min.X = s.Min.X
   120  	}
   121  	if r.Min.Y > s.Min.Y {
   122  		r.Min.Y = s.Min.Y
   123  	}
   124  	if r.Max.X < s.Max.X {
   125  		r.Max.X = s.Max.X
   126  	}
   127  	if r.Max.Y < s.Max.Y {
   128  		r.Max.Y = s.Max.Y
   129  	}
   130  	return r
   131  }
   132  
   133  // Canon returns the canonical version of r, where Min is to
   134  // the upper left of Max.
   135  func (r Rectangle) Canon() Rectangle {
   136  	if r.Max.X < r.Min.X {
   137  		r.Min.X, r.Max.X = r.Max.X, r.Min.X
   138  	}
   139  	if r.Max.Y < r.Min.Y {
   140  		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
   141  	}
   142  	return r
   143  }
   144  
   145  // Empty reports whether r represents the empty area.
   146  func (r Rectangle) Empty() bool {
   147  	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
   148  }
   149  
   150  // Add offsets r with the vector p.
   151  func (r Rectangle) Add(p Point) Rectangle {
   152  	return Rectangle{
   153  		Point{r.Min.X + p.X, r.Min.Y + p.Y},
   154  		Point{r.Max.X + p.X, r.Max.Y + p.Y},
   155  	}
   156  }
   157  
   158  // Sub offsets r with the vector -p.
   159  func (r Rectangle) Sub(p Point) Rectangle {
   160  	return Rectangle{
   161  		Point{r.Min.X - p.X, r.Min.Y - p.Y},
   162  		Point{r.Max.X - p.X, r.Max.Y - p.Y},
   163  	}
   164  }