fixed dependencies
This commit is contained in:
329
vendor/gonum.org/v1/plot/vg/vgtex/canvas.go
generated
vendored
Normal file
329
vendor/gonum.org/v1/plot/vg/vgtex/canvas.go
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
// Copyright ©2016 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package vgtex provides a vg.Canvas implementation for LaTeX, targeted at
|
||||
// the TikZ/PGF LaTeX package: https://sourceforge.net/projects/pgf
|
||||
//
|
||||
// vgtex generates PGF instructions that will be interpreted and rendered by LaTeX.
|
||||
// vgtex allows to put any valid LaTeX notation inside plot's strings.
|
||||
package vgtex // import "gonum.org/v1/plot/vg/vgtex"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gonum.org/v1/plot/font"
|
||||
"gonum.org/v1/plot/vg"
|
||||
"gonum.org/v1/plot/vg/draw"
|
||||
)
|
||||
|
||||
const degPerRadian = 180 / math.Pi
|
||||
|
||||
const (
|
||||
defaultHeader = `%%%%%% generated by gonum/plot %%%%%%
|
||||
\documentclass{standalone}
|
||||
\usepackage{pgf}
|
||||
\begin{document}
|
||||
`
|
||||
defaultFooter = "\\end{document}\n"
|
||||
)
|
||||
|
||||
func init() {
|
||||
draw.RegisterFormat("tex", func(w, h vg.Length) vg.CanvasWriterTo {
|
||||
return NewDocument(w, h)
|
||||
})
|
||||
}
|
||||
|
||||
// Canvas implements the vg.Canvas interface, translating drawing
|
||||
// primitives from gonum/plot to PGF.
|
||||
type Canvas struct {
|
||||
buf *bytes.Buffer
|
||||
w, h vg.Length
|
||||
stack []context
|
||||
|
||||
// If document is true, Canvas.WriteTo will generate a standalone
|
||||
// .tex file that can be fed to, e.g., pdflatex.
|
||||
document bool
|
||||
id int64 // id is a unique identifier for this canvas
|
||||
}
|
||||
|
||||
type context struct {
|
||||
color color.Color
|
||||
dashArray []vg.Length
|
||||
dashOffset vg.Length
|
||||
linew vg.Length
|
||||
}
|
||||
|
||||
// New returns a new LaTeX canvas.
|
||||
func New(w, h vg.Length) *Canvas {
|
||||
return newCanvas(w, h, false)
|
||||
}
|
||||
|
||||
// NewDocument returns a new LaTeX canvas that can be readily
|
||||
// compiled into a standalone document.
|
||||
func NewDocument(w, h vg.Length) *Canvas {
|
||||
return newCanvas(w, h, true)
|
||||
}
|
||||
|
||||
func newCanvas(w, h vg.Length, document bool) *Canvas {
|
||||
c := &Canvas{
|
||||
buf: new(bytes.Buffer),
|
||||
w: w,
|
||||
h: h,
|
||||
document: document,
|
||||
id: time.Now().UnixNano(),
|
||||
}
|
||||
if !document {
|
||||
c.wtex(`%%%% gonum/plot created for LaTeX/pgf`)
|
||||
c.wtex(`%%%% you need to add:`)
|
||||
c.wtex(`%%%% \usepackage{pgf}`)
|
||||
c.wtex(`%%%% to your LaTeX document`)
|
||||
}
|
||||
c.wtex("")
|
||||
c.wtex(`\begin{pgfpicture}`)
|
||||
c.stack = make([]context, 1)
|
||||
vg.Initialize(c)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Canvas) context() *context {
|
||||
return &c.stack[len(c.stack)-1]
|
||||
}
|
||||
|
||||
// Size returns the width and height of the canvas.
|
||||
func (c *Canvas) Size() (w, h vg.Length) {
|
||||
return c.w, c.h
|
||||
}
|
||||
|
||||
// SetLineWidth implements the vg.Canvas.SetLineWidth method.
|
||||
func (c *Canvas) SetLineWidth(w vg.Length) {
|
||||
c.context().linew = w
|
||||
}
|
||||
|
||||
// SetLineDash implements the vg.Canvas.SetLineDash method.
|
||||
func (c *Canvas) SetLineDash(pattern []vg.Length, offset vg.Length) {
|
||||
c.context().dashArray = pattern
|
||||
c.context().dashOffset = offset
|
||||
}
|
||||
|
||||
// SetColor implements the vg.Canvas.SetColor method.
|
||||
func (c *Canvas) SetColor(clr color.Color) {
|
||||
c.context().color = clr
|
||||
}
|
||||
|
||||
// Rotate implements the vg.Canvas.Rotate method.
|
||||
func (c *Canvas) Rotate(rad float64) {
|
||||
c.wtex(`\pgftransformrotate{%g}`, rad*degPerRadian)
|
||||
}
|
||||
|
||||
// Translate implements the vg.Canvas.Translate method.
|
||||
func (c *Canvas) Translate(pt vg.Point) {
|
||||
c.wtex(`\pgftransformshift{\pgfpoint{%gpt}{%gpt}}`, pt.X, pt.Y)
|
||||
}
|
||||
|
||||
// Scale implements the vg.Canvas.Scale method.
|
||||
func (c *Canvas) Scale(x, y float64) {
|
||||
c.wtex(`\pgftransformxscale{%g}`, x)
|
||||
c.wtex(`\pgftransformyscale{%g}`, y)
|
||||
}
|
||||
|
||||
// Push implements the vg.Canvas.Push method.
|
||||
func (c *Canvas) Push() {
|
||||
c.wtex(`\begin{pgfscope}`)
|
||||
c.stack = append(c.stack, *c.context())
|
||||
}
|
||||
|
||||
// Pop implements the vg.Canvas.Pop method.
|
||||
func (c *Canvas) Pop() {
|
||||
c.stack = c.stack[:len(c.stack)-1]
|
||||
c.wtex(`\end{pgfscope}`)
|
||||
c.wtex("")
|
||||
}
|
||||
|
||||
// Stroke implements the vg.Canvas.Stroke method.
|
||||
func (c *Canvas) Stroke(p vg.Path) {
|
||||
if c.context().linew <= 0 {
|
||||
return
|
||||
}
|
||||
c.Push()
|
||||
c.wstyle()
|
||||
c.wpath(p)
|
||||
c.wtex(`\pgfusepath{stroke}`)
|
||||
c.Pop()
|
||||
}
|
||||
|
||||
// Fill implements the vg.Canvas.Fill method.
|
||||
func (c *Canvas) Fill(p vg.Path) {
|
||||
c.Push()
|
||||
c.wstyle()
|
||||
c.wpath(p)
|
||||
c.wtex(`\pgfusepath{fill}`)
|
||||
c.Pop()
|
||||
}
|
||||
|
||||
// FillString implements the vg.Canvas.FillString method.
|
||||
func (c *Canvas) FillString(f font.Face, pt vg.Point, text string) {
|
||||
c.Push()
|
||||
c.wcolor()
|
||||
pt.X += 0.5 * f.Width(text)
|
||||
c.wtex(`\pgftext[base,at={\pgfpoint{%gpt}{%gpt}}]{{\fontsize{%gpt}{%gpt}\selectfont %s}}`, pt.X, pt.Y, f.Font.Size, f.Font.Size, text)
|
||||
c.Pop()
|
||||
}
|
||||
|
||||
// DrawImage implements the vg.Canvas.DrawImage method.
|
||||
// DrawImage will first save the image inside a PNG file and have the
|
||||
// generated LaTeX reference that file.
|
||||
// The file name will be "gonum-pgf-image-<canvas-id>-<time.Now()>.png
|
||||
func (c *Canvas) DrawImage(rect vg.Rectangle, img image.Image) {
|
||||
fname := fmt.Sprintf("gonum-pgf-image-%v-%v.png", c.id, time.Now().UnixNano())
|
||||
f, err := os.Create(fname)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
err = png.Encode(f, img)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("vgtex: error encoding image to PNG: %v", err))
|
||||
}
|
||||
|
||||
var (
|
||||
xmin = rect.Min.X
|
||||
ymin = rect.Min.Y
|
||||
width = rect.Size().X
|
||||
height = rect.Size().Y
|
||||
)
|
||||
c.wtex(`\pgftext[base,left,at=\pgfpoint{%gpt}{%gpt}]{\pgfimage[height=%gpt,width=%gpt]{%s}}`, xmin, ymin, height, width, fname)
|
||||
}
|
||||
|
||||
func (c *Canvas) indent(s string) string {
|
||||
return strings.Repeat(s, len(c.stack))
|
||||
}
|
||||
|
||||
func (c *Canvas) wtex(s string, args ...interface{}) {
|
||||
fmt.Fprintf(c.buf, c.indent(" ")+s+"\n", args...)
|
||||
}
|
||||
|
||||
func (c *Canvas) wstyle() {
|
||||
c.wdash()
|
||||
c.wlineWidth()
|
||||
c.wcolor()
|
||||
}
|
||||
|
||||
func (c *Canvas) wdash() {
|
||||
if len(c.context().dashArray) == 0 {
|
||||
c.wtex(`\pgfsetdash{}{0pt}`)
|
||||
return
|
||||
}
|
||||
str := `\pgfsetdash{`
|
||||
for _, d := range c.context().dashArray {
|
||||
str += fmt.Sprintf("{%gpt}", d)
|
||||
}
|
||||
str += fmt.Sprintf("}{%gpt}", c.context().dashOffset)
|
||||
c.wtex(str)
|
||||
}
|
||||
|
||||
func (c *Canvas) wlineWidth() {
|
||||
c.wtex(`\pgfsetlinewidth{%gpt}`, c.context().linew)
|
||||
}
|
||||
|
||||
func (c *Canvas) wcolor() {
|
||||
col := c.context().color
|
||||
if col == nil {
|
||||
col = color.Black
|
||||
}
|
||||
r, g, b, a := col.RGBA()
|
||||
// FIXME(sbinet) \color will last until the end of the current TeX group
|
||||
// use \pgfsetcolor and \pgfsetstrokecolor instead.
|
||||
// it needs a named color: define it on the fly (storing it at the beginning
|
||||
// of the document.)
|
||||
c.wtex(
|
||||
`\color[rgb]{%g,%g,%g}`,
|
||||
float64(r)/math.MaxUint16,
|
||||
float64(g)/math.MaxUint16,
|
||||
float64(b)/math.MaxUint16,
|
||||
)
|
||||
|
||||
opacity := float64(a) / math.MaxUint16
|
||||
c.wtex(`\pgfsetstrokeopacity{%g}`, opacity)
|
||||
c.wtex(`\pgfsetfillopacity{%g}`, opacity)
|
||||
}
|
||||
|
||||
func (c *Canvas) wpath(p vg.Path) {
|
||||
for _, comp := range p {
|
||||
switch comp.Type {
|
||||
case vg.MoveComp:
|
||||
c.wtex(`\pgfpathmoveto{\pgfpoint{%gpt}{%gpt}}`, comp.Pos.X, comp.Pos.Y)
|
||||
case vg.LineComp:
|
||||
c.wtex(`\pgflineto{\pgfpoint{%gpt}{%gpt}}`, comp.Pos.X, comp.Pos.Y)
|
||||
case vg.ArcComp:
|
||||
start := comp.Start * degPerRadian
|
||||
angle := comp.Angle * degPerRadian
|
||||
r := comp.Radius
|
||||
c.wtex(`\pgfpatharc{%g}{%g}{%gpt}`, start, angle, r)
|
||||
case vg.CurveComp:
|
||||
var a, b vg.Point
|
||||
switch len(comp.Control) {
|
||||
case 1:
|
||||
a = comp.Control[0]
|
||||
b = a
|
||||
case 2:
|
||||
a = comp.Control[0]
|
||||
b = comp.Control[1]
|
||||
default:
|
||||
panic("vgtex: invalid number of control points")
|
||||
}
|
||||
c.wtex(`\pgfcurveto{\pgfpoint{%gpt}{%gpt}}{\pgfpoint{%gpt}{%gpt}}{\pgfpoint{%gpt}{%gpt}}`,
|
||||
a.X, a.Y, b.X, b.Y, comp.Pos.X, comp.Pos.Y)
|
||||
case vg.CloseComp:
|
||||
c.wtex("%% path-close")
|
||||
default:
|
||||
panic(fmt.Errorf("vgtex: unknown path component type: %v", comp.Type))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriterTo interface, writing a LaTeX/pgf plot.
|
||||
func (c *Canvas) WriteTo(w io.Writer) (int64, error) {
|
||||
var (
|
||||
n int64
|
||||
nn int
|
||||
err error
|
||||
)
|
||||
b := bufio.NewWriter(w)
|
||||
if c.document {
|
||||
nn, err = b.Write([]byte(defaultHeader))
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
m, err := c.buf.WriteTo(b)
|
||||
n += m
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
nn, err = fmt.Fprintf(b, "\\end{pgfpicture}\n")
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
if c.document {
|
||||
nn, err = b.Write([]byte(defaultFooter))
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, b.Flush()
|
||||
}
|
||||
Reference in New Issue
Block a user