Exemple #1
0
// DrawGlyph implements the Glyph interface.
func (PyramidGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	r := sty.Radius + (sty.Radius-sty.Radius*sinπover6)/2
	var p vg.Path
	p.Move(pt.X, pt.Y+r)
	p.Line(pt.X-r*cosπover6, pt.Y-r*sinπover6)
	p.Line(pt.X+r*cosπover6, pt.Y-r*sinπover6)
	p.Close()
	c.Fill(p)
}
Exemple #2
0
// DrawGlyph implements the Glyph interface.
func (TriangleGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	c.SetLineStyle(LineStyle{Color: sty.Color, Width: vg.Points(0.5)})
	r := sty.Radius + (sty.Radius-sty.Radius*sinπover6)/2
	var p vg.Path
	p.Move(pt.X, pt.Y+r)
	p.Line(pt.X-r*cosπover6, pt.Y-r*sinπover6)
	p.Line(pt.X+r*cosπover6, pt.Y-r*sinπover6)
	p.Close()
	c.Stroke(p)
}
Exemple #3
0
// DrawGlyph implements the Glyph interface.
func (BoxGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	x := (sty.Radius-sty.Radius*cosπover4)/2 + sty.Radius*cosπover4
	var p vg.Path
	p.Move(pt.X-x, pt.Y-x)
	p.Line(pt.X+x, pt.Y-x)
	p.Line(pt.X+x, pt.Y+x)
	p.Line(pt.X-x, pt.Y+x)
	p.Close()
	c.Fill(p)
}
Exemple #4
0
// DrawGlyph implements the Glyph interface.
func (SquareGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	c.SetLineStyle(LineStyle{Color: sty.Color, Width: vg.Points(0.5)})
	x := (sty.Radius-sty.Radius*cosπover4)/2 + sty.Radius*cosπover4
	var p vg.Path
	p.Move(pt.X-x, pt.Y-x)
	p.Line(pt.X+x, pt.Y-x)
	p.Line(pt.X+x, pt.Y+x)
	p.Line(pt.X-x, pt.Y+x)
	p.Close()
	c.Stroke(p)
}
Exemple #5
0
// DrawGlyph implements the Glyph interface.
func (CrossGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	c.SetLineStyle(LineStyle{Color: sty.Color, Width: vg.Points(0.5)})
	r := sty.Radius * cosπover4
	var p vg.Path
	p.Move(pt.X-r, pt.Y-r)
	p.Line(pt.X+r, pt.Y+r)
	c.Stroke(p)
	p = vg.Path{}
	p.Move(pt.X-r, pt.Y+r)
	p.Line(pt.X+r, pt.Y-r)
	c.Stroke(p)
}
Exemple #6
0
func (line GrobLine) Draw(vp Viewport) {
	vp.Canvas.SetColor(line.color)
	vp.Canvas.SetLineWidth(vg.Points(line.size))
	vp.Canvas.SetLineDash(dashLength[line.linetype%7], 0)
	x0, y0 := vp.X(line.x0), vp.Y(line.y0)
	x1, y1 := vp.X(line.x1), vp.Y(line.y1)
	var p vg.Path

	p.Move(x0, y0)
	p.Line(x1, y1)
	vp.Canvas.Stroke(p)
}
Exemple #7
0
// FillPolygon fills a polygon with the given color.
func (c *Canvas) FillPolygon(clr color.Color, pts []Point) {
	if len(pts) == 0 {
		return
	}

	c.SetColor(clr)
	var p vg.Path
	p.Move(pts[0].X, pts[0].Y)
	for _, pt := range pts[1:] {
		p.Line(pt.X, pt.Y)
	}
	p.Close()
	c.Fill(p)
}
Exemple #8
0
func (c *contour) path(trX, trY func(float64) vg.Length) vg.Path {
	var pa vg.Path
	p := c.front()
	pa.Move(trX(p.X), trY(p.Y))
	for i := len(c.backward) - 2; i >= 0; i-- {
		p = c.backward[i]
		pa.Line(trX(p.X), trY(p.Y))
	}
	for _, p := range c.forward {
		pa.Line(trX(p.X), trY(p.Y))
	}

	return pa
}
Exemple #9
0
func (path GrobPath) Draw(vp Viewport) {
	vp.Canvas.Push()
	vp.Canvas.SetColor(path.color)
	vp.Canvas.SetLineWidth(vg.Points(path.size))
	vp.Canvas.SetLineDash(dashLength[path.linetype], 0)
	x, y := vp.X(path.points[0].x), vp.Y(path.points[0].y)
	var p vg.Path

	p.Move(x, y)
	for i := 1; i < len(path.points); i++ {
		x, y = vp.X(path.points[i].x), vp.Y(path.points[i].y)
		p.Line(x, y)
	}
	vp.Canvas.Stroke(p)
	vp.Canvas.Pop()
}
Exemple #10
0
func (rect GrobRect) Draw(vp Viewport) {
	println("GrobRect.Draw: ", rect.String(), " to ", vp.String())
	vp.Canvas.Push()
	vp.Canvas.SetColor(rect.fill)
	vp.Canvas.SetLineWidth(2)
	xmin, ymin := vp.X(rect.xmin), vp.Y(rect.ymin)
	xmax, ymax := vp.X(rect.xmax), vp.Y(rect.ymax)
	println(xmin, ymin, " -- ", xmax, ymax)
	var p vg.Path

	p.Move(xmin, ymin)
	p.Line(xmax, ymin)
	p.Line(xmax, ymax)
	p.Line(xmin, ymax)
	p.Close()
	vp.Canvas.Fill(p)
	vp.Canvas.Pop()
}
Exemple #11
0
// StrokeLines draws a line connecting a set of points
// in the given Canvas.
func (c *Canvas) StrokeLines(sty LineStyle, lines ...[]Point) {
	if len(lines) == 0 {
		return
	}

	c.SetLineStyle(sty)

	for _, l := range lines {
		if len(l) == 0 {
			continue
		}
		var p vg.Path
		p.Move(l[0].X, l[0].Y)
		for _, pt := range l[1:] {
			p.Line(pt.X, pt.Y)
		}
		c.Stroke(p)
	}
}
Exemple #12
0
// Plot draws the Line, implementing the plot.Plotter
// interface.
func (pts *Line) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)
	ps := make([]draw.Point, len(pts.XYs))

	for i, p := range pts.XYs {
		ps[i].X = trX(p.X)
		ps[i].Y = trY(p.Y)
	}

	if pts.ShadeColor != nil && len(ps) > 0 {
		c.SetColor(*pts.ShadeColor)
		minY := trY(plt.Y.Min)
		var pa vg.Path
		pa.Move(ps[0].X, minY)
		for i := range pts.XYs {
			pa.Line(ps[i].X, ps[i].Y)
		}
		pa.Line(ps[len(pts.XYs)-1].X, minY)
		pa.Close()
		c.Fill(pa)
	}

	c.StrokeLines(pts.LineStyle, c.ClipLinesXY(ps)...)
}
Exemple #13
0
// naivePlot implements the a naive rendering approach for contours.
// It is here as a debugging mode since it simply draws line segments
// generated by conrec without further computation.
func (h *Contour) naivePlot(c draw.Canvas, plt *plot.Plot) {
	var pal []color.Color
	if h.Palette != nil {
		pal = h.Palette.Colors()
	}

	trX, trY := plt.Transforms(&c)

	// Sort levels prior to palette scaling since we can't depend on
	// sorting as a side effect from calling contourPaths.
	sort.Float64s(h.Levels)
	// ps is a palette scaling factor to scale the palette uniformly
	// across the given levels. This enables a discordance between the
	// number of colours and the number of levels.
	ps := float64(len(pal)-1) / (h.Levels[len(h.Levels)-1] - h.Levels[0])
	if len(h.Levels) == 1 {
		ps = 0
	}

	levelMap := make(map[float64]int)
	for i, z := range h.Levels {
		levelMap[z] = i
	}

	// Draw each line segment as conrec generates it.
	var pa vg.Path
	conrec(h.GridXYZ, h.Levels, func(_, _ int, l line, z float64) {
		if math.IsNaN(z) {
			return
		}

		pa = pa[:0]

		x1, y1 := trX(l.p1.X), trY(l.p1.Y)
		x2, y2 := trX(l.p2.X), trY(l.p2.Y)

		if !c.Contains(draw.Point{x1, y1}) || !c.Contains(draw.Point{x2, y2}) {
			return
		}

		pa.Move(x1, y1)
		pa.Line(x2, y2)
		pa.Close()

		style := h.LineStyles[levelMap[z]%len(h.LineStyles)]
		var col color.Color
		switch {
		case z < h.Min:
			col = h.Underflow
		case z > h.Max:
			col = h.Overflow
		case len(pal) == 0:
			col = style.Color
		default:
			col = pal[int((z-h.Levels[0])*ps+0.5)] // Apply palette scaling.
		}
		if col != nil && style.Width != 0 {
			c.SetLineStyle(style)
			c.SetColor(col)
			c.Stroke(pa)
		}
	})
}
Exemple #14
0
// Plot implements the Plot method of the plot.Plotter interface.
func (h *HeatMap) Plot(c draw.Canvas, plt *plot.Plot) {
	pal := h.Palette.Colors()
	if len(pal) == 0 {
		panic("heatmap: empty palette")
	}
	// ps scales the palette uniformly across the data range.
	ps := float64(len(pal)-1) / (h.Max - h.Min)

	trX, trY := plt.Transforms(&c)

	var pa vg.Path
	cols, rows := h.GridXYZ.Dims()
	for i := 0; i < cols; i++ {

		var right, left float64
		switch i {
		case 0:
			right = (h.GridXYZ.X(i+1) - h.GridXYZ.X(i)) / 2
			left = -right
		case cols - 1:
			right = (h.GridXYZ.X(i) - h.GridXYZ.X(i-1)) / 2
			left = -right
		default:
			right = (h.GridXYZ.X(i+1) - h.GridXYZ.X(i)) / 2
			left = -(h.GridXYZ.X(i) - h.GridXYZ.X(i-1)) / 2
		}

		for j := 0; j < rows; j++ {
			v := h.GridXYZ.Z(i, j)
			if math.IsNaN(v) || math.IsInf(v, 0) {
				continue
			}

			pa = pa[:0]

			var up, down float64
			switch j {
			case 0:
				up = (h.GridXYZ.Y(j+1) - h.GridXYZ.Y(j)) / 2
				down = -up
			case rows - 1:
				up = (h.GridXYZ.Y(j) - h.GridXYZ.Y(j-1)) / 2
				down = -up
			default:
				up = (h.GridXYZ.Y(j+1) - h.GridXYZ.Y(j)) / 2
				down = -(h.GridXYZ.Y(j) - h.GridXYZ.Y(j-1)) / 2
			}

			x, y := trX(h.GridXYZ.X(i)+left), trY(h.GridXYZ.Y(j)+down)
			dx, dy := trX(h.GridXYZ.X(i)+right), trY(h.GridXYZ.Y(j)+up)

			if !c.Contains(draw.Point{x, y}) || !c.Contains(draw.Point{dx, dy}) {
				continue
			}

			pa.Move(x, y)
			pa.Line(dx, y)
			pa.Line(dx, dy)
			pa.Line(x, dy)
			pa.Close()

			var col color.Color
			switch {
			case v < h.Min:
				col = h.Underflow
			case v > h.Max:
				col = h.Overflow
			default:
				col = pal[int((v-h.Min)*ps+0.5)] // Apply palette scaling.
			}
			if col != nil {
				c.SetColor(col)
				c.Fill(pa)
			}
		}
	}
}
Exemple #15
0
func (point GrobPoint) Draw(vp Viewport) {
	vp.Canvas.Push()
	vp.Canvas.SetColor(point.color)
	vp.Canvas.SetLineWidth(1)
	x, y := vp.X(point.x), vp.Y(point.y)
	s := vg.Points(point.size)
	var p vg.Path

	draw := vp.Canvas.Stroke
	if point.shape >= SolidCirclePoint && point.shape <= SolidNablaPoint {
		draw = vp.Canvas.Fill
	}

	switch point.shape {
	case BlankPoint:
		return
	case DotPoint:
		dpi := vp.Canvas.DPI()
		p.Arc(x, y, vg.Inch/vg.Length(dpi), 0, 2*math.Pi)
		p.Close()
		vp.Canvas.Fill(p)
	case CirclePoint, SolidCirclePoint:
		p.Arc(x, y, vg.Points(point.size), 0, 2*math.Pi)
		p.Close()
		draw(p)
	case SquarePoint, SolidSquarePoint:
		p.Move(x-s, y-s)
		p.Line(x+s, y-s)
		p.Line(x+s, y+s)
		p.Line(x-s, y+s)
		p.Close()
		draw(p)
	case DiamondPoint, SolidDiamondPoint:
		p.Move(x, y-s)
		p.Line(x+s, y)
		p.Line(x, y+s)
		p.Line(x-s, y)
		p.Close()
		draw(p)
	case DeltaPoint, SolidDeltaPoint:
		ss := 0.57735 * s
		p.Move(x, y+2*ss)
		p.Line(x-s, y-ss)
		p.Line(x+s, y-ss)
		p.Close()
		draw(p)
	case NablaPoint, SolidNablaPoint:
		ss := 0.57735 * s
		p.Move(x, y-2*ss)
		p.Line(x-s, y+ss)
		p.Line(x+s, y+ss)
		p.Close()
		draw(p)
	case CrossPoint:
		ss := s / 1.3
		p.Move(x-ss, y-ss)
		p.Line(x+ss, y+ss)
		p.Move(x-ss, y+ss)
		p.Line(x+ss, y-ss)
		draw(p)
	case PlusPoint:
		p.Move(x-s, y)
		p.Line(x+s, y)
		p.Move(x, y-s)
		p.Line(x, y+s)
		draw(p)
	case StarPoint:
		ss := s / 1.3
		p.Move(x-ss, y-ss)
		p.Line(x+ss, y+ss)
		p.Move(x-ss, y+ss)
		p.Line(x+ss, y-ss)
		p.Move(x-s, y)
		p.Line(x+s, y)
		p.Move(x, y-s)
		p.Line(x, y+s)
		draw(p)
	default:
		println("Implement Draw for points " + point.shape.String())
	}
	vp.Canvas.Pop()
}
Exemple #16
0
func TestGraphicGrobs(t *testing.T) {
	// Output
	file, err := os.Create("grobs.png")
	if err != nil {
		t.Fatalf("%", err)
	}

	pngCanvas := vgimg.PngCanvas{Canvas: vgimg.New(10*vg.Inch, 8*vg.Inch)}
	vg.Initialize(pngCanvas)
	pngCanvas.Translate(-5*vg.Inch, -4*vg.Inch)
	dot := func(x, y float64) {
		pngCanvas.Push()
		pngCanvas.SetColor(BuiltinColors["red"])
		pngCanvas.SetLineWidth(5)
		var p vg.Path
		xr := vg.Length(x) * vg.Inch
		yr := vg.Length(y) * vg.Inch
		p.Move(xr-5, yr-5)
		p.Line(xr-5, yr+5)
		p.Line(xr+5, yr+5)
		p.Line(xr+5, yr-5)
		p.Close()
		pngCanvas.Fill(p)
		pngCanvas.Pop()
	}

	dot(0, 0)
	dot(5, 0)
	dot(0, 4)

	allVP := Viewport{
		X0:     0,
		Y0:     0,
		Width:  10 * vg.Inch,
		Height: 8 * vg.Inch,
		Canvas: pngCanvas,
	}
	innerVP := allVP.Sub(0.05, 0.05, 0.9, 0.9)
	bg := GrobRect{xmin: 0, ymin: 0, xmax: 1, ymax: 1, fill: BuiltinColors["gray80"]}
	bg.Draw(innerVP)

	cols := []string{"red", "green", "blue", "cyan", "magenta", "yellow",
		"white", "gray", "black"}

	// Draw points in all shapes, three sizes and all builtin colors.
	points := []Grob{}
	x, y := 0.1, 0.1
	for shape := DotPoint; shape <= StarPoint; shape++ {
		for size := 2; size < 7; size += 2 {
			y = 0.05
			for _, col := range cols {
				g := GrobPoint{
					x:     x,
					y:     y,
					size:  float64(size),
					shape: shape,
					color: BuiltinColors[col],
				}
				points = append(points, g)
				y += 0.035
			}
			x += 0.021
		}
	}
	x, y = 0.02, 0.05
	for _, col := range cols {
		g := GrobText{
			x:     x,
			y:     y,
			text:  col,
			size:  10,
			color: BuiltinColors[col],
			vjust: 0.5,
			hjust: 0,
		}
		points = append(points, g)
		y += 0.035
	}
	x, y = 0.121, 0.36
	for shape := DotPoint; shape <= StarPoint; shape++ {
		dy := float64(shape%2) * 0.015
		g := GrobText{
			x:     x,
			y:     y + dy,
			text:  shape.String(),
			size:  10,
			color: BuiltinColors["black"],
			vjust: 0.5,
			hjust: 0.5,
		}
		points = append(points, g)
		x += 3 * 0.021
	}
	for _, grob := range points {
		grob.Draw(innerVP)
	}

	// Draw lines with different styles and widths.
	lines := []Grob{}
	x, y = 0.1, 0.45
	for lt := SolidLine; lt <= TwodashLine; lt++ {
		x = 0.1
		for size := 1; size < 8; size += 2 {
			g := GrobLine{
				x0:       x,
				y0:       y,
				x1:       x + 0.18,
				y1:       y,
				size:     float64(size),
				linetype: lt,
				color:    BuiltinColors["black"],
			}
			lines = append(lines, g)
			x += 0.22
		}
		y += 0.04
	}
	for _, grob := range lines {
		grob.Draw(innerVP)
	}

	// Draw rectangles
	rectVP := innerVP.Sub(0.1, 0.7, 0.4, 0.3)
	rect := []Grob{}
	bgr := GrobRect{xmin: 0, ymin: 0, xmax: 1, ymax: 1, fill: BuiltinColors["gray40"]}
	bgr.Draw(rectVP)
	x, y = 0.0, 0.0
	w, h := 0.5, 0.5
	for _, col := range cols {
		g := GrobRect{
			xmin: x,
			ymin: y,
			xmax: x + w,
			ymax: y + h,
			fill: BuiltinColors[col],
		}
		rect = append(rect, g)
		x += w
		y += h
		w /= 2
		h /= 2
	}
	for _, grob := range rect {
		grob.Draw(rectVP)
	}

	// Draw path
	pathVP := innerVP.Sub(0.55, 0.7, 0.4, 0.3)
	bgp := GrobRect{xmin: 0, ymin: 0, xmax: 1, ymax: 1, fill: BuiltinColors["gray"]}
	bgp.Draw(pathVP)
	sin := make([]struct{ x, y float64 }, 50)
	for i := range sin {
		k := float64(i) / float64(len(sin)-1)
		x = k * 2 * math.Pi
		println(float64(i)/float64(len(sin)), x, math.Sin(x))
		y = 0.4 * math.Sin(x)
		sin[i].x = k
		sin[i].y = 0.55 + y
	}
	g := GrobPath{
		points:   sin,
		size:     4,
		linetype: SolidLine,
		color:    BuiltinColors["white"],
	}
	g.Draw(pathVP)
	cos := make([]struct{ x, y float64 }, 25)
	for i := range cos {
		k := float64(i) / float64(len(cos)-1)
		x = k * 4 * math.Pi
		y = 0.3 * math.Cos(x)
		cos[i].x = k
		cos[i].y = 0.45 + y
	}
	g = GrobPath{
		points:   cos,
		size:     2,
		linetype: DottedLine,
		color:    BuiltinColors["green"],
	}
	g.Draw(pathVP)

	pngCanvas.WriteTo(file)
	file.Close()
}