mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-09 10:06:35 -05:00
adding a full-featured rectangle implementation to d2geom, adding an ecs component for it
This commit is contained in:
parent
0472233949
commit
7a8b07d1c1
6
d2common/d2geom/rectangle/area.go
Normal file
6
d2common/d2geom/rectangle/area.go
Normal file
@ -0,0 +1,6 @@
|
||||
package rectangle
|
||||
|
||||
// Area calculates the area of the given rectangle.
|
||||
func Area(r *Rectangle) float64 {
|
||||
return r.Width * r.Height
|
||||
}
|
12
d2common/d2geom/rectangle/ceil.go
Normal file
12
d2common/d2geom/rectangle/ceil.go
Normal file
@ -0,0 +1,12 @@
|
||||
package rectangle
|
||||
|
||||
import "math"
|
||||
|
||||
// Ceil rounds a Rectangle's position up to the smallest integer greater than or equal to each
|
||||
// current coordinate.
|
||||
func Ceil(r *Rectangle) *Rectangle {
|
||||
r.X = math.Ceil(r.X)
|
||||
r.Y = math.Ceil(r.Y)
|
||||
|
||||
return r
|
||||
}
|
14
d2common/d2geom/rectangle/ceil_all.go
Normal file
14
d2common/d2geom/rectangle/ceil_all.go
Normal file
@ -0,0 +1,14 @@
|
||||
package rectangle
|
||||
|
||||
import "math"
|
||||
|
||||
// CeilAll rounds a Rectangle's position and size up to the smallest
|
||||
// integer greater than or equal to each respective value.
|
||||
func CeilAll(r *Rectangle) *Rectangle {
|
||||
r.X = math.Ceil(r.X)
|
||||
r.Y = math.Ceil(r.Y)
|
||||
r.Width = math.Ceil(r.Width)
|
||||
r.Height = math.Ceil(r.Height)
|
||||
|
||||
return r
|
||||
}
|
6
d2common/d2geom/rectangle/center_on.go
Normal file
6
d2common/d2geom/rectangle/center_on.go
Normal file
@ -0,0 +1,6 @@
|
||||
package rectangle
|
||||
|
||||
// CenterOn moves the top-left corner of a Rectangle so that its center is at the given coordinates.
|
||||
func CenterOn(r *Rectangle, x, y float64) *Rectangle {
|
||||
return r.SetCenterX(x).SetCenterY(y)
|
||||
}
|
10
d2common/d2geom/rectangle/contains.go
Normal file
10
d2common/d2geom/rectangle/contains.go
Normal file
@ -0,0 +1,10 @@
|
||||
package rectangle
|
||||
|
||||
// Contains checks if the given x, y is inside the Rectangle's bounds.
|
||||
func Contains(r *Rectangle, x, y float64) bool {
|
||||
if r.Width <= 0 || r.Height <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return r.X <= x && r.X+r.Width >= x && r.Y <= y && r.Y+r.Height >= y
|
||||
}
|
13
d2common/d2geom/rectangle/contains_rectangle.go
Normal file
13
d2common/d2geom/rectangle/contains_rectangle.go
Normal file
@ -0,0 +1,13 @@
|
||||
package rectangle
|
||||
|
||||
// ContainsRectangle checks if one rectangle fully contains another.
|
||||
func ContainsRectangle(a, b *Rectangle) bool {
|
||||
if b.Area() > a.Area() {
|
||||
return false
|
||||
}
|
||||
|
||||
return (b.X > a.X && b.X < a.Right()) &&
|
||||
(b.Right() > a.X && b.Right() < a.Right()) &&
|
||||
(b.Y > a.Y && b.Y < a.Bottom()) &&
|
||||
(b.Bottom() > a.Y && b.Bottom() < a.Bottom())
|
||||
}
|
6
d2common/d2geom/rectangle/copy_from.go
Normal file
6
d2common/d2geom/rectangle/copy_from.go
Normal file
@ -0,0 +1,6 @@
|
||||
package rectangle
|
||||
|
||||
// CopyFrom copies the values of one Rectangle to a destination Rectangle.
|
||||
func CopyFrom(source, dest *Rectangle) *Rectangle {
|
||||
return dest.SetTo(source.X, source.Y, source.Width, source.Height)
|
||||
}
|
19
d2common/d2geom/rectangle/deconstruct.go
Normal file
19
d2common/d2geom/rectangle/deconstruct.go
Normal file
@ -0,0 +1,19 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/geom/point"
|
||||
|
||||
// Deconstruct creates a slice of points for each corner of a Rectangle.
|
||||
// If a slice is specified, each point object will be added to the end of the slice,
|
||||
// otherwise a new slice will be created.
|
||||
func Deconstruct(r *Rectangle, to []*point.Point) []*point.Point {
|
||||
if to == nil {
|
||||
to = make([]*point.Point, 0)
|
||||
}
|
||||
|
||||
to = append(to, point.New(r.X, r.Y))
|
||||
to = append(to, point.New(r.Right(), r.Y))
|
||||
to = append(to, point.New(r.Right(), r.Bottom()))
|
||||
to = append(to, point.New(r.X, r.Bottom()))
|
||||
|
||||
return to
|
||||
}
|
16
d2common/d2geom/rectangle/equals.go
Normal file
16
d2common/d2geom/rectangle/equals.go
Normal file
@ -0,0 +1,16 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/phomath"
|
||||
|
||||
// Equals compares the `x`, `y`, `width` and `height` properties of two rectangles.
|
||||
func Equals(a, b *Rectangle) bool {
|
||||
dx := (a.X - b.X) * (a.X - b.X)
|
||||
dy := (a.Y - b.Y) * (a.Y - b.Y)
|
||||
dw := (a.Width - b.Width) * (a.Width - b.Width)
|
||||
dh := (a.Height - b.Height) * (a.Height - b.Height)
|
||||
|
||||
return dx < phomath.Epsilon &&
|
||||
dy < phomath.Epsilon &&
|
||||
dw < phomath.Epsilon &&
|
||||
dh < phomath.Epsilon
|
||||
}
|
17
d2common/d2geom/rectangle/fit_inside.go
Normal file
17
d2common/d2geom/rectangle/fit_inside.go
Normal file
@ -0,0 +1,17 @@
|
||||
package rectangle
|
||||
|
||||
// Adjusts rectangle `a`, changing its width, height and position,
|
||||
// so that it fits inside the area of rectangle `b`, while maintaining its original
|
||||
// aspect ratio.
|
||||
func FitInside(a, b *Rectangle) *Rectangle {
|
||||
aRatio := GetAspectRatio(a)
|
||||
bRatio := GetAspectRatio(b)
|
||||
|
||||
if aRatio < bRatio {
|
||||
a.SetSize(b.Height*aRatio, b.Height)
|
||||
} else {
|
||||
a.SetSize(b.Width, b.Width/aRatio)
|
||||
}
|
||||
|
||||
return a.CenterOn(b.CenterX(), b.CenterY())
|
||||
}
|
16
d2common/d2geom/rectangle/get_aspect_ratio.go
Normal file
16
d2common/d2geom/rectangle/get_aspect_ratio.go
Normal file
@ -0,0 +1,16 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gravestench/pho/phomath"
|
||||
)
|
||||
|
||||
// GetAspectRatio returns the aspect ratio (width/height) of the given rectangle
|
||||
func GetAspectRatio(r *Rectangle) float64 {
|
||||
if r.Height < phomath.Epsilon {
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
return r.Width / r.Height
|
||||
}
|
8
d2common/d2geom/rectangle/get_center.go
Normal file
8
d2common/d2geom/rectangle/get_center.go
Normal file
@ -0,0 +1,8 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/geom/point"
|
||||
|
||||
// GetCenter returns the center of the Rectangle as a Point.
|
||||
func GetCenter(r *Rectangle) *point.Point {
|
||||
return point.New(r.CenterX(), r.CenterY())
|
||||
}
|
38
d2common/d2geom/rectangle/get_point.go
Normal file
38
d2common/d2geom/rectangle/get_point.go
Normal file
@ -0,0 +1,38 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/geom/point"
|
||||
|
||||
// GetPoint calculates the coordinates of a point at a certain `position` on the
|
||||
// Rectangle's perimeter, assigns to and returns the given point, or creates a point if nil.
|
||||
func GetPoint(r *Rectangle, position float64, p *point.Point) *point.Point {
|
||||
if p == nil {
|
||||
p = point.New(0, 0)
|
||||
}
|
||||
|
||||
if position <= 0 || position >= 1 {
|
||||
p.X, p.Y = r.X, r.Y
|
||||
return p
|
||||
}
|
||||
|
||||
perimeter := Perimeter(r) * position
|
||||
|
||||
if position > 0.5 {
|
||||
perimeter -= r.Width + r.Height
|
||||
|
||||
if perimeter <= r.Width {
|
||||
// face 3
|
||||
p.X, p.Y = r.Right()-perimeter, r.Bottom()
|
||||
} else {
|
||||
// face 4
|
||||
p.X, p.Y = r.X, r.Bottom()-(perimeter-r.Width)
|
||||
}
|
||||
} else if position <= r.Width {
|
||||
// face 1
|
||||
p.X, p.Y = r.X+perimeter, r.Y
|
||||
} else {
|
||||
// face 2
|
||||
p.X, p.Y = r.Right(), r.Y+(perimeter-r.Width)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
31
d2common/d2geom/rectangle/get_points.go
Normal file
31
d2common/d2geom/rectangle/get_points.go
Normal file
@ -0,0 +1,31 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
)
|
||||
|
||||
const ByStepRate = -1
|
||||
|
||||
// GetPoints returns a slice of points from the perimeter of the Rectangle,
|
||||
// each spaced out based on the quantity or step required.
|
||||
func GetPoints(r *Rectangle, quantity int, stepRate float64, points []*point.Point) []*point.Point {
|
||||
if quantity == ByStepRate {
|
||||
quantity = int(Perimeter(r) / stepRate)
|
||||
}
|
||||
|
||||
if points == nil {
|
||||
points = make([]*point.Point, 0)
|
||||
}
|
||||
|
||||
for len(points) < quantity {
|
||||
points = append(points, nil)
|
||||
}
|
||||
|
||||
for idx := 0; idx < quantity; idx++ {
|
||||
position := float64(idx) / float64(quantity)
|
||||
|
||||
points[idx] = GetPoint(r, position, nil)
|
||||
}
|
||||
|
||||
return points
|
||||
}
|
19
d2common/d2geom/rectangle/get_random_point.go
Normal file
19
d2common/d2geom/rectangle/get_random_point.go
Normal file
@ -0,0 +1,19 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
)
|
||||
|
||||
// GetRandomPoint returns a random point within the Rectangle's bounds.
|
||||
func GetRandomPoint(r *Rectangle, p *point.Point) *point.Point {
|
||||
if p == nil {
|
||||
p = point.New(0, 0)
|
||||
}
|
||||
|
||||
p.X = r.X + (rand.Float64() * r.Width)
|
||||
p.Y = r.Y + (rand.Float64() * r.Height)
|
||||
|
||||
return p
|
||||
}
|
44
d2common/d2geom/rectangle/get_random_point_outside.go
Normal file
44
d2common/d2geom/rectangle/get_random_point_outside.go
Normal file
@ -0,0 +1,44 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
"github.com/gravestench/pho/phomath"
|
||||
)
|
||||
|
||||
// Calculates a random point that lies within the `outer` Rectangle, but outside of the `inner`
|
||||
// Rectangle. The inner Rectangle must be fully contained within the outer rectangle.
|
||||
func GetRandomPointOutside(outer, inner *Rectangle, out *point.Point) *point.Point {
|
||||
if out == nil {
|
||||
out = point.New(0, 0)
|
||||
}
|
||||
|
||||
if !ContainsRectangle(outer, inner) {
|
||||
return out
|
||||
}
|
||||
|
||||
const (
|
||||
top = iota
|
||||
right
|
||||
bottom
|
||||
left
|
||||
)
|
||||
|
||||
switch phomath.Between(top, left) {
|
||||
case top:
|
||||
out.X = outer.X + (rand.Float64() * (inner.Right() - outer.X))
|
||||
out.Y = outer.Y + (rand.Float64() * (inner.Top() - outer.Y))
|
||||
case right:
|
||||
out.X = inner.X + (rand.Float64() * (outer.Right() - inner.X))
|
||||
out.Y = inner.Y + (rand.Float64() * (outer.Bottom() - inner.Bottom()))
|
||||
case bottom:
|
||||
out.X = outer.X + (rand.Float64() * (inner.X - outer.X))
|
||||
out.Y = inner.Y + (rand.Float64() * (outer.Bottom() - inner.Y))
|
||||
case left:
|
||||
out.X = inner.Right() + (rand.Float64() * (outer.Right() - inner.Right()))
|
||||
out.Y = outer.Y + (rand.Float64() * (inner.Bottom() - outer.Y))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
9
d2common/d2geom/rectangle/get_rectangle_from_points.go
Normal file
9
d2common/d2geom/rectangle/get_rectangle_from_points.go
Normal file
@ -0,0 +1,9 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/geom/point"
|
||||
|
||||
// GetRectangleFromPoints calculates the Axis Aligned Bounding Box ( or aabb) from an array of
|
||||
// points.
|
||||
func GetRectangleFromPoints(points []*point.Point) *Rectangle {
|
||||
return New(0, 0, 0, 0).MergePoints(points)
|
||||
}
|
9
d2common/d2geom/rectangle/get_size.go
Normal file
9
d2common/d2geom/rectangle/get_size.go
Normal file
@ -0,0 +1,9 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/geom/point"
|
||||
|
||||
// GetSize returns the size of the Rectangle, expressed as a Point object.
|
||||
// With the value of the `width` as the `x` property and the `height` as the `y` property.
|
||||
func GetSize(r *Rectangle) *point.Point {
|
||||
return point.New(r.Width, r.Height)
|
||||
}
|
11
d2common/d2geom/rectangle/inflate.go
Normal file
11
d2common/d2geom/rectangle/inflate.go
Normal file
@ -0,0 +1,11 @@
|
||||
package rectangle
|
||||
|
||||
// Inflate increases the size of a Rectangle by a specified amount.
|
||||
// The center of the Rectangle stays the same. The amounts are added to each side,
|
||||
// so the actual increase in width or height is two times bigger than the respective argument.
|
||||
func Inflate(r *Rectangle, x, y float64) *Rectangle {
|
||||
cx, cy := r.CenterX(), r.CenterY()
|
||||
r.Width, r.Height = r.Width+(2*x), r.Height+(2*y)
|
||||
|
||||
return r.CenterOn(cx, cy)
|
||||
}
|
29
d2common/d2geom/rectangle/intersection.go
Normal file
29
d2common/d2geom/rectangle/intersection.go
Normal file
@ -0,0 +1,29 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gravestench/pho/geom/intersects"
|
||||
)
|
||||
|
||||
// Takes two Rectangles and first checks to see if they intersect.
|
||||
// If they intersect it will return the area of intersection in the `out` Rectangle.
|
||||
// If they do not intersect, the `out` Rectangle will have a width and height of zero.
|
||||
// The given `output` rectangle will be assigned the intsersect values and returned.
|
||||
// A new rectangle will be created if it is nil.
|
||||
func Intersection(a, b, output *Rectangle) *Rectangle {
|
||||
if output == nil {
|
||||
output = New(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
if intersects.RectangleToRectangle(a, b) {
|
||||
output.X = math.Max(a.X, b.X)
|
||||
output.Y = math.Max(a.Y, b.Y)
|
||||
output.Width = math.Min(a.Right(), b.Right()) - output.X
|
||||
output.Height = math.Min(a.Bottom(), b.Bottom()) - output.Y
|
||||
} else {
|
||||
output.SetEmpty()
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
89
d2common/d2geom/rectangle/marching_ants.go
Normal file
89
d2common/d2geom/rectangle/marching_ants.go
Normal file
@ -0,0 +1,89 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
)
|
||||
|
||||
const (
|
||||
AutoStep = -1
|
||||
AutoQuantity = -1
|
||||
)
|
||||
|
||||
// Returns an array of points from the perimeter of the Rectangle,
|
||||
// where each point is spaced out based on either the `step` value, or the `quantity`.
|
||||
func MarchingAnts(r *Rectangle, step float64, quantity int, out []*point.Point) []*point.Point {
|
||||
if step <= 0 {
|
||||
step = AutoStep
|
||||
}
|
||||
|
||||
if quantity <= 0 {
|
||||
quantity = AutoQuantity
|
||||
}
|
||||
|
||||
if out == nil {
|
||||
out = make([]*point.Point, quantity)
|
||||
}
|
||||
|
||||
if step == AutoStep && quantity == AutoQuantity {
|
||||
return /* bail */ out
|
||||
}
|
||||
|
||||
if step == AutoStep {
|
||||
step = Perimeter(r) / float64(quantity)
|
||||
} else {
|
||||
quantity = int(math.Round(Perimeter(r) / step))
|
||||
}
|
||||
|
||||
const (
|
||||
top = iota
|
||||
right
|
||||
bottom
|
||||
left
|
||||
numFaces
|
||||
)
|
||||
|
||||
x, y := r.X, r.Y
|
||||
face := top
|
||||
|
||||
for idx := 0; idx < quantity; idx++ {
|
||||
out = append(out, point.New(x, y))
|
||||
|
||||
switch face {
|
||||
case top:
|
||||
x += step
|
||||
|
||||
if x >= r.Right() {
|
||||
face = (face + 1) % numFaces
|
||||
y += x - r.Right()
|
||||
x = r.Right()
|
||||
}
|
||||
case right:
|
||||
y += step
|
||||
|
||||
if y >= r.Bottom() {
|
||||
face = (face + 1) % numFaces
|
||||
x -= y - r.Bottom()
|
||||
y = r.Bottom()
|
||||
}
|
||||
case bottom:
|
||||
x -= step
|
||||
|
||||
if x <= r.Left() {
|
||||
face = (face + 1) % numFaces
|
||||
y -= r.Left() - x
|
||||
x = r.Left()
|
||||
}
|
||||
case left:
|
||||
y -= step
|
||||
|
||||
if y <= r.Top() {
|
||||
face = (face + 1) % numFaces
|
||||
y = r.Top()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
23
d2common/d2geom/rectangle/merge_points.go
Normal file
23
d2common/d2geom/rectangle/merge_points.go
Normal file
@ -0,0 +1,23 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
)
|
||||
|
||||
// Merges a Rectangle with a list of points by repositioning and/or resizing
|
||||
// it such that all points are located on or within its bounds.
|
||||
func MergePoints(r *Rectangle, points []*point.Point) *Rectangle {
|
||||
minX, maxX, minY, maxY := r.X, r.Right(), r.Y, r.Bottom()
|
||||
|
||||
for idx := range points {
|
||||
minX, maxX = math.Min(minX, points[idx].X), math.Max(maxX, points[idx].X)
|
||||
minY, maxY = math.Min(minY, points[idx].Y), math.Max(maxY, points[idx].Y)
|
||||
}
|
||||
|
||||
r.X, r.Y = minX, minY
|
||||
r.Width, r.Height = maxX-minX, maxY-minY
|
||||
|
||||
return r
|
||||
}
|
7
d2common/d2geom/rectangle/merge_rectangle.go
Normal file
7
d2common/d2geom/rectangle/merge_rectangle.go
Normal file
@ -0,0 +1,7 @@
|
||||
package rectangle
|
||||
|
||||
// MergeRectangle merges the source rectangle into the target rectangle and returns the target.
|
||||
// Neither rectangle should have a negative width or height.
|
||||
func MergeRectangle(target, source *Rectangle) *Rectangle {
|
||||
return MergePoints(target, source.Deconstruct(nil))
|
||||
}
|
9
d2common/d2geom/rectangle/merge_xy.go
Normal file
9
d2common/d2geom/rectangle/merge_xy.go
Normal file
@ -0,0 +1,9 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/geom/point"
|
||||
|
||||
// MergeXY merges a Rectangle with a point by repositioning and/or resizing it
|
||||
// so that the point is on or within its bounds.
|
||||
func MergeXY(r *Rectangle, x, y float64) *Rectangle {
|
||||
return r.MergePoints([]*point.Point{point.New(x, y)})
|
||||
}
|
184
d2common/d2geom/rectangle/namespace.go
Normal file
184
d2common/d2geom/rectangle/namespace.go
Normal file
@ -0,0 +1,184 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
)
|
||||
|
||||
type RectangleNamespace interface {
|
||||
Contains(r *Rectangle, x, y float64) bool
|
||||
GetPoint(r *Rectangle, position float64, p *point.Point) *point.Point
|
||||
GetPoints(r *Rectangle, quantity int, stepRate float64, points []*point.Point) []*point.Point
|
||||
GetRandomPoint(r *Rectangle, p *point.Point) *point.Point
|
||||
ContainsPoint(r *Rectangle, p *point.Point) bool
|
||||
ContainsRectangle(r *Rectangle, other *Rectangle) bool
|
||||
Deconstruct(r *Rectangle, to []*point.Point) []*point.Point
|
||||
Equals(r *Rectangle, other *Rectangle) bool
|
||||
FitInside(r *Rectangle, other *Rectangle) *Rectangle
|
||||
Inflate(r *Rectangle, x, y float64) *Rectangle
|
||||
Intersection(r *Rectangle, other, intersect *Rectangle) *Rectangle
|
||||
MergePoints(r *Rectangle, points []*point.Point) *Rectangle
|
||||
MergeRectangle(r *Rectangle, other *Rectangle) *Rectangle
|
||||
MergeXY(r *Rectangle, x, y float64) *Rectangle
|
||||
Offset(r *Rectangle, x, y float64) *Rectangle
|
||||
OffsetPoint(r *Rectangle, p *point.Point) *Rectangle
|
||||
Overlaps(r *Rectangle, other *Rectangle) bool
|
||||
PerimeterPoint(r *Rectangle, angle float64, p *point.Point) *point.Point
|
||||
GetRandomPointOutside(r *Rectangle, other *Rectangle, out *point.Point) *point.Point
|
||||
SameDimensions(r *Rectangle, other *Rectangle) bool
|
||||
Scale(r *Rectangle, x, y float64) *Rectangle
|
||||
Union(r *Rectangle, other *Rectangle) *Rectangle
|
||||
}
|
||||
|
||||
type Namespace struct{}
|
||||
|
||||
// Contains checks if the given x, y is inside the Rectangle's bounds.
|
||||
func (*Namespace) Contains(r *Rectangle, x, y float64) bool {
|
||||
return Contains(r, x, y)
|
||||
}
|
||||
|
||||
// GetPoint calculates the coordinates of a point at a certain `position` on the
|
||||
// Rectangle's perimeter, assigns to and returns the given point, or creates a point if nil.
|
||||
func (*Namespace) GetPoint(r *Rectangle, position float64, p *point.Point) *point.Point {
|
||||
return GetPoint(r, position, p)
|
||||
}
|
||||
|
||||
// GetPoints returns a slice of points from the perimeter of the Rectangle,
|
||||
// each spaced out based on the quantity or step required.
|
||||
func (*Namespace) GetPoints(r *Rectangle, quantity int, stepRate float64,
|
||||
points []*point.Point) []*point.Point {
|
||||
return GetPoints(r, quantity, stepRate, points)
|
||||
}
|
||||
|
||||
// GetRandomPoint returns a random point within the Rectangle's bounds.
|
||||
func (*Namespace) GetRandomPoint(r *Rectangle, p *point.Point) *point.Point {
|
||||
return GetRandomPoint(r, p)
|
||||
}
|
||||
|
||||
// Ceil rounds a Rectangle's position up to the smallest integer greater than or equal to each
|
||||
// current coordinate.
|
||||
func (*Namespace) Ceil(r *Rectangle) *Rectangle {
|
||||
return Ceil(r)
|
||||
}
|
||||
|
||||
// CeilAll rounds a Rectangle's position and size up to the smallest
|
||||
// integer greater than or equal to each respective value.
|
||||
func (*Namespace) CeilAll(r *Rectangle) *Rectangle {
|
||||
return CeilAll(r)
|
||||
}
|
||||
|
||||
// ContainsPoint checks if a given point is inside a Rectangle's bounds.
|
||||
func (*Namespace) ContainsPoint(r *Rectangle, p *point.Point) bool {
|
||||
return Contains(r, p.X, p.Y)
|
||||
}
|
||||
|
||||
// ContainsRect checks if a given point is inside a Rectangle's bounds.
|
||||
func (*Namespace) ContainsRectangle(r, other *Rectangle) bool {
|
||||
return ContainsRectangle(r, other)
|
||||
}
|
||||
|
||||
// CopyFrom copies the values of the given rectangle.
|
||||
func (*Namespace) CopyFrom(target, source *Rectangle) *Rectangle {
|
||||
return CopyFrom(source, target)
|
||||
}
|
||||
|
||||
// Deconstruct creates a slice of points for each corner of a Rectangle.
|
||||
// If a slice is specified, each point object will be added to the end of the slice,
|
||||
// otherwise a new slice will be created.
|
||||
func (*Namespace) Deconstruct(r *Rectangle, to []*point.Point) []*point.Point {
|
||||
return Deconstruct(r, to)
|
||||
}
|
||||
|
||||
// Equals compares the `x`, `y`, `width` and `height` properties of two rectangles.
|
||||
func (*Namespace) Equals(a, b *Rectangle) bool {
|
||||
return Equals(a, b)
|
||||
}
|
||||
|
||||
// Adjusts rectangle, changing its width, height and position,
|
||||
// so that it fits inside the area of the source rectangle, while maintaining its original
|
||||
// aspect ratio.
|
||||
func (*Namespace) FitInside(inner, outer *Rectangle) *Rectangle {
|
||||
return FitInside(inner, outer)
|
||||
}
|
||||
|
||||
func (*Namespace) Inflate(r *Rectangle, x, y float64) *Rectangle {
|
||||
return Inflate(r, x, y)
|
||||
}
|
||||
|
||||
// Takes two Rectangles and first checks to see if they intersect.
|
||||
// If they intersect it will return the area of intersection in the `out` Rectangle.
|
||||
// If they do not intersect, the `out` Rectangle will have a width and height of zero.
|
||||
// The given `intersect` rectangle will be assigned the intsersect values and returned.
|
||||
// A new rectangle will be created if `intersect` is nil.
|
||||
func (*Namespace) Intersection(r, other, intersect *Rectangle) *Rectangle {
|
||||
return Intersection(r, other, intersect)
|
||||
}
|
||||
|
||||
// MergePoints adjusts this rectangle using a list of points by repositioning and/or resizing
|
||||
// it such that all points are located on or within its bounds.
|
||||
func (*Namespace) MergePoints(r *Rectangle, points []*point.Point) *Rectangle {
|
||||
return MergePoints(r, points)
|
||||
}
|
||||
|
||||
// MergeRectangle merges the given rectangle into this rectangle and returns this rectangle.
|
||||
// Neither rectangle should have a negative width or height.
|
||||
func (*Namespace) MergeRectangle(r *Rectangle, other *Rectangle) *Rectangle {
|
||||
return MergeRectangle(r, other)
|
||||
}
|
||||
|
||||
// MergeXY merges this rectangle with a point by repositioning and/or resizing it so that the
|
||||
// point is/on or/within its bounds.
|
||||
func (*Namespace) MergeXY(r *Rectangle, x, y float64) *Rectangle {
|
||||
return MergeXY(r, x, y)
|
||||
}
|
||||
|
||||
// Offset nudges (translates) the top left corner of this Rectangle by a given offset.
|
||||
func (*Namespace) Offset(r *Rectangle, x, y float64) *Rectangle {
|
||||
return Offset(r, x, y)
|
||||
}
|
||||
|
||||
// OffsetPoint nudges (translates) the top left corner of this Rectangle by the coordinates of a
|
||||
// point.
|
||||
func (*Namespace) OffsetPoint(r *Rectangle, p *point.Point) *Rectangle {
|
||||
return OffsetPoint(r, p)
|
||||
}
|
||||
|
||||
// Checks if this Rectangle overlaps with another rectangle.
|
||||
func (*Namespace) Overlaps(r *Rectangle, other *Rectangle) bool {
|
||||
return Overlaps(r, other)
|
||||
}
|
||||
|
||||
// PerimeterPoint returns a Point from the perimeter of the Rectangle based on the given angle.
|
||||
func (*Namespace) PerimeterPoint(r *Rectangle, angle float64, p *point.Point) *point.Point {
|
||||
return PerimeterPoint(r, angle, p)
|
||||
}
|
||||
|
||||
// Calculates a random point that lies within the `outer` Rectangle, but outside of the `inner`
|
||||
// Rectangle. The inner Rectangle must be fully contained within the outer rectangle.
|
||||
func (*Namespace) GetRandomPointOutside(r, other *Rectangle, out *point.Point) *point.Point {
|
||||
var outer, inner *Rectangle
|
||||
|
||||
if r.ContainsRectangle(other) {
|
||||
outer, inner = r, other
|
||||
} else {
|
||||
outer, inner = other, r
|
||||
}
|
||||
|
||||
return GetRandomPointOutside(outer, inner, out)
|
||||
}
|
||||
|
||||
// SameDimensions determines if the two objects (either Rectangles or Rectangle-like) have the same
|
||||
// width and height values under strict equality.
|
||||
func (*Namespace) SameDimensions(r, other *Rectangle) bool {
|
||||
return SameDimensions(r, other)
|
||||
}
|
||||
|
||||
// Scale the width and height of this Rectangle by the given amounts.
|
||||
func (*Namespace) Scale(r *Rectangle, x, y float64) *Rectangle {
|
||||
return Scale(r, x, y)
|
||||
}
|
||||
|
||||
// Union creates a new Rectangle or repositions and/or resizes an existing Rectangle so that it
|
||||
// encompasses the two given Rectangles, i.e. calculates their union.
|
||||
func (*Namespace) Union(r *Rectangle, other *Rectangle) *Rectangle {
|
||||
return Union(r, other, r)
|
||||
}
|
9
d2common/d2geom/rectangle/offset.go
Normal file
9
d2common/d2geom/rectangle/offset.go
Normal file
@ -0,0 +1,9 @@
|
||||
package rectangle
|
||||
|
||||
// Offset nudges (translates) the top left corner of a Rectangle by a given offset.
|
||||
func Offset(r *Rectangle, x, y float64) *Rectangle {
|
||||
r.X += x
|
||||
r.Y += y
|
||||
|
||||
return r
|
||||
}
|
11
d2common/d2geom/rectangle/offset_point.go
Normal file
11
d2common/d2geom/rectangle/offset_point.go
Normal file
@ -0,0 +1,11 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/geom/point"
|
||||
|
||||
// OffsetPoint nudges (translates) the top left corner of a Rectangle by the coordinates of a point.
|
||||
func OffsetPoint(r *Rectangle, p *point.Point) *Rectangle {
|
||||
r.X += p.X
|
||||
r.Y += p.Y
|
||||
|
||||
return r
|
||||
}
|
10
d2common/d2geom/rectangle/overlaps.go
Normal file
10
d2common/d2geom/rectangle/overlaps.go
Normal file
@ -0,0 +1,10 @@
|
||||
package rectangle
|
||||
|
||||
// Checks if two Rectangles overlap. If a Rectangle is within another Rectangle,
|
||||
// the two will be considered overlapping. Thus, the Rectangles are treated as "solid".
|
||||
func Overlaps(a, b *Rectangle) bool {
|
||||
return a.X < b.Right() &&
|
||||
a.Right() > b.X &&
|
||||
a.Y < b.Bottom() &&
|
||||
a.Bottom() > b.Y
|
||||
}
|
6
d2common/d2geom/rectangle/perimeter.go
Normal file
6
d2common/d2geom/rectangle/perimeter.go
Normal file
@ -0,0 +1,6 @@
|
||||
package rectangle
|
||||
|
||||
// Perimeter calculates the perimeter of a Rectangle.
|
||||
func Perimeter(r *Rectangle) float64 {
|
||||
return 2 * (r.Width + r.Height)
|
||||
}
|
24
d2common/d2geom/rectangle/perimeter_point.go
Normal file
24
d2common/d2geom/rectangle/perimeter_point.go
Normal file
@ -0,0 +1,24 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
"github.com/gravestench/pho/phomath"
|
||||
)
|
||||
|
||||
func PerimeterPoint(r *Rectangle, angle float64, out *point.Point) *point.Point {
|
||||
if out == nil {
|
||||
out = point.New(0, 0)
|
||||
}
|
||||
|
||||
angle = phomath.DegToRad(angle)
|
||||
polarity := map[bool]float64{true: 1, false: -1}
|
||||
s, c := math.Sin(angle), math.Cos(angle)
|
||||
dx, dy := r.Width/2*polarity[c > 0], r.Height/2*polarity[s > 0]
|
||||
|
||||
out.X = dx + r.CenterX()
|
||||
out.Y = dy + r.CenterY()
|
||||
|
||||
return out
|
||||
}
|
367
d2common/d2geom/rectangle/rectangle.go
Normal file
367
d2common/d2geom/rectangle/rectangle.go
Normal file
@ -0,0 +1,367 @@
|
||||
package rectangle
|
||||
|
||||
import (
|
||||
"github.com/gravestench/pho/geom"
|
||||
"github.com/gravestench/pho/geom/line"
|
||||
"github.com/gravestench/pho/geom/point"
|
||||
"github.com/gravestench/pho/phomath"
|
||||
)
|
||||
|
||||
// New creates a new rectangle
|
||||
func New(x, y, w, h float64) *Rectangle {
|
||||
return &Rectangle{
|
||||
Type: geom.Rectangle,
|
||||
X: x,
|
||||
Y: y,
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
}
|
||||
|
||||
// Encapsulates a 2D rectangle defined by its corner point in the top-left and its extends
|
||||
// in x (width) and y (height)
|
||||
type Rectangle struct {
|
||||
Type geom.ShapeType
|
||||
X, Y float64
|
||||
Width, Height float64
|
||||
}
|
||||
|
||||
// Area calculates the area of the given rectangle.
|
||||
func (r *Rectangle) Area() float64 {
|
||||
return r.Width * r.Height
|
||||
}
|
||||
|
||||
// Left returns the left position of the rectangle
|
||||
func (r *Rectangle) Left() float64 {
|
||||
return r.X
|
||||
}
|
||||
|
||||
// SetLeft sets the left position of the rectangle, which also sets the x coordinate
|
||||
func (r *Rectangle) SetLeft(value float64) *Rectangle {
|
||||
if value >= r.Right() {
|
||||
r.Width = 0
|
||||
} else {
|
||||
r.Width = r.Right() - value
|
||||
}
|
||||
|
||||
r.X = value
|
||||
return r
|
||||
}
|
||||
|
||||
// Right returns the right position of the rectangle
|
||||
func (r *Rectangle) Right() float64 {
|
||||
return r.X + r.Width
|
||||
}
|
||||
|
||||
// SetRight sets the right position of the rectangle, which adjusts the width
|
||||
func (r *Rectangle) SetRight(value float64) *Rectangle {
|
||||
if value <= r.X {
|
||||
r.Width = 0
|
||||
} else {
|
||||
r.Width = value - r.X
|
||||
}
|
||||
|
||||
r.X = value
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Top returns the top position of the rectangle
|
||||
func (r *Rectangle) Top() float64 {
|
||||
return r.Y
|
||||
}
|
||||
|
||||
// SetTop sets the top position of the rectangle, which also adjusts the Y coordinate
|
||||
func (r *Rectangle) SetTop(value float64) *Rectangle {
|
||||
if value >= r.Bottom() {
|
||||
r.Height = 0
|
||||
} else {
|
||||
r.Height = r.Bottom() - value
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Bottom returns the bottom position of the rectangle
|
||||
func (r *Rectangle) Bottom() float64 {
|
||||
return r.Y + r.Height
|
||||
}
|
||||
|
||||
// SetBottom sets the bottom position of the rectangle, which also adjusts the height
|
||||
func (r *Rectangle) SetBottom(value float64) *Rectangle {
|
||||
if value <= r.Y {
|
||||
r.Height = 0
|
||||
} else {
|
||||
r.Height = value - r.Y
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Rectangle) CenterX() float64 {
|
||||
return r.X + r.Width/2
|
||||
}
|
||||
|
||||
func (r *Rectangle) SetCenterX(value float64) *Rectangle {
|
||||
r.X = value - r.Width/2
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Rectangle) CenterY() float64 {
|
||||
return r.Y + r.Height/2
|
||||
}
|
||||
|
||||
func (r *Rectangle) SetCenterY(value float64) *Rectangle {
|
||||
r.Y = value - r.Height/2
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// CenterOn moves the top-left corner of a Rectangle so that its center is at the given coordinates.
|
||||
func (r *Rectangle) CenterOn(x, y float64) *Rectangle {
|
||||
return CenterOn(r, x, y)
|
||||
}
|
||||
|
||||
// Contains checks if the given x, y is inside the Rectangle's bounds.
|
||||
func (r *Rectangle) Contains(x, y float64) bool {
|
||||
return Contains(r, x, y)
|
||||
}
|
||||
|
||||
// GetPoint calculates the coordinates of a point at a certain `position` on the
|
||||
// Rectangle's perimeter, assigns to and returns the given point, or creates a point if nil.
|
||||
func (r *Rectangle) GetPoint(position float64, p *point.Point) *point.Point {
|
||||
return GetPoint(r, position, p)
|
||||
}
|
||||
|
||||
// GetPoints returns a slice of points from the perimeter of the Rectangle,
|
||||
// each spaced out based on the quantity or step required.
|
||||
func (r *Rectangle) GetPoints(quantity int, stepRate float64, points []*point.Point) []*point.Point {
|
||||
return GetPoints(r, quantity, stepRate, points)
|
||||
}
|
||||
|
||||
// GetRandomPoint returns a random point within the Rectangle's bounds.
|
||||
func (r *Rectangle) GetRandomPoint(p *point.Point) *point.Point {
|
||||
return GetRandomPoint(r, p)
|
||||
}
|
||||
|
||||
// SetTo sets the position, width, and height of the Rectangle.
|
||||
func (r *Rectangle) SetTo(x, y, w, h float64) *Rectangle {
|
||||
r.X, r.Y, r.Width, r.Height = x, y, w, h
|
||||
return r
|
||||
}
|
||||
|
||||
// SetEmpty resets the position, width, and height of the Rectangle to 0.
|
||||
func (r *Rectangle) SetEmpty() *Rectangle {
|
||||
return r.SetTo(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
// SetPosition sets the position of the rectangle.
|
||||
func (r *Rectangle) SetPosition(x, y float64) *Rectangle {
|
||||
r.X, r.Y = x, y
|
||||
return r
|
||||
}
|
||||
|
||||
// SetSize sets the width and height of the rectangle.
|
||||
func (r *Rectangle) SetSize(w, h float64) *Rectangle {
|
||||
r.Width, r.Height = w, h
|
||||
return r
|
||||
}
|
||||
|
||||
// IsEmpty determines if the Rectangle is empty.
|
||||
// A Rectangle is empty if its width or height is less than or equal to 0.
|
||||
func (r *Rectangle) IsEmpty() bool {
|
||||
return r.Width <= phomath.Epsilon || r.Height <= phomath.Epsilon
|
||||
}
|
||||
|
||||
// GetLineA returns a line object that corresponds to the top side of this rectangle.
|
||||
// Assigns to the given line and returns it, or creates a new line if nil.
|
||||
func (r *Rectangle) GetLineA(l *line.Line) *line.Line {
|
||||
if l == nil {
|
||||
l = line.New(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
l.SetTo(r.X, r.Y, r.Right(), r.Y)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// GetLineB returns a line object that corresponds to the right side of this rectangle.
|
||||
// Assigns to the given line and returns it, or creates a new line if nil.
|
||||
func (r *Rectangle) GetLineB(l *line.Line) *line.Line {
|
||||
if l == nil {
|
||||
l = line.New(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
l.SetTo(r.Right(), r.Y, r.Right(), r.Bottom())
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// GetLineC returns a line object that corresponds to the bottom side of this rectangle.
|
||||
// Assigns to the given line and returns it, or creates a new line if nil.
|
||||
func (r *Rectangle) GetLineC(l *line.Line) *line.Line {
|
||||
if l == nil {
|
||||
l = line.New(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
l.SetTo(r.X, r.Bottom(), r.X, r.Y)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// GetLineD returns a line object that corresponds to the left side of this rectangle.
|
||||
// Assigns to the given line and returns it, or creates a new line if nil.
|
||||
func (r *Rectangle) GetLineD(l *line.Line) *line.Line {
|
||||
if l == nil {
|
||||
l = line.New(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
l.SetTo(r.X, r.Y, r.X, r.Bottom())
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// Ceil rounds a Rectangle's position up to the smallest integer greater than or equal to each
|
||||
// current coordinate.
|
||||
func (r *Rectangle) Ceil() *Rectangle {
|
||||
return Ceil(r)
|
||||
}
|
||||
|
||||
// CeilAll rounds a Rectangle's position and size up to the smallest
|
||||
// integer greater than or equal to each respective value.
|
||||
func (r *Rectangle) CeilAll() *Rectangle {
|
||||
return CeilAll(r)
|
||||
}
|
||||
|
||||
// Clone this rectangle to a new rectangle instance
|
||||
func (r *Rectangle) Clone() *Rectangle {
|
||||
return New(r.X, r.Y, r.Width, r.Height)
|
||||
}
|
||||
|
||||
// ContainsPoint checks if a given point is inside a Rectangle's bounds.
|
||||
func (r *Rectangle) ContainsPoint(p *point.Point) bool {
|
||||
return Contains(r, p.X, p.Y)
|
||||
}
|
||||
|
||||
// ContainsRect checks if a given point is inside a Rectangle's bounds.
|
||||
func (r *Rectangle) ContainsRectangle(other *Rectangle) bool {
|
||||
return ContainsRectangle(r, other)
|
||||
}
|
||||
|
||||
// CopyFrom copies the values of the given rectangle.
|
||||
func (r *Rectangle) CopyFrom(source *Rectangle) *Rectangle {
|
||||
return CopyFrom(source, r)
|
||||
}
|
||||
|
||||
// Deconstruct creates a slice of points for each corner of a Rectangle.
|
||||
// If a slice is specified, each point object will be added to the end of the slice,
|
||||
// otherwise a new slice will be created.
|
||||
func (r *Rectangle) Deconstruct(to []*point.Point) []*point.Point {
|
||||
return Deconstruct(r, to)
|
||||
}
|
||||
|
||||
// Equals compares the `x`, `y`, `width` and `height` properties of two rectangles.
|
||||
func (r *Rectangle) Equals(other *Rectangle) bool {
|
||||
return Equals(r, other)
|
||||
}
|
||||
|
||||
// Adjusts rectangle, changing its width, height and position,
|
||||
// so that it fits inside the area of the source rectangle, while maintaining its original
|
||||
// aspect ratio.
|
||||
func (r *Rectangle) FitInside(other *Rectangle) *Rectangle {
|
||||
return FitInside(r, other)
|
||||
}
|
||||
|
||||
// GetCenter returns the center of the Rectangle as a Point.
|
||||
func (r *Rectangle) GetCenter() *point.Point {
|
||||
return GetCenter(r)
|
||||
}
|
||||
|
||||
// GetSize returns the size of the Rectangle, expressed as a Point object.
|
||||
// With the value of the `width` as the `x` property and the `height` as the `y` property.
|
||||
func (r *Rectangle) GetSize() *point.Point {
|
||||
return GetSize(r)
|
||||
}
|
||||
|
||||
func (r *Rectangle) Inflate(x, y float64) *Rectangle {
|
||||
return Inflate(r, x, y)
|
||||
}
|
||||
|
||||
// Takes two Rectangles and first checks to see if they intersect.
|
||||
// If they intersect it will return the area of intersection in the `out` Rectangle.
|
||||
// If they do not intersect, the `out` Rectangle will have a width and height of zero.
|
||||
// The given `intersect` rectangle will be assigned the intsersect values and returned.
|
||||
// A new rectangle will be created if `intersect` is nil.
|
||||
func (r *Rectangle) Intersection(other, intersect *Rectangle) *Rectangle {
|
||||
return Intersection(r, other, intersect)
|
||||
}
|
||||
|
||||
// MergePoints adjusts this rectangle using a list of points by repositioning and/or resizing
|
||||
// it such that all points are located on or within its bounds.
|
||||
func (r *Rectangle) MergePoints(points []*point.Point) *Rectangle {
|
||||
return MergePoints(r, points)
|
||||
}
|
||||
|
||||
// MergeRectangle merges the given rectangle into this rectangle and returns this rectangle.
|
||||
// Neither rectangle should have a negative width or height.
|
||||
func (r *Rectangle) MergeRectangle(other *Rectangle) *Rectangle {
|
||||
return MergeRectangle(r, other)
|
||||
}
|
||||
|
||||
// MergeXY merges this rectangle with a point by repositioning and/or resizing it so that the
|
||||
// point is/on or/within its bounds.
|
||||
func (r *Rectangle) MergeXY(x, y float64) *Rectangle {
|
||||
return MergeXY(r, x, y)
|
||||
}
|
||||
|
||||
// Offset nudges (translates) the top left corner of this Rectangle by a given offset.
|
||||
func (r *Rectangle) Offset(x, y float64) *Rectangle {
|
||||
return Offset(r, x, y)
|
||||
}
|
||||
|
||||
// OffsetPoint nudges (translates) the top left corner of this Rectangle by the coordinates of a
|
||||
// point.
|
||||
func (r *Rectangle) OffsetPoint(p *point.Point) *Rectangle {
|
||||
return OffsetPoint(r, p)
|
||||
}
|
||||
|
||||
// Checks if this Rectangle overlaps with another rectangle.
|
||||
func (r *Rectangle) Overlaps(other *Rectangle) bool {
|
||||
return Overlaps(r, other)
|
||||
}
|
||||
|
||||
// PerimeterPoint returns a Point from the perimeter of the Rectangle based on the given angle.
|
||||
func (r *Rectangle) PerimeterPoint(angle float64, p *point.Point) *point.Point {
|
||||
return PerimeterPoint(r, angle, p)
|
||||
}
|
||||
|
||||
// Calculates a random point that lies within the `outer` Rectangle, but outside of the `inner`
|
||||
// Rectangle. The inner Rectangle must be fully contained within the outer rectangle.
|
||||
func (r *Rectangle) GetRandomPointOutside(other *Rectangle, out *point.Point) *point.Point {
|
||||
var outer, inner *Rectangle
|
||||
|
||||
if r.ContainsRectangle(other) {
|
||||
outer, inner = r, other
|
||||
} else {
|
||||
outer, inner = other, r
|
||||
}
|
||||
|
||||
return GetRandomPointOutside(outer, inner, out)
|
||||
}
|
||||
|
||||
// SameDimensions determines if the two objects (either Rectangles or Rectangle-like) have the same
|
||||
// width and height values under strict equality.
|
||||
func (r *Rectangle) SameDimensions(other *Rectangle) bool {
|
||||
return SameDimensions(r, other)
|
||||
}
|
||||
|
||||
// Scale the width and height of this Rectangle by the given amounts.
|
||||
func (r *Rectangle) Scale(x, y float64) *Rectangle {
|
||||
return Scale(r, x, y)
|
||||
}
|
||||
|
||||
// Union creates a new Rectangle or repositions and/or resizes an existing Rectangle so that it
|
||||
// encompasses the two given Rectangles, i.e. calculates their union.
|
||||
func (r *Rectangle) Union(other *Rectangle) *Rectangle {
|
||||
return Union(r, other, r)
|
||||
}
|
12
d2common/d2geom/rectangle/same_dimensions.go
Normal file
12
d2common/d2geom/rectangle/same_dimensions.go
Normal file
@ -0,0 +1,12 @@
|
||||
package rectangle
|
||||
|
||||
import "github.com/gravestench/pho/phomath"
|
||||
|
||||
// SameDimensions determines if the two objects (either Rectangles or Rectangle-like) have the same
|
||||
// width and height values under strict equality.
|
||||
func SameDimensions(a, b *Rectangle) bool {
|
||||
dw := (a.Width - b.Width) * (a.Width - b.Width)
|
||||
dh := (a.Height - b.Height) * (a.Height - b.Height)
|
||||
|
||||
return dw < phomath.Epsilon && dh < phomath.Epsilon
|
||||
}
|
9
d2common/d2geom/rectangle/scale.go
Normal file
9
d2common/d2geom/rectangle/scale.go
Normal file
@ -0,0 +1,9 @@
|
||||
package rectangle
|
||||
|
||||
// Scale the width and height of this Rectangle by the given amounts.
|
||||
func Scale(r *Rectangle, x, y float64) *Rectangle {
|
||||
r.Width *= x
|
||||
r.Height *= y
|
||||
|
||||
return r
|
||||
}
|
12
d2common/d2geom/rectangle/union.go
Normal file
12
d2common/d2geom/rectangle/union.go
Normal file
@ -0,0 +1,12 @@
|
||||
package rectangle
|
||||
|
||||
import "math"
|
||||
|
||||
// Union creates a new Rectangle or repositions and/or resizes an existing Rectangle so that it
|
||||
// encompasses the two given Rectangles, i.e. calculates their union.
|
||||
func Union(a, b, out *Rectangle) *Rectangle {
|
||||
x, y := math.Min(a.X, b.X), math.Min(a.Y, b.Y)
|
||||
w, h := math.Min(a.Width, b.Width), math.Min(a.Height, b.Height)
|
||||
|
||||
return out.SetTo(x, y, w, h)
|
||||
}
|
43
d2core/d2components/rectangle.go
Normal file
43
d2core/d2components/rectangle.go
Normal file
@ -0,0 +1,43 @@
|
||||
//nolint:dupl,golint,stylecheck // component declarations are supposed to look the same
|
||||
package d2components
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom/rectangle"
|
||||
"github.com/gravestench/akara"
|
||||
)
|
||||
|
||||
// static check that Rectangle implements Component
|
||||
var _ akara.Component = &Rectangle{}
|
||||
|
||||
// Rectangle represents an entities x,y axis scale as a vector
|
||||
type Rectangle struct {
|
||||
rectangle.Rectangle
|
||||
}
|
||||
|
||||
// New creates a new Rectangle instance. By default, the scale is (1,1)
|
||||
func (*Rectangle) New() akara.Component {
|
||||
return &Rectangle{
|
||||
Rectangle: rectangle.Rectangle{},
|
||||
}
|
||||
}
|
||||
|
||||
// RectangleFactory is a wrapper for the generic component factory that returns Rectangle component instances.
|
||||
// This can be embedded inside of a system to give them the methods for adding, retrieving, and removing a Rectangle.
|
||||
type RectangleFactory struct {
|
||||
Rectangle *akara.ComponentFactory
|
||||
}
|
||||
|
||||
// AddRectangle adds a Rectangle component to the given entity and returns it
|
||||
func (m *RectangleFactory) AddRectangle(id akara.EID) *Rectangle {
|
||||
return m.Rectangle.Add(id).(*Rectangle)
|
||||
}
|
||||
|
||||
// GetRectangle returns the Rectangle component for the given entity, and a bool for whether or not it exists
|
||||
func (m *RectangleFactory) GetRectangle(id akara.EID) (*Rectangle, bool) {
|
||||
component, found := m.Rectangle.Get(id)
|
||||
if !found {
|
||||
return nil, found
|
||||
}
|
||||
|
||||
return component.(*Rectangle), found
|
||||
}
|
Loading…
Reference in New Issue
Block a user