///|
/// Boolean polygon operation used by cpdf's GPC-backed clipping helpers.
pub(all) enum PdfClipOperation {
PdfClipDifference
PdfClipIntersection
PdfClipExclusiveOr
PdfClipUnion
} derive(Debug, Eq, ToJson)
///|
/// A vertex in a cpdf/GPC polygon contour.
pub(all) struct PdfClipVertex {
x : Double
y : Double
} derive(Debug, Eq, ToJson)
///|
/// One contour in a cpdf/GPC polygon.
///
/// `hole=true` matches cpdf's `1` hole flag. `hole=false` matches cpdf's `0`
/// exterior-contour flag.
pub(all) struct PdfClipContour {
hole : Bool
vertices : Array[PdfClipVertex]
} derive(Debug, Eq, ToJson)
///|
/// A cpdf/GPC polygon represented as an ordered list of contours.
pub(all) struct PdfClipPolygon {
contours : Array[PdfClipContour]
} derive(Debug, Eq, ToJson)
///|
/// Build a cpdf/GPC polygon vertex.
pub fn pdf_clip_vertex(x : Double, y : Double) -> PdfClipVertex {
{ x, y }
}
///|
/// Build a cpdf/GPC polygon contour, copying the input vertex view.
pub fn pdf_clip_contour(
hole : Bool,
vertices : ArrayView[PdfClipVertex],
) -> PdfClipContour {
{ hole, vertices: vertices.to_owned() }
}
///|
/// Build a cpdf/GPC polygon, copying the input contours and their vertices.
pub fn pdf_clip_polygon(contours : ArrayView[PdfClipContour]) -> PdfClipPolygon {
let copied : Array[PdfClipContour] = []
for contour in contours {
copied.push(pdf_clip_contour(contour.hole, contour.vertices))
}
{ contours: copied }
}
///|
/// Return the cpdf null GPC polygon.
pub fn pdf_clip_null_polygon() -> PdfClipPolygon {
{ contours: [] }
}
///|
/// Number of contours in this polygon.
pub fn PdfClipPolygon::num_contours(self : PdfClipPolygon) -> Int {
self.contours.length()
}
///|
/// Number of vertices in this contour.
pub fn PdfClipContour::num_vertices(self : PdfClipContour) -> Int {
self.vertices.length()
}
///|
/// Return cpdf's integer hole flag for this contour.
pub fn PdfClipContour::hole_flag(self : PdfClipContour) -> Int {
if self.hole {
1
} else {
0
}
}
///|
/// Return the integer operation code used by cpdf's GPC binding.
pub fn PdfClipOperation::gpc_code(self : PdfClipOperation) -> Int {
match self {
PdfClipDifference => 0
PdfClipIntersection => 1
PdfClipExclusiveOr => 2
PdfClipUnion => 3
}
}
///|
/// Build the cpdf/GPC rectangle polygon for `[xmin, xmax] x [ymin, ymax]`.
pub fn pdf_clip_polygon_of_box(
xmin : Double,
xmax : Double,
ymin : Double,
ymax : Double,
) -> PdfClipPolygon {
pdf_clip_polygon([
pdf_clip_contour(false, [
pdf_clip_vertex(xmin, ymin),
pdf_clip_vertex(xmax, ymin),
pdf_clip_vertex(xmax, ymax),
pdf_clip_vertex(xmin, ymax),
]),
])
}
///|
/// Build a cpdf/GPC polygon from parallel hole flags and vertex arrays.
///
/// Raises `PdfError::BadNumberArgument` when the inputs have different lengths.
pub fn pdf_clip_make_polygon(
holes : ArrayView[Bool],
vertex_arrays : ArrayView[Array[PdfClipVertex]],
) -> PdfClipPolygon raise PdfError {
if holes.length() != vertex_arrays.length() {
raise BadNumberArgument("pdf_clip_make_polygon: unequal length inputs")
}
let contours : Array[PdfClipContour] = []
for index in 0..