#![allow(clippy::let_and_return)]
use crate::geo_point_as;
use crate::prelude::*;
use geo::point;
use std::cmp::{max, min};
pub fn make_actual_shape(
shape: &IRect,
parent_actual_shape: &U16Rect,
) -> U16Rect {
let parent_actual_top_left_pos: U16Pos = parent_actual_shape.min().into();
let parent_actual_top_left_ipos: IPos =
geo_point_as!(parent_actual_top_left_pos, isize);
let parent_actual_bottom_right_pos: U16Pos = parent_actual_shape.max().into();
let parent_actual_bottom_right_ipos: IPos =
geo_point_as!(parent_actual_bottom_right_pos, isize);
let top_left_pos: IPos = shape.min().into();
let bottom_right_pos: IPos = shape.max().into();
let actual_top_left_ipos: IPos = top_left_pos + parent_actual_top_left_ipos;
let actual_top_left_x = min(
max(actual_top_left_ipos.x(), parent_actual_top_left_ipos.x()),
parent_actual_bottom_right_ipos.x(),
);
let actual_top_left_y = min(
max(actual_top_left_ipos.y(), parent_actual_top_left_ipos.y()),
parent_actual_bottom_right_ipos.y(),
);
let actual_top_left_pos: U16Pos =
point!(x: actual_top_left_x as u16, y: actual_top_left_y as u16);
let actual_bottom_right_ipos: IPos =
bottom_right_pos + parent_actual_top_left_ipos;
let actual_bottom_right_x = min(
max(
actual_bottom_right_ipos.x(),
parent_actual_top_left_ipos.x(),
),
parent_actual_bottom_right_ipos.x(),
);
let actual_bottom_right_y = min(
max(
actual_bottom_right_ipos.y(),
parent_actual_top_left_ipos.y(),
),
parent_actual_bottom_right_ipos.y(),
);
let actual_bottom_right_pos: U16Pos =
point!(x: actual_bottom_right_x as u16, y: actual_bottom_right_y as u16);
let actual_isize = ISize::new(
(actual_bottom_right_pos.x() as isize) - (actual_top_left_pos.x() as isize),
(actual_bottom_right_pos.y() as isize) - (actual_top_left_pos.y() as isize),
);
let actual_shape = U16Rect::new(
actual_top_left_pos,
point!(x: actual_top_left_pos.x() + actual_isize.width() as u16, y: actual_top_left_pos.y() + actual_isize.height() as u16),
);
actual_shape
}
pub fn bound_size(shape: &IRect, parent_actual_shape: &U16Rect) -> IRect {
use std::cmp::{max, min};
let top_left_pos: IPos = shape.min().into();
let height = max(
min(shape.height(), parent_actual_shape.height() as isize),
0,
);
let width = max(min(shape.width(), parent_actual_shape.width() as isize), 0);
IRect::new(
top_left_pos,
point!(x: top_left_pos.x() + width, y: top_left_pos.y() + height),
)
}
pub fn bound_position(shape: &IRect, parent_actual_shape: &U16Rect) -> IRect {
let top_left_pos: IPos = shape.min().into();
let bottom_right_pos: IPos = shape.max().into();
let top_left_x = if top_left_pos.x() < 0 {
0
} else if bottom_right_pos.x() > parent_actual_shape.width() as isize {
let x_diff = num_traits::sign::abs_sub(
bottom_right_pos.x(),
parent_actual_shape.width() as isize,
);
let result = top_left_pos.x() - x_diff;
result
} else {
top_left_pos.x()
};
let top_left_y = if top_left_pos.y() < 0 {
0
} else if bottom_right_pos.y() > parent_actual_shape.height() as isize {
let y_diff = num_traits::sign::abs_sub(
bottom_right_pos.y(),
parent_actual_shape.height() as isize,
);
let result = top_left_pos.y() - y_diff;
result
} else {
top_left_pos.y()
};
IRect::new(
(top_left_x, top_left_y),
(top_left_x + shape.width(), top_left_y + shape.height()),
)
}
pub fn bound_shape(shape: &IRect, parent_actual_shape: &U16Rect) -> IRect {
let bounded = bound_size(shape, parent_actual_shape);
bound_position(&bounded, parent_actual_shape)
}