package geom import ( "fmt" "opslag.de/schobers/geom/ints" ) // ZeroPt represents the coordinate (0, 0) var ZeroPt = Point{0, 0} // OnePt represents the coordinate (1, 1) var OnePt = Point{1, 1} // North represents the coordinate next to the ZeroPt (Y == -1) var North = Point{0, -1} // East represents the coordinate next to the ZeroPt (X == 1) var East = Point{1, 0} // South represents the coordinate next to the ZeroPt (Y == 1) var South = Point{0, 1} // West represents the coordinate next to the ZeroPt (X == -1) var West = Point{-1, 0} // Point represents a 2-dimensional point. type Point struct { X, Y int } // Pt is a shorthand function to create a point. func Pt(x, y int) Point { return Point{x, y} } // NewPt is a short function to create a point and return a pointer to it. func NewPt(x, y int) *Point { return &Point{x, y} } // Abs returns a point the absolute values of X and Y. func (p Point) Abs() Point { return Pt(ints.Abs(p.X), ints.Abs(p.Y)) } // Add returns the sum of p and q. func (p Point) Add(q Point) Point { return p.Add2D(q.X, q.Y) } // Add2D adds x and y to X and Y of point p and returns the sum. func (p Point) Add2D(x, y int) Point { return Pt(p.X+x, p.Y+y) } // Div divides the X and Y values of point p with t and returns the result. func (p Point) Div(t int) Point { return Pt(p.X/t, p.Y/t) } // DistInt returns the integer distance between the points p and q. func (p Point) DistInt(q Point) int { return ints.SubAbs(p.X, q.X) + ints.SubAbs(p.Y, q.Y) } // In tests if the point p is inside the rectangle r. func (p Point) In(r Rectangle) bool { if p.X < r.Min.X || p.X >= r.Max.X || p.Y < r.Min.Y || p.Y >= r.Max.Y { return false } return true } // Less returns true if q is above (Y is smaller) or left (X is smaller) than p. Otherwise returns false. func (p Point) Less(q Point) bool { if p.Y == q.Y { return p.X < q.X } return p.Y < q.Y } // Mul multiplier the X and Y values of point p with t and returns the result. func (p Point) Mul(t int) Point { return Pt(p.X*t, p.Y*t) } // Norm returns the point with both X and Y normalized. func (p Point) Norm() Point { return Pt(ints.Norm(p.X), ints.Norm(p.Y)) } // Rect returns a rectangle starting from point p to given point q func (p Point) Rect(q Point) Rectangle { return Rectangle{Min: p, Max: q} } // Rect2D returns a rectangle starting from point p to given coordinate (x, y) func (p Point) Rect2D(x, y int) Rectangle { return Rectangle{Min: p, Max: Pt(x, y)} } // RectRel returns a rectangle starting from point p with the given size. func (p Point) RectRel(size Point) Rectangle { return RectRel(p.X, p.Y, size.X, size.Y) } // RectRel2D returns a rectangle starting from point p with the given width and height func (p Point) RectRel2D(width, height int) Rectangle { return RectRel(p.X, p.Y, width, height) } // String returns a string representation of point p "X, Y". func (p Point) String() string { return fmt.Sprintf("%d, %d", p.X, p.Y) } // StringBrackets formats the point p as a string "(X, Y)". func (p Point) StringBrackets() string { return fmt.Sprintf("(%d, %d)", p.X, p.Y) } // StringCompact returns a compact string representation of point p "X,Y". func (p Point) StringCompact() string { return fmt.Sprintf("%d,%d", p.X, p.Y) } // Sub returns the difference of p and q. func (p Point) Sub(p2 Point) Point { return Pt(p.X-p2.X, p.Y-p2.Y) } // ToF returns the floating point representation of p. func (p Point) ToF() PointF { return PtF(float64(p.X), float64(p.Y)) } // ToF32 returns the floating point representation of p. func (p Point) ToF32() PointF32 { return PtF32(float32(p.X), float32(p.Y)) } // XY returns the X and Y component of the coordinate. func (p Point) XY() (int, int) { return p.X, p.Y } // MaxPt returns the point that is at the largest X & Y position of a and b. func MaxPt(a, b Point) Point { return Pt(ints.Max(a.X, b.X), ints.Max(a.Y, b.Y)) } // MinMaxPoints returns the extremes of all the given points. func MinMaxPoints(p ...Point) (min Point, max Point) { if 0 == len(p) { return Point{}, Point{} } min, max = p[0], p[0] for i := 1; i < len(p); i++ { var pt = p[i] if pt.X < min.X { min.X = pt.X } else if pt.X > max.X { max.X = pt.X } if pt.Y < min.Y { min.Y = pt.Y } else if pt.Y > max.Y { max.Y = pt.Y } } return min, max } // MinPt returns the point that is at the smallest X & Y position of a and b. func MinPt(a, b Point) Point { return Pt(ints.Min(a.X, b.X), ints.Min(a.Y, b.Y)) }