///|
/// `ParamPair` represents an X,Y absolute coordinate pair of parameters.
pub(all) struct ParamPair {
x : Double
y : Double
} derive(Debug, Eq)
///|
/// `to_string` returns a string representation of a `ParamPair`.
pub fn ParamPair::to_string(self : ParamPair) -> String {
"(\{svg_num(self.x)},\{svg_num(self.y)})"
}
///|
pub impl Show for ParamPair with fn output(self, logger) {
logger.write_string(self.to_string())
}
///|
/// `PathCmd` represents an individual absolute SVG command.
pub(all) struct PathCmd {
cmd : AbsoluteCmd
gerber_lp : GerberLP
params : Array[ParamPair]
} derive(Debug, Eq)
///|
pub impl Show for PathCmd with fn output(self, logger) {
let { cmd, gerber_lp, params } = self
logger.write_string(
(
$|{cmd: \{cmd}, gerber_lp: \{gerber_lp}, params: \{Repr(params)}}
),
)
}
///|
test "PathCmd show interface" {
let cmd = { cmd: M, gerber_lp: Dark, params: [{ x: 10.0, y: 20.0 }] }
inspect(
cmd,
content=(
#|{cmd: M, gerber_lp: Dark, params: [{ x: 10, y: 20 }]}
),
)
}
///|
/// `from_svg_cmd` creates a `PathCmd` from a raw SVG command and a `GerberLP`.
pub fn PathCmd::from_svg_cmd(
svg_cmd : Cmd,
gerber_lp : GerberLP,
) -> PathCmd raise FontError {
let cmd = match svg_cmd.c {
"M" => M
"L" => L
"C" => C
"Q" => Q
"Z" => Z
c =>
raise FontError("PathCmd::from_svg_cmd: unsupported SVG command '\{c}'")
}
if svg_cmd.p.0.length() % 2 != 0 {
raise FontError(
"PathCmd::from_svg_cmd: unexpected odd params length in svg_cmd: \{svg_cmd}",
)
}
//
let params : Array[ParamPair] = Array::makei(svg_cmd.p.0.length() / 2, fn(i) {
let x = svg_cmd.p.0[i * 2]
let y = svg_cmd.p.0[i * 2 + 1]
{ x, y }
})
//
{ cmd, gerber_lp, params }
}
///|
/// `to_svg_cmd` converts a `PathCmd` back to a raw SVG command and its `GerberLP` code.
pub fn PathCmd::to_svg_cmd(self : PathCmd) -> (Cmd, String) {
let gerber_lp = match self.cmd {
M =>
match self.gerber_lp {
Dark => "d"
Clear => "c"
}
_ => ""
}
let p : Array[Double] = Array::makei(self.params.length() * 2, fn(i) {
let pp = self.params[i / 2]
if i % 2 == 0 {
pp.x
} else {
pp.y
}
})
let c = "\{self.cmd}"
let cmd = { c, p }
(cmd, gerber_lp)
}
///|
/// `bbox` returns the minimum bounding box of a `PathCmd`.
pub fn PathCmd::bbox(self : PathCmd) -> @geom.BoundingBox {
let r = @geom.BoundingBox::max_reversed()
for index, pp in self.params {
if index == 0 {
r.min.x = pp.x
r.min.y = pp.y
r.max.x = pp.x
r.max.y = pp.y
} else {
let _ = r.expand_to_include_point(@geom.pt(pp.x, pp.y))
}
}
r
}
///|
/// `PathCmdFn` represents a function that processes or transforms individual commands.
/// The first argument is the index within the command.
pub(all) struct PathCmdFn((Int, PathCmd) -> PathCmd)
///|
/// `clone` makes a deep copy of a `PathCmd`.
pub fn PathCmd::clone(self : PathCmd) -> PathCmd {
let params = Array::makei(self.params.length(), fn(i) {
let param = self.params[i]
{ x: param.x, y: param.y }
})
{ cmd: self.cmd, gerber_lp: self.gerber_lp, params }
}