///|
/// 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 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 default() {
Point::zero()
}
///|
pub fn Point::is_zero(self : Point) -> Bool {
self.x == 0 && self.y == 0
}
///|
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::length(self : Point) -> Scalar {
(self.x * self.x + self.y * self.y).sqrt()
}
///|
pub fn Point::distance_to_origin(self : Point) -> Scalar {
self.length()
}
///|
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 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 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::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::empty() -> IRect {
IRect::new(0, 0, 0, 0)
}
///|
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 impl Default for IRect with default() {
IRect::empty()
}
///|
pub fn IRect::width(self : IRect) -> Int {
self.right - self.left
}
///|
pub fn IRect::height(self : IRect) -> Int {
self.bottom - self.top
}
///|
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::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::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::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::outset(self : IRect, dx : Int, dy : Int) -> IRect {
self.inset(-dx, -dy)
}
///|
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::empty() -> Rect {
Rect::new(0, 0, 0, 0)
}
///|
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 impl Default for Rect with default() {
Rect::empty()
}
///|
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::is_empty(self : Rect) -> Bool {
self.right <= self.left || self.bottom <= self.top
}
///|
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::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::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::outset(self : Rect, dx : Scalar, dy : Scalar) -> Rect {
self.inset(-dx, -dy)
}
///|
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::to_irect_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(),
)
}
///|
/// 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 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 {
{ ..self, rect: self.rect.offset(dx, dy) }
}