github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/image/geom.go (about)

     1  // Copyright 2010 The Go Authors. 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  	"strconv"
     9  )
    10  
    11  // A Point is an X, Y coordinate pair. The axes increase right and down.
    12  type Point struct {
    13  	X, Y int
    14  }
    15  
    16  // String returns a string representation of p like "(3,4)".
    17  func (p Point) String() string {
    18  	return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
    19  }
    20  
    21  // Add returns the vector p+q.
    22  func (p Point) Add(q Point) Point {
    23  	return Point{p.X + q.X, p.Y + q.Y}
    24  }
    25  
    26  // Sub returns the vector p-q.
    27  func (p Point) Sub(q Point) Point {
    28  	return Point{p.X - q.X, p.Y - q.Y}
    29  }
    30  
    31  // Mul returns the vector p*k.
    32  func (p Point) Mul(k int) Point {
    33  	return Point{p.X * k, p.Y * k}
    34  }
    35  
    36  // Div returns the vector p/k.
    37  func (p Point) Div(k int) Point {
    38  	return Point{p.X / k, p.Y / k}
    39  }
    40  
    41  // In reports whether p is in r.
    42  func (p Point) In(r Rectangle) bool {
    43  	return r.Min.X <= p.X && p.X < r.Max.X &&
    44  		r.Min.Y <= p.Y && p.Y < r.Max.Y
    45  }
    46  
    47  // Mod returns the point q in r such that p.X-q.X is a multiple of r's width
    48  // and p.Y-q.Y is a multiple of r's height.
    49  func (p Point) Mod(r Rectangle) Point {
    50  	w, h := r.Dx(), r.Dy()
    51  	p = p.Sub(r.Min)
    52  	p.X = p.X % w
    53  	if p.X < 0 {
    54  		p.X += w
    55  	}
    56  	p.Y = p.Y % h
    57  	if p.Y < 0 {
    58  		p.Y += h
    59  	}
    60  	return p.Add(r.Min)
    61  }
    62  
    63  // Eq reports whether p and q are equal.
    64  func (p Point) Eq(q Point) bool {
    65  	return p.X == q.X && p.Y == q.Y
    66  }
    67  
    68  // ZP is the zero Point.
    69  var ZP Point
    70  
    71  // Pt is shorthand for Point{X, Y}.
    72  func Pt(X, Y int) Point {
    73  	return Point{X, Y}
    74  }
    75  
    76  // A Rectangle contains the points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
    77  // It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
    78  // well-formed. A rectangle's methods always return well-formed outputs for
    79  // well-formed inputs.
    80  type Rectangle struct {
    81  	Min, Max Point
    82  }
    83  
    84  // String returns a string representation of r like "(3,4)-(6,5)".
    85  func (r Rectangle) String() string {
    86  	return r.Min.String() + "-" + r.Max.String()
    87  }
    88  
    89  // Dx returns r's width.
    90  func (r Rectangle) Dx() int {
    91  	return r.Max.X - r.Min.X
    92  }
    93  
    94  // Dy returns r's height.
    95  func (r Rectangle) Dy() int {
    96  	return r.Max.Y - r.Min.Y
    97  }
    98  
    99  // Size returns r's width and height.
   100  func (r Rectangle) Size() Point {
   101  	return Point{
   102  		r.Max.X - r.Min.X,
   103  		r.Max.Y - r.Min.Y,
   104  	}
   105  }
   106  
   107  // Add returns the rectangle r translated by p.
   108  func (r Rectangle) Add(p Point) Rectangle {
   109  	return Rectangle{
   110  		Point{r.Min.X + p.X, r.Min.Y + p.Y},
   111  		Point{r.Max.X + p.X, r.Max.Y + p.Y},
   112  	}
   113  }
   114  
   115  // Sub returns the rectangle r translated by -p.
   116  func (r Rectangle) Sub(p Point) Rectangle {
   117  	return Rectangle{
   118  		Point{r.Min.X - p.X, r.Min.Y - p.Y},
   119  		Point{r.Max.X - p.X, r.Max.Y - p.Y},
   120  	}
   121  }
   122  
   123  // Inset returns the rectangle r inset by n, which may be negative. If either
   124  // of r's dimensions is less than 2*n then an empty rectangle near the center
   125  // of r will be returned.
   126  func (r Rectangle) Inset(n int) Rectangle {
   127  	if r.Dx() < 2*n {
   128  		r.Min.X = (r.Min.X + r.Max.X) / 2
   129  		r.Max.X = r.Min.X
   130  	} else {
   131  		r.Min.X += n
   132  		r.Max.X -= n
   133  	}
   134  	if r.Dy() < 2*n {
   135  		r.Min.Y = (r.Min.Y + r.Max.Y) / 2
   136  		r.Max.Y = r.Min.Y
   137  	} else {
   138  		r.Min.Y += n
   139  		r.Max.Y -= n
   140  	}
   141  	return r
   142  }
   143  
   144  // Intersect returns the largest rectangle contained by both r and s. If the
   145  // two rectangles do not overlap then the zero rectangle will be returned.
   146  func (r Rectangle) Intersect(s Rectangle) Rectangle {
   147  	if r.Min.X < s.Min.X {
   148  		r.Min.X = s.Min.X
   149  	}
   150  	if r.Min.Y < s.Min.Y {
   151  		r.Min.Y = s.Min.Y
   152  	}
   153  	if r.Max.X > s.Max.X {
   154  		r.Max.X = s.Max.X
   155  	}
   156  	if r.Max.Y > s.Max.Y {
   157  		r.Max.Y = s.Max.Y
   158  	}
   159  	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
   160  		return ZR
   161  	}
   162  	return r
   163  }
   164  
   165  // Union returns the smallest rectangle that contains both r and s.
   166  func (r Rectangle) Union(s Rectangle) Rectangle {
   167  	if r.Min.X > s.Min.X {
   168  		r.Min.X = s.Min.X
   169  	}
   170  	if r.Min.Y > s.Min.Y {
   171  		r.Min.Y = s.Min.Y
   172  	}
   173  	if r.Max.X < s.Max.X {
   174  		r.Max.X = s.Max.X
   175  	}
   176  	if r.Max.Y < s.Max.Y {
   177  		r.Max.Y = s.Max.Y
   178  	}
   179  	return r
   180  }
   181  
   182  // Empty reports whether the rectangle contains no points.
   183  func (r Rectangle) Empty() bool {
   184  	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
   185  }
   186  
   187  // Eq reports whether r and s are equal.
   188  func (r Rectangle) Eq(s Rectangle) bool {
   189  	return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
   190  		r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
   191  }
   192  
   193  // Overlaps reports whether r and s have a non-empty intersection.
   194  func (r Rectangle) Overlaps(s Rectangle) bool {
   195  	return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
   196  		r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
   197  }
   198  
   199  // In reports whether every point in r is in s.
   200  func (r Rectangle) In(s Rectangle) bool {
   201  	if r.Empty() {
   202  		return true
   203  	}
   204  	// Note that r.Max is an exclusive bound for r, so that r.In(s)
   205  	// does not require that r.Max.In(s).
   206  	return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
   207  		s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
   208  }
   209  
   210  // Canon returns the canonical version of r. The returned rectangle has minimum
   211  // and maximum coordinates swapped if necessary so that it is well-formed.
   212  func (r Rectangle) Canon() Rectangle {
   213  	if r.Max.X < r.Min.X {
   214  		r.Min.X, r.Max.X = r.Max.X, r.Min.X
   215  	}
   216  	if r.Max.Y < r.Min.Y {
   217  		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
   218  	}
   219  	return r
   220  }
   221  
   222  // ZR is the zero Rectangle.
   223  var ZR Rectangle
   224  
   225  // Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
   226  func Rect(x0, y0, x1, y1 int) Rectangle {
   227  	if x0 > x1 {
   228  		x0, x1 = x1, x0
   229  	}
   230  	if y0 > y1 {
   231  		y0, y1 = y1, y0
   232  	}
   233  	return Rectangle{Point{x0, y0}, Point{x1, y1}}
   234  }