Go CLI that turns the markdown currency of this stack (Redmine notes, Discourse posts, briefing output) into typeset PDFs: two embedded typst templates (report with title page/TOC/headers, dense brief), front-matter (title/subtitle/author/date/classification/template), GFM tables, and bar charts rendered in pure Go (go-chart) from fenced chart data blocks. Engine is a prebuilt typst 0.15.1 container pinned by digest and run --network none; PDF bytes to stdout or -o. Exit codes 0/1/2. All dev in docker (dev.sh/Makefile); unit tests + golden typst fixtures plus a host-side smoke against the real engine container. Generated with Crush Assisted-by: Crush:glm-5.2
90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
package drawing
|
|
|
|
// NewDashVertexConverter creates a new dash converter.
|
|
func NewDashVertexConverter(dash []float64, dashOffset float64, flattener Flattener) *DashVertexConverter {
|
|
var dasher DashVertexConverter
|
|
dasher.dash = dash
|
|
dasher.currentDash = 0
|
|
dasher.dashOffset = dashOffset
|
|
dasher.next = flattener
|
|
return &dasher
|
|
}
|
|
|
|
// DashVertexConverter is a converter for dash vertexes.
|
|
type DashVertexConverter struct {
|
|
next Flattener
|
|
x, y, distance float64
|
|
dash []float64
|
|
currentDash int
|
|
dashOffset float64
|
|
}
|
|
|
|
// LineTo implements the pathbuilder interface.
|
|
func (dasher *DashVertexConverter) LineTo(x, y float64) {
|
|
dasher.lineTo(x, y)
|
|
}
|
|
|
|
// MoveTo implements the pathbuilder interface.
|
|
func (dasher *DashVertexConverter) MoveTo(x, y float64) {
|
|
dasher.next.MoveTo(x, y)
|
|
dasher.x, dasher.y = x, y
|
|
dasher.distance = dasher.dashOffset
|
|
dasher.currentDash = 0
|
|
}
|
|
|
|
// LineJoin implements the pathbuilder interface.
|
|
func (dasher *DashVertexConverter) LineJoin() {
|
|
dasher.next.LineJoin()
|
|
}
|
|
|
|
// Close implements the pathbuilder interface.
|
|
func (dasher *DashVertexConverter) Close() {
|
|
dasher.next.Close()
|
|
}
|
|
|
|
// End implements the pathbuilder interface.
|
|
func (dasher *DashVertexConverter) End() {
|
|
dasher.next.End()
|
|
}
|
|
|
|
func (dasher *DashVertexConverter) lineTo(x, y float64) {
|
|
rest := dasher.dash[dasher.currentDash] - dasher.distance
|
|
for rest < 0 {
|
|
dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
|
|
dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
|
|
rest = dasher.dash[dasher.currentDash] - dasher.distance
|
|
}
|
|
d := distance(dasher.x, dasher.y, x, y)
|
|
for d >= rest {
|
|
k := rest / d
|
|
lx := dasher.x + k*(x-dasher.x)
|
|
ly := dasher.y + k*(y-dasher.y)
|
|
if dasher.currentDash%2 == 0 {
|
|
// line
|
|
dasher.next.LineTo(lx, ly)
|
|
} else {
|
|
// gap
|
|
dasher.next.End()
|
|
dasher.next.MoveTo(lx, ly)
|
|
}
|
|
d = d - rest
|
|
dasher.x, dasher.y = lx, ly
|
|
dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
|
|
rest = dasher.dash[dasher.currentDash]
|
|
}
|
|
dasher.distance = d
|
|
if dasher.currentDash%2 == 0 {
|
|
// line
|
|
dasher.next.LineTo(x, y)
|
|
} else {
|
|
// gap
|
|
dasher.next.End()
|
|
dasher.next.MoveTo(x, y)
|
|
}
|
|
if dasher.distance >= dasher.dash[dasher.currentDash] {
|
|
dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
|
|
dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
|
|
}
|
|
dasher.x, dasher.y = x, y
|
|
}
|