// Approximate a circular arc using multiple // cubic Bézier curves, one for each π/2 segment. // // This is from: // http://hansmuller-flex.blogspot.com/2011/04/approximating-circular-arc-with-cubic.html func arc(p *pdf.Path, comp vg.PathComp) { x0 := comp.X + comp.Radius*vg.Length(math.Cos(comp.Start)) y0 := comp.Y + comp.Radius*vg.Length(math.Sin(comp.Start)) p.Line(pdfPoint(x0, y0)) a1 := comp.Start end := a1 + comp.Angle sign := 1.0 if end < a1 { sign = -1.0 } left := math.Abs(comp.Angle) // Square root of the machine epsilon for IEEE 64-bit floating // point values. This is the equality threshold recommended // in Numerical Recipes, if I recall correctly—it's small enough. const epsilon = 1.4901161193847656e-08 for left > epsilon { a2 := a1 + sign*math.Min(math.Pi/2, left) partialArc(p, comp.X, comp.Y, comp.Radius, a1, a2) left -= math.Abs(a2 - a1) a1 = a2 } }
func main() { doc := pdf.New() canvas := doc.NewPage(pdf.USLetterWidth, pdf.USLetterHeight) canvas.Translate(500, 500) // canvas.SetColor(230, 100, 30) canvas.SetStrokeColor(20, 40, 60) path := new(pdf.Path) path.Move(pdf.Point{0, 0}) path.Line(pdf.Point{0, 50}) canvas.Stroke(path) text := new(pdf.Text) text.SetFont(pdf.Helvetica, 14) text.Text("Hello, World!") canvas.DrawText(text) canvas.Close() err := doc.Encode(os.Stdout) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }
func EngraveStaff(origin pdf.Point, width, height, lineWidth pdf.Unit, canvas *pdf.Canvas) { path := new(pdf.Path) noteHeight := pdf.Unit(height / 4) for i := 0; i < 5; i++ { path.Move(origin) path.Line(pdf.Point{origin.X + width, origin.Y}) origin.Y = origin.Y + noteHeight } canvas.Push() canvas.SetLineWidth(lineWidth) canvas.Stroke(path) canvas.Pop() }
// pdfPath returns a pdf.Path from a vg.Path. func pdfPath(c *Canvas, path vg.Path) *pdf.Path { p := new(pdf.Path) for _, comp := range path { switch comp.Type { case vg.MoveComp: p.Move(pdfPoint(comp.X, comp.Y)) case vg.LineComp: p.Line(pdfPoint(comp.X, comp.Y)) case vg.ArcComp: arc(p, comp) case vg.CloseComp: p.Close() default: panic(fmt.Sprintf("Unknown path component type: %d\n", comp.Type)) } } return p }
// Approximate a circular arc using multiple // cubic Bézier curves, one for each π/2 segment. // // This is from: // http://hansmuller-flex.blogspot.com/2011/04/approximating-circular-arc-with-cubic.html func arc(p *pdf.Path, comp vg.PathComp) { x0 := comp.X + comp.Radius*vg.Length(math.Cos(comp.Start)) y0 := comp.Y + comp.Radius*vg.Length(math.Sin(comp.Start)) p.Line(pdfPoint(x0, y0)) a1 := comp.Start end := a1 + comp.Angle sign := 1.0 if end < a1 { sign = -1.0 } left := math.Abs(comp.Angle) for left > 0 { a2 := a1 + sign*math.Min(math.Pi/2, left) partialArc(p, comp.X, comp.Y, comp.Radius, a1, a2) left -= math.Abs(a2 - a1) a1 = a2 } }
func EngraveSurrogateNoteHead(origin pdf.Point, size pdf.Unit, canvas *pdf.Canvas) { outline := new(pdf.Path) topRight := pdf.Point{origin.X + size, origin.Y + size} outline.Rectangle(pdf.Rectangle{origin, topRight}) mid := pdf.Point{origin.X + pdf.Unit(size/2), origin.Y + pdf.Unit(size/2)} midPoints := new(pdf.Path) midPoints.Move(pdf.Point{mid.X, origin.Y}) midPoints.Line(pdf.Point{mid.X, origin.Y + size}) midPoints.Move(pdf.Point{origin.X, mid.Y}) midPoints.Line(pdf.Point{origin.X + size, mid.Y}) canvas.Push() canvas.SetColor(0.6, 0.6, 0.6) canvas.Fill(outline) canvas.SetLineWidth(pdf.Unit(0.1)) canvas.Stroke(midPoints) canvas.Pop() }