///|
fn pdf_path_min_double(left : Double, right : Double) -> Double {
if left < right {
left
} else {
right
}
}
///|
fn pdf_path_max_double(left : Double, right : Double) -> Double {
if left > right {
left
} else {
right
}
}
///|
fn pdf_path_bounds_of_points(
p0 : Point2,
p1 : Point2,
p2 : Point2,
p3 : Point2,
) -> PdfRectangle {
{
min_x: pdf_path_min_double(
pdf_path_min_double(p0.x, p1.x),
pdf_path_min_double(p2.x, p3.x),
),
min_y: pdf_path_min_double(
pdf_path_min_double(p0.y, p1.y),
pdf_path_min_double(p2.y, p3.y),
),
max_x: pdf_path_max_double(
pdf_path_max_double(p0.x, p1.x),
pdf_path_max_double(p2.x, p3.x),
),
max_y: pdf_path_max_double(
pdf_path_max_double(p0.y, p1.y),
pdf_path_max_double(p2.y, p3.y),
),
}
}
///|
fn pdf_path_union_bounds(
left : PdfRectangle,
right : PdfRectangle,
) -> PdfRectangle {
{
min_x: pdf_path_min_double(left.min_x, right.min_x),
min_y: pdf_path_min_double(left.min_y, right.min_y),
max_x: pdf_path_max_double(left.max_x, right.max_x),
max_y: pdf_path_max_double(left.max_y, right.max_y),
}
}
///|
/// Return cpdfcontent's control-point bounding box for a path segment.
///
/// Bezier bounds intentionally include the two control points rather than
/// solving for curve extrema, matching `cpdfcontent.ml`'s `bbox_of_segment`.
pub fn PdfPathSegment::bounds(self : PdfPathSegment) -> PdfRectangle {
match self {
PdfPathStraight(start, finish) =>
pdf_path_bounds_of_points(start, finish, start, finish)
PdfPathBezier(start, control1, control2, finish) =>
pdf_path_bounds_of_points(start, control1, control2, finish)
}
}
///|
/// Compatibility wrapper for `PdfPathSegment::bounds`.
pub fn pdf_path_segment_bounds(segment : PdfPathSegment) -> PdfRectangle {
segment.bounds()
}
///|
fn pdf_path_empty_bounds() -> PdfRectangle {
{ min_x: 0.0, min_y: 0.0, max_x: 0.0, max_y: 0.0, }
}
///|
/// Return cpdfcontent's axis-aligned bounding box for a path.
///
/// Empty paths return a zero rectangle, matching `cpdfcontent.ml`.
pub fn PdfPath::bounds(self : PdfPath) -> PdfRectangle {
let mut found = false
let mut bounds = pdf_path_empty_bounds()
for subpath in self.subpaths {
for segment in subpath.segments {
let segment_bounds = segment.bounds()
if found {
bounds = pdf_path_union_bounds(bounds, segment_bounds)
} else {
bounds = segment_bounds
found = true
}
}
}
bounds
}
///|
/// Compatibility wrapper for `PdfPath::bounds`.
pub fn pdf_path_bounds(path : PdfPath) -> PdfRectangle {
path.bounds()
}
///|
/// Return the bounds of a path, or `None` when it has no drawable segments.
pub fn PdfPath::pdf_path_bounds_optional(self : PdfPath) -> PdfRectangle? {
let mut found = false
let mut bounds = pdf_path_empty_bounds()
for subpath in self.subpaths {
for segment in subpath.segments {
let segment_bounds = segment.bounds()
if found {
bounds = pdf_path_union_bounds(bounds, segment_bounds)
} else {
bounds = segment_bounds
found = true
}
}
}
if found {
Some(bounds)
} else {
None
}
}