godot.core.math.Rect2i.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of godot-library-debug Show documentation
Show all versions of godot-library-debug Show documentation
Contains godot api as kotlin classes and jvm cpp interaction code.
@file:Suppress("PackageDirectoryMismatch", "unused")
package godot.core
import godot.Side
import godot.annotation.CoreTypeHelper
import godot.annotation.CoreTypeLocalCopy
import kotlincompile.definitions.GodotJvmBuildConfig
import kotlin.math.max
import kotlin.math.min
private typealias Point2i = Vector2i
private typealias Size2i = Vector2i
class Rect2i(
p_position: Point2i,
p_size: Size2i
) {
@Suppress("PropertyName")
@PublishedApi
internal var _position = Point2i(p_position)
@Suppress("PropertyName")
@PublishedApi
internal var _size = Size2i(p_size)
//PROPERTIES
/**
* Return a copy of the position Vector2i
*
*
* Beginning corner. Typically has values lower than [end].
*
* **Warning**: Writing position.x = 2 will only modify a copy, not the actual object.
* To modify it, use [position].
*
* See: [Documentation](https://godot-kotl.in/en/stable/user-guide/api-differences/#core-types)
* */
@CoreTypeLocalCopy
var position
get() = Point2i(_position)
set(value) {
_position = Point2i(value)
}
/**
* Apply modifications on actual [position] [Vector2].
*
*
* [position] var return a copy of actual position of this [Rect2i]. This method purpose is to make changes to the
* actual position.
* See also: [position]
*/
@CoreTypeHelper
inline fun position(block: Point2i.() -> T): T {
return _position.block()
}
/**
* Return a copy of the size Vector2i
*
*
* Size from [position] to [end]. Typically, all components are positive.
* If the size is negative, you can use [abs] to fix it.
*
* **Warning**: Writing size.x = 2 will only modify a copy, not the actual object.
* To modify it, use [size].
*
* See: [Documentation](https://godot-kotl.in/en/stable/user-guide/api-differences/#core-types)
* */
@CoreTypeLocalCopy
var size
get() = Size2i(_size)
set(value) {
_size = Size2i(value)
}
/**
* Apply modifications on actual [size] [Vector2].
*
*
* [size] var return a copy of actual size of this [Rect2i]. This method purpose is to make changes to the
* actual size.
* See also: [size]
*/
@CoreTypeHelper
inline fun size(block: Size2i.() -> T): T {
return _size.block()
}
/**
* Ending corner. This is calculated as `position + size`. Setting this value will change the size.
*/
@CoreTypeLocalCopy
var end: Vector2i
get() = _position + _size
set(value) {
_size = value - _position
}
/**
* Constructs a default-initialized [Rect2i] with default (zero) values of [position] and [size].
*/
constructor() : this(Point2i(), Size2i())
/**
* Constructs a [Rect2i] by [x], [y], [width], and [height].
*/
constructor(x: Int, y: Int, width: Int, height: Int) : this(Point2i(x, y), Size2i(width, height))
/**
* Constructs a new [Rect2i] from [Rect2]. The floating point coordinates will be truncated.
*/
constructor(rect: Rect2) : this(rect._position.toVector2i(), rect._size.toVector2i())
/**
* Constructs a [Rect2i] as a copy of the given [Rect2i].
*/
constructor(rect: Rect2i) : this(rect._position, rect._size)
// API
/**
* Returns a [Rect2i] with equivalent position and area, modified so that the top-left corner is the origin and
* `width` and `height` are positive.
*/
fun abs() = Rect2i(position + size.min(Point2i()), size.abs())
/**
* Returns `true` if this [Rect2i] completely encloses another one.
*/
fun encloses(rect: Rect2i) = (rect._position.x >= _position.x) && (rect._position.y >= _position.y) &&
((rect._position.x + rect._size.x) <= (_position.x + _size.x)) &&
((rect._position.y + rect._size.y) <= (_position.y + _size.y))
/**
* Returns a copy of this [Rect2i] expanded so that the borders align with the given point.
*/
fun expand(vector: Point2i) = Rect2i(this).also {
it.expandTo(vector)
}
private fun expandTo(p_vector: Point2i) {
val begin = Point2i(_position)
val end = _position + _size
if (p_vector.x < begin.x) {
begin.x = p_vector.x
}
if (p_vector.y < begin.y) {
begin.y = p_vector.y
}
if (p_vector.x > end.x) {
end.x = p_vector.x
}
if (p_vector.y > end.y) {
end.y = p_vector.y
}
_position = begin
_size = end - begin
}
/**
* Returns the area of the [Rect2i]. See also [hasArea].
*/
fun getArea(): Int = size.width * size.height
/**
* Returns the center of the [Rect2i], which is equal to [position] + ([size] / 2).
*
* If [size] is an odd number, the returned center value will be rounded towards [position].
*/
fun getCenter(): Vector2i = position + (size / 2)
/**
* Returns a copy of the [Rect2i] grown by the specified `amount` on all sides.
*/
fun grow(amount: Int) = Rect2i(this).also {
it._position.x -= amount
it._position.y -= amount
it._size.width += amount * 2
it._size.height += amount * 2
}
/**
* Returns a copy of the [Rect2i] grown by the specified amount on each side individually.
*/
fun growIndividual(left: Int, top: Int, right: Int, bottom: Int) = Rect2i(this).also {
it._position.x -= left
it._position.y -= top
it._size.width += left + right
it._size.height += top + bottom
}
/**
* Returns a copy of the [Rect2i] grown by the specified [amount] on the specified [Side].
*/
fun growSide(side: Side, amount: Int) = growIndividual(
if (Side.SIDE_LEFT === side) amount else 0,
if (Side.SIDE_TOP === side) amount else 0,
if (Side.SIDE_RIGHT === side) amount else 0,
if (Side.SIDE_BOTTOM === side) amount else 0
)
/**
* Returns `true` if the [Rect2i] has area, and `false` if the [Rect2i] is linear, empty, or has a negative [size].
* See also [getArea].
*/
fun hasArea() = _size.x > 0 && _size.y > 0
/**
* Returns `true` if the [Rect2i] contains a point. By convention, the right and bottom edges of the [Rect2i] are
* considered exclusive, so points on these edges are not included.
*
* **Note**: This method is not reliable for [Rect2i] with a negative size. Use [abs] to get a positive sized
* equivalent rectangle to check for contained points.
*/
fun hasPoint(point: Point2i): Boolean {
if (point.x < _position.x) {
return false
}
if (point.y < _position.y) {
return false
}
if (point.x >= (_position.x + _size.x)) {
return false
}
if (point.y >= (_position.y + _size.y)) {
return false
}
return true
}
/**
* Returns the intersection of this [Rect2i] and `b`.
* If the rectangles do not intersect, an empty [Rect2i] is returned.
*/
fun intersection(rect: Rect2i): Rect2i {
val ret = Rect2i(rect)
if (!intersects(ret)) {
return Rect2i()
}
ret._position.x = max(rect._position.x, _position.x)
ret._position.y = max(rect._position.y, _position.y)
val rectEnd: Point2i = rect._position + rect._size
val end = _position + _size
ret._size.x = min(rectEnd.x, end.x) - ret._position.x
ret._size.y = min(rectEnd.y, end.y) - ret._position.y
return ret
}
/**
* Returns `true` if the [Rect2i] overlaps with `b` (i.e. they have at least one point in common).
*/
fun intersects(rect: Rect2i): Boolean {
if (GodotJvmBuildConfig.DEBUG) {
require(!(size.x < 0 || size.y < 0 || rect.size.x < 0 || rect.size.y < 0)) {
"Rect2i size is negative, this is not supported. Use Rect2i.abs() to get a Rect2i with a positive size."
}
}
if (_position.x >= (rect._position.x + rect._size.width)) {
return false
}
if ((_position.x + _size.width) <= rect._position.x) {
return false
}
if (_position.y >= (rect._position.y + rect._size.height)) {
return false
}
if ((_position.y + _size.height) <= rect._position.y) {
return false
}
return true
}
/**
* Returns a larger [Rect2i] that contains this [Rect2i] and `b`.
*/
fun merge(rect: Rect2i): Rect2i {
val newRect = Rect2i()
newRect._position.x = min(rect._position.x, _position.x)
newRect._position.y = min(rect._position.y, _position.y)
newRect._size.x = max(rect._position.x + rect._size.x, _position.x + _size.x)
newRect._size.y = max(rect._position.y + rect._size.y, _position.y + _size.y)
newRect._size = newRect._size - newRect._position // Make relative again.
return newRect
}
fun toRect2() = Rect2(
_position.toVector2(),
_size.toVector2()
)
override fun toString(): String {
return "[P: $_position, S: $_size]"
}
/**
* Returns `true` if the rectangles are equal.
*/
override fun equals(other: Any?): Boolean = when (other) {
is Rect2i -> _position == other._position && _size == other._size
else -> false
}
override fun hashCode(): Int {
var result = _position.hashCode()
result = 31 * result + _size.hashCode()
return result
}
}