///|
/// Integer point or vector.
pub(all) struct IPoint {
x : Int
y : Int
} derive(Debug, Eq)
///|
pub fn IPoint::new(x : Int, y : Int) -> IPoint {
{ x, y }
}
///|
pub fn IPoint::zero() -> IPoint {
IPoint::new(0, 0)
}
///|
pub impl Default for IPoint with fn default() {
IPoint::zero()
}
///|
pub fn IPoint::is_zero(self : IPoint) -> Bool {
self.x == 0 && self.y == 0
}
///|
pub fn IPoint::equals(self : IPoint, x : Int, y : Int) -> Bool {
self == IPoint::new(x, y)
}
///|
pub fn IPoint::offset(self : IPoint, dx : Int, dy : Int) -> IPoint {
IPoint::new(self.x + dx, self.y + dy)
}
///|
pub fn IPoint::to_point(self : IPoint) -> Point {
Point::new(Float::from_int(self.x), Float::from_int(self.y))
}
///|
/// Floating-point point or vector.
pub(all) struct Point {
x : Scalar
y : Scalar
} derive(Debug, Eq)
///|
pub fn Point::new(x : Scalar, y : Scalar) -> Point {
{ x, y }
}
///|
pub fn Point::zero() -> Point {
Point::new(0, 0)
}
///|
pub impl Default for Point with fn default() {
Point::zero()
}
///|
pub fn Point::is_zero(self : Point) -> Bool {
self.x == 0 && self.y == 0
}
///|
pub fn Point::is_finite(self : Point) -> Bool {
geometry_scalar_is_finite(self.x) && geometry_scalar_is_finite(self.y)
}
///|
pub fn Point::equals(self : Point, x : Scalar, y : Scalar) -> Bool {
self == Point::new(x, y)
}
///|
pub fn Point::offset(self : Point, dx : Scalar, dy : Scalar) -> Point {
Point::new(self.x + dx, self.y + dy)
}
///|
pub fn Point::scale(self : Point, scale : Scalar) -> Point {
Point::new(self.x * scale, self.y * scale)
}
///|
pub fn Point::dot(self : Point, other : Point) -> Scalar {
self.x * other.x + self.y * other.y
}
///|
pub fn Point::cross(self : Point, other : Point) -> Scalar {
self.x * other.y - self.y * other.x
}
///|
pub fn Point::length_squared(self : Point) -> Scalar {
self.dot(self)
}
///|
pub fn Point::length(self : Point) -> Scalar {
self.length_squared().sqrt()
}
///|
pub fn Point::distance_to_origin(self : Point) -> Scalar {
self.length()
}
///|
pub fn Point::distance_to(self : Point, other : Point) -> Scalar {
Point::new(self.x - other.x, self.y - other.y).length()
}
///|
pub fn Point::distance_to_squared(self : Point, other : Point) -> Scalar {
Point::new(self.x - other.x, self.y - other.y).length_squared()
}
///|
pub fn Point::distance_to_origin_squared(self : Point) -> Scalar {
self.length_squared()
}
///|
pub fn Point::with_length(self : Point, length : Scalar) -> Point? {
if !self.is_finite() || !geometry_scalar_is_finite(length) || length < 0.0 {
None
} else {
let current_length = self.length()
if current_length == 0.0 || !geometry_scalar_is_finite(current_length) {
None
} else {
Some(self.scale(length / current_length))
}
}
}
///|
pub fn Point::normalized(self : Point) -> Point? {
self.with_length(1.0)
}
///|
pub fn Point::rotate_cw(self : Point) -> Point {
Point::new(self.y, -self.x)
}
///|
pub fn Point::rotate_ccw(self : Point) -> Point {
Point::new(-self.y, self.x)
}
///|
pub fn Point::to_ipoint_round(self : Point) -> IPoint {
IPoint::new(self.x.round().to_int(), self.y.round().to_int())
}
///|
/// Integer width and height.
pub(all) struct ISize {
width : Int
height : Int
} derive(Debug, Eq)
///|
pub fn ISize::new(width : Int, height : Int) -> ISize {
{ width, height }
}
///|
pub fn ISize::empty() -> ISize {
ISize::new(0, 0)
}
///|
pub impl Default for ISize with fn default() {
ISize::empty()
}
///|
pub fn ISize::is_zero(self : ISize) -> Bool {
self.width == 0 && self.height == 0
}
///|
pub fn ISize::is_empty(self : ISize) -> Bool {
self.width <= 0 || self.height <= 0
}
///|
pub fn ISize::area(self : ISize) -> Int64 {
self.width.to_int64() * self.height.to_int64()
}
///|
pub fn ISize::to_size(self : ISize) -> Size {
Size::new(Float::from_int(self.width), Float::from_int(self.height))
}
///|
/// Floating-point width and height.
pub(all) struct Size {
width : Scalar
height : Scalar
} derive(Debug, Eq)
///|
pub fn Size::new(width : Scalar, height : Scalar) -> Size {
{ width, height }
}
///|
pub fn Size::empty() -> Size {
Size::new(0, 0)
}
///|
pub fn Size::from_isize(size : ISize) -> Size {
size.to_size()
}
///|
pub impl Default for Size with fn default() {
Size::empty()
}
///|
pub fn Size::is_zero(self : Size) -> Bool {
self.width == 0 && self.height == 0
}
///|
pub fn Size::is_empty(self : Size) -> Bool {
self.width <= 0 || self.height <= 0
}
///|
pub fn Size::is_finite(self : Size) -> Bool {
geometry_scalar_is_finite(self.width) &&
geometry_scalar_is_finite(self.height)
}
///|
pub fn Size::scale(self : Size, scale : Scalar) -> Size {
Size::new(self.width * scale, self.height * scale)
}
///|
pub fn Size::to_isize_round(self : Size) -> ISize {
ISize::new(self.width.round().to_int(), self.height.round().to_int())
}
///|
/// Integer rectangle stored as left/top/right/bottom bounds.
pub(all) struct IRect {
left : Int
top : Int
right : Int
bottom : Int
} derive(Debug, Eq)
///|
pub fn IRect::new(left : Int, top : Int, right : Int, bottom : Int) -> IRect {
{ left, top, right, bottom }
}
///|
pub fn IRect::from_ltrb(
left : Int,
top : Int,
right : Int,
bottom : Int,
) -> IRect {
IRect::new(left, top, right, bottom)
}
///|
pub fn IRect::empty() -> IRect {
IRect::new(0, 0, 0, 0)
}
///|
pub fn IRect::from_wh(width : Int, height : Int) -> IRect {
IRect::from_xywh(0, 0, width, height)
}
///|
pub fn IRect::from_xywh(x : Int, y : Int, width : Int, height : Int) -> IRect {
IRect::new(x, y, x + width, y + height)
}
///|
pub fn IRect::from_size(size : ISize) -> IRect {
IRect::from_xywh(0, 0, size.width, size.height)
}
///|
pub fn IRect::from_point_and_size(point : IPoint, size : ISize) -> IRect {
IRect::from_xywh(point.x, point.y, size.width, size.height)
}
///|
pub impl Default for IRect with fn default() {
IRect::empty()
}
///|
pub fn IRect::x(self : IRect) -> Int {
self.left
}
///|
pub fn IRect::y(self : IRect) -> Int {
self.top
}
///|
pub fn IRect::left(self : IRect) -> Int {
self.left
}
///|
pub fn IRect::top(self : IRect) -> Int {
self.top
}
///|
pub fn IRect::right(self : IRect) -> Int {
self.right
}
///|
pub fn IRect::bottom(self : IRect) -> Int {
self.bottom
}
///|
pub fn IRect::width(self : IRect) -> Int {
self.right - self.left
}
///|
pub fn IRect::width_64(self : IRect) -> Int64 {
self.right.to_int64() - self.left.to_int64()
}
///|
pub fn IRect::height(self : IRect) -> Int {
self.bottom - self.top
}
///|
pub fn IRect::height_64(self : IRect) -> Int64 {
self.bottom.to_int64() - self.top.to_int64()
}
///|
pub fn IRect::size(self : IRect) -> ISize {
ISize::new(self.width(), self.height())
}
///|
pub fn IRect::is_empty(self : IRect) -> Bool {
self.right <= self.left || self.bottom <= self.top
}
///|
pub fn IRect::is_empty_64(self : IRect) -> Bool {
self.width_64() <= 0L || self.height_64() <= 0L
}
///|
pub fn IRect::is_sorted(self : IRect) -> Bool {
self.left <= self.right && self.top <= self.bottom
}
///|
pub fn IRect::contains_point(self : IRect, point : IPoint) -> Bool {
!self.is_empty() &&
point.x >= self.left &&
point.x < self.right &&
point.y >= self.top &&
point.y < self.bottom
}
///|
pub fn IRect::contains_rect(self : IRect, other : IRect) -> Bool {
!self.is_empty() &&
!other.is_empty() &&
self.left <= other.left &&
self.top <= other.top &&
self.right >= other.right &&
self.bottom >= other.bottom
}
///|
pub fn IRect::intersects(self : IRect, other : IRect) -> Bool {
!self.is_empty() &&
!other.is_empty() &&
self.left < other.right &&
other.left < self.right &&
self.top < other.bottom &&
other.top < self.bottom
}
///|
pub fn IRect::offset(self : IRect, dx : Int, dy : Int) -> IRect {
IRect::new(self.left + dx, self.top + dy, self.right + dx, self.bottom + dy)
}
///|
pub fn IRect::with_offset(self : IRect, offset : IPoint) -> IRect {
self.offset(offset.x, offset.y)
}
///|
pub fn IRect::with_offset_to(self : IRect, point : IPoint) -> IRect {
IRect::from_xywh(point.x, point.y, self.width(), self.height())
}
///|
pub fn IRect::inset(self : IRect, dx : Int, dy : Int) -> IRect {
IRect::new(self.left + dx, self.top + dy, self.right - dx, self.bottom - dy)
}
///|
pub fn IRect::with_inset(self : IRect, inset : ISize) -> IRect {
self.inset(inset.width, inset.height)
}
///|
pub fn IRect::outset(self : IRect, dx : Int, dy : Int) -> IRect {
self.inset(-dx, -dy)
}
///|
pub fn IRect::with_outset(self : IRect, outset : ISize) -> IRect {
self.outset(outset.width, outset.height)
}
///|
pub fn IRect::with_adjustment(
self : IRect,
delta_left : Int,
delta_top : Int,
delta_right : Int,
delta_bottom : Int,
) -> IRect {
IRect::new(
self.left + delta_left,
self.top + delta_top,
self.right + delta_right,
self.bottom + delta_bottom,
)
}
///|
pub fn IRect::sorted(self : IRect) -> IRect {
IRect::new(
Int::min(self.left, self.right),
Int::min(self.top, self.bottom),
Int::max(self.left, self.right),
Int::max(self.top, self.bottom),
)
}
///|
pub fn IRect::intersect(self : IRect, other : IRect) -> IRect? {
let result = IRect::new(
Int::max(self.left, other.left),
Int::max(self.top, other.top),
Int::min(self.right, other.right),
Int::min(self.bottom, other.bottom),
)
if result.is_empty() {
None
} else {
Some(result)
}
}
///|
pub fn IRect::join(self : IRect, other : IRect) -> IRect {
if self.is_empty() {
other
} else if other.is_empty() {
self
} else {
IRect::new(
Int::min(self.left, other.left),
Int::min(self.top, other.top),
Int::max(self.right, other.right),
Int::max(self.bottom, other.bottom),
)
}
}
///|
pub fn IRect::to_rect(self : IRect) -> Rect {
Rect::new(
Float::from_int(self.left),
Float::from_int(self.top),
Float::from_int(self.right),
Float::from_int(self.bottom),
)
}
///|
/// Floating-point rectangle stored as left/top/right/bottom bounds.
pub(all) struct Rect {
left : Scalar
top : Scalar
right : Scalar
bottom : Scalar
} derive(Debug, Eq)
///|
pub fn Rect::new(
left : Scalar,
top : Scalar,
right : Scalar,
bottom : Scalar,
) -> Rect {
{ left, top, right, bottom }
}
///|
pub fn Rect::from_ltrb(
left : Scalar,
top : Scalar,
right : Scalar,
bottom : Scalar,
) -> Rect {
Rect::new(left, top, right, bottom)
}
///|
pub fn Rect::empty() -> Rect {
Rect::new(0, 0, 0, 0)
}
///|
pub fn Rect::from_wh(width : Scalar, height : Scalar) -> Rect {
Rect::from_xywh(0, 0, width, height)
}
///|
pub fn Rect::from_iwh(width : Int, height : Int) -> Rect {
Rect::from_wh(Float::from_int(width), Float::from_int(height))
}
///|
pub fn Rect::from_xywh(
x : Scalar,
y : Scalar,
width : Scalar,
height : Scalar,
) -> Rect {
Rect::new(x, y, x + width, y + height)
}
///|
pub fn Rect::from_size(size : Size) -> Rect {
Rect::from_xywh(0, 0, size.width, size.height)
}
///|
pub fn Rect::from_isize(size : ISize) -> Rect {
Rect::from_size(size.to_size())
}
///|
pub fn Rect::from_point_and_size(point : Point, size : Size) -> Rect {
Rect::from_xywh(point.x, point.y, size.width, size.height)
}
///|
pub fn Rect::from_points(points : Array[Point]) -> Rect? {
if points.is_empty() {
None
} else {
let first = points[0]
let mut left = first.x
let mut top = first.y
let mut right = first.x
let mut bottom = first.y
for i in 1.. Rect {
match Rect::from_points(points) {
Some(rect) => rect
None => Rect::empty()
}
}
///|
pub fn Rect::from_irect(rect : IRect) -> Rect {
rect.to_rect()
}
///|
pub impl Default for Rect with fn default() {
Rect::empty()
}
///|
pub fn Rect::x(self : Rect) -> Scalar {
self.left
}
///|
pub fn Rect::y(self : Rect) -> Scalar {
self.top
}
///|
pub fn Rect::left(self : Rect) -> Scalar {
self.left
}
///|
pub fn Rect::top(self : Rect) -> Scalar {
self.top
}
///|
pub fn Rect::right(self : Rect) -> Scalar {
self.right
}
///|
pub fn Rect::bottom(self : Rect) -> Scalar {
self.bottom
}
///|
pub fn Rect::width(self : Rect) -> Scalar {
self.right - self.left
}
///|
pub fn Rect::height(self : Rect) -> Scalar {
self.bottom - self.top
}
///|
pub fn Rect::size(self : Rect) -> Size {
Size::new(self.width(), self.height())
}
///|
pub fn Rect::center_x(self : Rect) -> Scalar {
self.left * 0.5 + self.right * 0.5
}
///|
pub fn Rect::center_y(self : Rect) -> Scalar {
self.top * 0.5 + self.bottom * 0.5
}
///|
pub fn Rect::center(self : Rect) -> Point {
Point::new(self.center_x(), self.center_y())
}
///|
pub fn Rect::top_left(self : Rect) -> Point {
Point::new(self.left, self.top)
}
///|
pub fn Rect::tl(self : Rect) -> Point {
self.top_left()
}
///|
pub fn Rect::top_right(self : Rect) -> Point {
Point::new(self.right, self.top)
}
///|
pub fn Rect::tr(self : Rect) -> Point {
self.top_right()
}
///|
pub fn Rect::bottom_right(self : Rect) -> Point {
Point::new(self.right, self.bottom)
}
///|
pub fn Rect::br(self : Rect) -> Point {
self.bottom_right()
}
///|
pub fn Rect::bottom_left(self : Rect) -> Point {
Point::new(self.left, self.bottom)
}
///|
pub fn Rect::bl(self : Rect) -> Point {
self.bottom_left()
}
///|
pub fn Rect::to_quad(
self : Rect,
direction? : PathDirection = CW,
) -> Array[Point] {
if direction is CW {
[self.top_left(), self.top_right(), self.bottom_right(), self.bottom_left()]
} else {
[self.top_left(), self.bottom_left(), self.bottom_right(), self.top_right()]
}
}
///|
pub fn Rect::is_empty(self : Rect) -> Bool {
self.right <= self.left || self.bottom <= self.top
}
///|
pub fn Rect::is_sorted(self : Rect) -> Bool {
self.left <= self.right && self.top <= self.bottom
}
///|
fn geometry_scalar_is_finite(value : Scalar) -> Bool {
value == value && value - value == 0.0
}
///|
pub fn Rect::is_finite(self : Rect) -> Bool {
geometry_scalar_is_finite(self.left) &&
geometry_scalar_is_finite(self.top) &&
geometry_scalar_is_finite(self.right) &&
geometry_scalar_is_finite(self.bottom)
}
///|
pub fn Rect::contains_point(self : Rect, point : Point) -> Bool {
!self.is_empty() &&
point.x >= self.left &&
point.x < self.right &&
point.y >= self.top &&
point.y < self.bottom
}
///|
pub fn Rect::contains_rect(self : Rect, other : Rect) -> Bool {
!self.is_empty() &&
!other.is_empty() &&
self.left <= other.left &&
self.top <= other.top &&
self.right >= other.right &&
self.bottom >= other.bottom
}
///|
pub fn Rect::intersects(self : Rect, other : Rect) -> Bool {
!self.is_empty() &&
!other.is_empty() &&
self.left < other.right &&
other.left < self.right &&
self.top < other.bottom &&
other.top < self.bottom
}
///|
pub fn Rect::offset(self : Rect, dx : Scalar, dy : Scalar) -> Rect {
Rect::new(self.left + dx, self.top + dy, self.right + dx, self.bottom + dy)
}
///|
pub fn Rect::with_offset(self : Rect, offset : Point) -> Rect {
self.offset(offset.x, offset.y)
}
///|
pub fn Rect::with_offset_to(self : Rect, point : Point) -> Rect {
Rect::from_xywh(point.x, point.y, self.width(), self.height())
}
///|
pub fn Rect::inset(self : Rect, dx : Scalar, dy : Scalar) -> Rect {
Rect::new(self.left + dx, self.top + dy, self.right - dx, self.bottom - dy)
}
///|
pub fn Rect::with_inset(self : Rect, inset : Size) -> Rect {
self.inset(inset.width, inset.height)
}
///|
pub fn Rect::outset(self : Rect, dx : Scalar, dy : Scalar) -> Rect {
self.inset(-dx, -dy)
}
///|
pub fn Rect::with_outset(self : Rect, outset : Size) -> Rect {
self.outset(outset.width, outset.height)
}
///|
pub fn Rect::sorted(self : Rect) -> Rect {
Rect::new(
Float::min(self.left, self.right),
Float::min(self.top, self.bottom),
Float::max(self.left, self.right),
Float::max(self.top, self.bottom),
)
}
///|
pub fn Rect::intersect(self : Rect, other : Rect) -> Rect? {
let result = Rect::new(
Float::max(self.left, other.left),
Float::max(self.top, other.top),
Float::min(self.right, other.right),
Float::min(self.bottom, other.bottom),
)
if result.is_empty() {
None
} else {
Some(result)
}
}
///|
pub fn Rect::join(self : Rect, other : Rect) -> Rect {
if self.is_empty() {
other
} else if other.is_empty() {
self
} else {
Rect::new(
Float::min(self.left, other.left),
Float::min(self.top, other.top),
Float::max(self.right, other.right),
Float::max(self.bottom, other.bottom),
)
}
}
///|
pub fn Rect::round(self : Rect) -> IRect {
IRect::new(
self.left.round().to_int(),
self.top.round().to_int(),
self.right.round().to_int(),
self.bottom.round().to_int(),
)
}
///|
pub fn Rect::round_in(self : Rect) -> IRect {
IRect::new(
self.left.ceil().to_int(),
self.top.ceil().to_int(),
self.right.floor().to_int(),
self.bottom.floor().to_int(),
)
}
///|
pub fn Rect::round_out(self : Rect) -> IRect {
IRect::new(
self.left.floor().to_int(),
self.top.floor().to_int(),
self.right.ceil().to_int(),
self.bottom.ceil().to_int(),
)
}
///|
pub fn Rect::to_irect_round(self : Rect) -> IRect {
self.round()
}
///|
/// Rounded rectangle bounds plus per-corner x/y radii.
///
/// Corners are stored in Skia order: upper-left, upper-right, lower-right,
/// lower-left.
pub(all) struct RRect {
rect : Rect
upper_left : Size
upper_right : Size
lower_right : Size
lower_left : Size
} derive(Debug, Eq)
///|
fn normalize_rrect_radius(radius : Size) -> Size {
if radius.width <= 0.0 || radius.height <= 0.0 {
Size::empty()
} else {
radius
}
}
///|
fn scale_rrect_radius(radius : Size, scale : Scalar) -> Size {
Size::new(radius.width * scale, radius.height * scale)
}
///|
pub fn RRect::new(
rect : Rect,
upper_left : Size,
upper_right : Size,
lower_right : Size,
lower_left : Size,
) -> RRect {
let rect = rect.sorted()
if rect.is_empty() {
RRect::empty()
} else {
let upper_left = normalize_rrect_radius(upper_left)
let upper_right = normalize_rrect_radius(upper_right)
let lower_right = normalize_rrect_radius(lower_right)
let lower_left = normalize_rrect_radius(lower_left)
let width = rect.width()
let height = rect.height()
let top_width = upper_left.width + upper_right.width
let bottom_width = lower_left.width + lower_right.width
let left_height = upper_left.height + lower_left.height
let right_height = upper_right.height + lower_right.height
let scale : Scalar = 1.0
let scale = if top_width > width && top_width > 0.0 {
Float::min(scale, width / top_width)
} else {
scale
}
let scale = if bottom_width > width && bottom_width > 0.0 {
Float::min(scale, width / bottom_width)
} else {
scale
}
let scale = if left_height > height && left_height > 0.0 {
Float::min(scale, height / left_height)
} else {
scale
}
let scale = if right_height > height && right_height > 0.0 {
Float::min(scale, height / right_height)
} else {
scale
}
{
rect,
upper_left: scale_rrect_radius(upper_left, scale),
upper_right: scale_rrect_radius(upper_right, scale),
lower_right: scale_rrect_radius(lower_right, scale),
lower_left: scale_rrect_radius(lower_left, scale),
}
}
}
///|
pub fn RRect::empty() -> RRect {
{
rect: Rect::empty(),
upper_left: Size::empty(),
upper_right: Size::empty(),
lower_right: Size::empty(),
lower_left: Size::empty(),
}
}
///|
pub fn RRect::from_rect(rect : Rect) -> RRect {
RRect::new(rect, Size::empty(), Size::empty(), Size::empty(), Size::empty())
}
///|
pub fn RRect::from_rect_xy(rect : Rect, rx : Scalar, ry : Scalar) -> RRect {
let radius = Size::new(rx, ry)
RRect::new(rect, radius, radius, radius, radius)
}
///|
pub fn RRect::from_oval(oval : Rect) -> RRect {
let oval = oval.sorted()
if oval.is_empty() {
RRect::empty()
} else {
RRect::from_rect_xy(oval, oval.width() / 2.0, oval.height() / 2.0)
}
}
///|
pub impl Default for RRect with fn default() {
RRect::empty()
}
///|
pub fn RRect::bounds(self : RRect) -> Rect {
self.rect
}
///|
pub fn RRect::width(self : RRect) -> Scalar {
self.rect.width()
}
///|
pub fn RRect::height(self : RRect) -> Scalar {
self.rect.height()
}
///|
pub fn RRect::is_empty(self : RRect) -> Bool {
self.rect.is_empty()
}
///|
pub fn RRect::is_rect(self : RRect) -> Bool {
!self.is_empty() &&
self.upper_left.is_zero() &&
self.upper_right.is_zero() &&
self.lower_right.is_zero() &&
self.lower_left.is_zero()
}
///|
pub fn RRect::is_simple(self : RRect) -> Bool {
!self.is_empty() &&
!self.is_rect() &&
!self.is_oval() &&
self.upper_left == self.upper_right &&
self.upper_left == self.lower_right &&
self.upper_left == self.lower_left
}
///|
pub fn RRect::is_oval(self : RRect) -> Bool {
!self.is_empty() &&
self.upper_left == Size::new(self.width() / 2.0, self.height() / 2.0) &&
self.upper_left == self.upper_right &&
self.upper_left == self.lower_right &&
self.upper_left == self.lower_left
}
///|
pub fn RRect::offset(self : RRect, dx : Scalar, dy : Scalar) -> RRect {
RRect::new(
self.rect.offset(dx, dy),
self.upper_left,
self.upper_right,
self.lower_right,
self.lower_left,
)
}
///|
pub fn RRect::with_offset(self : RRect, delta : Point) -> RRect {
self.offset(delta.x, delta.y)
}
///|
pub fn RRect::with_offset_to(self : RRect, point : Point) -> RRect {
let rect = self.bounds()
self.with_offset(Point::new(point.x - rect.x(), point.y - rect.y()))
}
///|
pub fn RRect::with_inset(self : RRect, inset : Size) -> RRect {
RRect::new(
self.bounds().with_inset(inset),
Size::new(
Float::max(self.upper_left.width - inset.width, 0.0),
Float::max(self.upper_left.height - inset.height, 0.0),
),
Size::new(
Float::max(self.upper_right.width - inset.width, 0.0),
Float::max(self.upper_right.height - inset.height, 0.0),
),
Size::new(
Float::max(self.lower_right.width - inset.width, 0.0),
Float::max(self.lower_right.height - inset.height, 0.0),
),
Size::new(
Float::max(self.lower_left.width - inset.width, 0.0),
Float::max(self.lower_left.height - inset.height, 0.0),
),
)
}
///|
pub fn RRect::with_outset(self : RRect, outset : Size) -> RRect {
RRect::new(
self.bounds().with_outset(outset),
Size::new(
self.upper_left.width + outset.width,
self.upper_left.height + outset.height,
),
Size::new(
self.upper_right.width + outset.width,
self.upper_right.height + outset.height,
),
Size::new(
self.lower_right.width + outset.width,
self.lower_right.height + outset.height,
),
Size::new(
self.lower_left.width + outset.width,
self.lower_left.height + outset.height,
),
)
}
///|
pub fn RRect::contains_rect(self : RRect, rect : Rect) -> Bool {
let rect = rect.sorted()
if self.is_empty() || rect.is_empty() || !self.bounds().contains_rect(rect) {
false
} else {
self.contains_xy(rect.left, rect.top) &&
self.contains_xy(rect.right, rect.top) &&
self.contains_xy(rect.right, rect.bottom) &&
self.contains_xy(rect.left, rect.bottom)
}
}
///|
fn RRect::contains_xy(self : RRect, x : Scalar, y : Scalar) -> Bool {
let rect = self.bounds()
let left = rect.left
let top = rect.top
let right = rect.right
let bottom = rect.bottom
if x < left || x > right || y < top || y > bottom {
false
} else {
let contains_corner = fn(
corner_x : Scalar,
corner_y : Scalar,
radius : Size,
) -> Bool {
if radius.is_zero() {
true
} else {
let dx = x - corner_x
let dy = y - corner_y
dx * dx / (radius.width * radius.width) +
dy * dy / (radius.height * radius.height) <=
1.0
}
}
if x < left + self.upper_left.width && y < top + self.upper_left.height {
contains_corner(
left + self.upper_left.width,
top + self.upper_left.height,
self.upper_left,
)
} else if x > right - self.upper_right.width &&
y < top + self.upper_right.height {
contains_corner(
right - self.upper_right.width,
top + self.upper_right.height,
self.upper_right,
)
} else if x > right - self.lower_right.width &&
y > bottom - self.lower_right.height {
contains_corner(
right - self.lower_right.width,
bottom - self.lower_right.height,
self.lower_right,
)
} else if x < left + self.lower_left.width &&
y > bottom - self.lower_left.height {
contains_corner(
left + self.lower_left.width,
bottom - self.lower_left.height,
self.lower_left,
)
} else {
true
}
}
}