summaryrefslogtreecommitdiff
path: root/fpdf.go
diff options
context:
space:
mode:
Diffstat (limited to 'fpdf.go')
-rw-r--r--fpdf.go164
1 files changed, 105 insertions, 59 deletions
diff --git a/fpdf.go b/fpdf.go
index 6c21210..ea4b384 100644
--- a/fpdf.go
+++ b/fpdf.go
@@ -907,7 +907,7 @@ func (f *Fpdf) Circle(x, y, r float64, styleStr string) {
//
// See tutorial 11 for an example of this function.
func (f *Fpdf) Ellipse(x, y, rx, ry, degRotate float64, styleStr string) {
- f.Arc(x, y, rx, ry, degRotate, 0, 360, styleStr)
+ f.arc(x, y, rx, ry, degRotate, 0, 360, styleStr, false)
}
// Polygon draws a closed figure defined by a series of vertices specified by
@@ -1047,54 +1047,7 @@ func (f *Fpdf) CurveBezierCubic(x0, y0, cx0, cy0, cx1, cy1, x1, y1 float64, styl
//
// See tutorial 11 for an example of this function.
func (f *Fpdf) Arc(x, y, rx, ry, degRotate, degStart, degEnd float64, styleStr string) {
- x *= f.k
- y = (f.h - y) * f.k
- rx *= f.k
- ry *= f.k
- segments := int(degEnd-degStart) / 60
- if segments < 2 {
- segments = 2
- }
- angleStart := degStart * math.Pi / 180
- angleEnd := degEnd * math.Pi / 180
- angleTotal := angleEnd - angleStart
- dt := angleTotal / float64(segments)
- dtm := dt / 3
- if degRotate != 0 {
- a := -degRotate * math.Pi / 180
- f.outf("q %.5f %.5f %.5f %.5f %.5f %.5f cm", math.Cos(a), -1*math.Sin(a),
- math.Sin(a), math.Cos(a), x, y)
- x = 0
- y = 0
- }
- t := angleStart
- a0 := x + rx*math.Cos(t)
- b0 := y + ry*math.Sin(t)
- c0 := -rx * math.Sin(t)
- d0 := ry * math.Cos(t)
- f.point(a0/f.k, f.h-(b0/f.k))
- for j := 1; j <= segments; j++ {
- // Draw this bit of the total curve
- t = (float64(j) * dt) + angleStart
- a1 := x + rx*math.Cos(t)
- b1 := y + ry*math.Sin(t)
- c1 := -rx * math.Sin(t)
- d1 := ry * math.Cos(t)
- f.curve((a0+(c0*dtm))/f.k,
- f.h-((b0+(d0*dtm))/f.k),
- (a1-(c1*dtm))/f.k,
- f.h-((b1-(d1*dtm))/f.k),
- a1/f.k,
- f.h-(b1/f.k))
- a0 = a1
- b0 = b1
- c0 = c1
- d0 = d1
- }
- f.out(fillDrawOp(styleStr))
- if degRotate != 0 {
- f.out("Q")
- }
+ f.arc(x, y, rx, ry, degRotate, degStart, degEnd, styleStr, false)
}
// SetAlpha sets the alpha blending channel. The blending effect applies to
@@ -3487,19 +3440,22 @@ func (f *Fpdf) enddoc() {
}
// Path Drawing
-//
-// Create a "path" by moving a virtual stylus around the page, then draw it or
-// fill it in. The main advantage of using the path drawing routines rather
-// than multiple Fpdf.Line is that PDF creates nice line joins at the angles,
-// rather than just overlaying the lines.
-// MoveTo moves the stylus to (x, y) without drawing the path from the previous
-// point. Paths must start with a MoveTo to set the original stylus location or
-// the result is undefined.
+// MoveTo moves the stylus to (x, y) without drawing the path from the
+// previous point. Paths must start with a MoveTo to set the original
+// stylus location or the result is undefined.
+//
+// Create a "path" by moving a virtual stylus around the page (with
+// MoveTo, LineTo, CurveTo, CurveBezierCubicTo, ArcTo & ClosePath)
+// then draw it or fill it in (with DrawPath). The main advantage of
+// using the path drawing routines rather than multiple Fpdf.Line is
+// that PDF creates nice line joins at the angles, rather than just
+// overlaying the lines.
//
// See tutorial 30 for an example of this function.
func (f *Fpdf) MoveTo(x, y float64) {
- f.point(x, y) // rename?
+ f.point(x, y)
+ f.x, f.y = x, y
}
// LineTo creates a line from the current stylus location to (x, y), which
@@ -3509,6 +3465,7 @@ func (f *Fpdf) MoveTo(x, y float64) {
// See tutorial 30 for an example of this function.
func (f *Fpdf) LineTo(x, y float64) {
f.outf("%.2f %.2f l", x*f.k, (f.h-y)*f.k)
+ f.x, f.y = x, y
}
// CurveTo creates a single-segment quadratic Bézier curve. The curve starts at
@@ -3521,6 +3478,7 @@ func (f *Fpdf) LineTo(x, y float64) {
// See tutorial 30 for an example of this function.
func (f *Fpdf) CurveTo(cx, cy, x, y float64) {
f.outf("%.5f %.5f %.5f %.5f v", cx*f.k, (f.h-cy)*f.k, x*f.k, (f.h-y)*f.k)
+ f.x, f.y = x, y
}
// CurveBezierCubicTo creates a single-segment cubic Bézier curve. The curve
@@ -3533,7 +3491,8 @@ func (f *Fpdf) CurveTo(cx, cy, x, y float64) {
//
// See tutorial 30 for examples of this function.
func (f *Fpdf) CurveBezierCubicTo(cx0, cy0, cx1, cy1, x, y float64) {
- f.curve(cx0, cy0, cx1, cy1, x, y) // rename?
+ f.curve(cx0, cy0, cx1, cy1, x, y)
+ f.x, f.y = x, y
}
// ClosePath creates a line from the current location to the last MoveTo point
@@ -3556,3 +3515,90 @@ func (f *Fpdf) ClosePath() {
func (f *Fpdf) DrawPath(styleStr string) {
f.outf(fillDrawOp(styleStr))
}
+
+// ArcTo draws an elliptical arc centered at point (x, y). rx and ry specify its
+// horizontal and vertical radii. If the start of the arc is not at
+// the current position, a connecting line will be drawn.
+//
+// degRotate specifies the angle that the arc will be rotated. degStart and
+// degEnd specify the starting and ending angle of the arc. All angles are
+// specified in degrees and measured counter-clockwise from the 3 o'clock
+// position.
+//
+// styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for
+// outlined and filled. An empty string will be replaced with "D". Drawing uses
+// the current draw color, line width, and cap style centered on the arc's
+// path. Filling uses the current fill color.
+//
+// See tutorial 30 for an example of this function.
+func (f *Fpdf) ArcTo(x, y, rx, ry, degRotate, degStart, degEnd float64) {
+ f.arc(x, y, rx, ry, degRotate, degStart, degEnd, "", true)
+}
+
+func (f *Fpdf) arc(x, y, rx, ry, degRotate, degStart, degEnd float64,
+ styleStr string, path bool) {
+ x *= f.k
+ y = (f.h - y) * f.k
+ rx *= f.k
+ ry *= f.k
+ segments := int(degEnd-degStart) / 60
+ if segments < 2 {
+ segments = 2
+ }
+ angleStart := degStart * math.Pi / 180
+ angleEnd := degEnd * math.Pi / 180
+ angleTotal := angleEnd - angleStart
+ dt := angleTotal / float64(segments)
+ dtm := dt / 3
+ if degRotate != 0 {
+ a := -degRotate * math.Pi / 180
+ f.outf("q %.5f %.5f %.5f %.5f %.5f %.5f cm",
+ math.Cos(a), -1*math.Sin(a),
+ math.Sin(a), math.Cos(a), x, y)
+ x = 0
+ y = 0
+ }
+ t := angleStart
+ a0 := x + rx*math.Cos(t)
+ b0 := y + ry*math.Sin(t)
+ c0 := -rx * math.Sin(t)
+ d0 := ry * math.Cos(t)
+ sx := a0 / f.k // start point of arc
+ sy := f.h - (b0 / f.k)
+ if path {
+ if f.x != sx || f.y != sy {
+ // Draw connecting line to start point
+ f.LineTo(sx, sy)
+ }
+ } else {
+ f.point(sx, sy)
+ }
+ for j := 1; j <= segments; j++ {
+ // Draw this bit of the total curve
+ t = (float64(j) * dt) + angleStart
+ a1 := x + rx*math.Cos(t)
+ b1 := y + ry*math.Sin(t)
+ c1 := -rx * math.Sin(t)
+ d1 := ry * math.Cos(t)
+ f.curve((a0+(c0*dtm))/f.k,
+ f.h-((b0+(d0*dtm))/f.k),
+ (a1-(c1*dtm))/f.k,
+ f.h-((b1-(d1*dtm))/f.k),
+ a1/f.k,
+ f.h-(b1/f.k))
+ a0 = a1
+ b0 = b1
+ c0 = c1
+ d0 = d1
+ if path {
+ f.x = a1 / f.k
+ f.y = f.h - (b1 / f.k)
+ }
+ }
+ if !path {
+ f.out(fillDrawOp(styleStr))
+ }
+ if degRotate != 0 {
+ f.out("Q")
+ }
+}