File: polygon.go

package info (click to toggle)
golang-gonum-v1-plot 0.7.0-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 13,980 kB
  • sloc: sh: 81; makefile: 13
file content (128 lines) | stat: -rw-r--r-- 3,158 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// 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 plotter

import (
	"image/color"
	"math"

	"gonum.org/v1/plot"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)

// Polygon implements the Plotter interface, drawing a polygon.
type Polygon struct {
	// XYs is a copy of the vertices of this polygon.
	// Each item in the array holds one ring in the
	// Polygon.
	XYs []XYs

	// LineStyle is the style of the line around the edge
	// of the polygon.
	draw.LineStyle

	// Color is the fill color of the polygon.
	Color color.Color
}

// NewPolygon returns a polygon that uses the default line style and
// no fill color, where xys are the rings of the polygon.
// Different backends may render overlapping rings and self-intersections
// differently, but all built-in backends treat inner rings
// with the opposite winding order from the outer ring as
// holes.
func NewPolygon(xys ...XYer) (*Polygon, error) {
	data := make([]XYs, len(xys))
	for i, d := range xys {
		var err error
		data[i], err = CopyXYs(d)
		if err != nil {
			return nil, err
		}
	}
	return &Polygon{
		XYs:       data,
		LineStyle: DefaultLineStyle,
	}, nil
}

// Plot draws the polygon, implementing the plot.Plotter
// interface.
func (pts *Polygon) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)
	ps := make([][]vg.Point, len(pts.XYs))

	for i, ring := range pts.XYs {
		ps[i] = make([]vg.Point, len(ring))
		for j, p := range ring {
			ps[i][j].X = trX(p.X)
			ps[i][j].Y = trY(p.Y)
		}
		ps[i] = c.ClipPolygonXY(ps[i])
	}
	if pts.Color != nil && len(ps) > 0 {
		c.SetColor(pts.Color)
		var pa vg.Path
		for _, ring := range ps {
			if len(ring) == 0 {
				continue
			}
			pa.Move(ring[0])
			for _, p := range ring {
				pa.Line(p)
			}
			pa.Close()
		}
		c.Fill(pa)
	}

	for _, ring := range ps {
		if len(ring) > 0 && ring[len(ring)-1] != ring[0] {
			ring = append(ring, ring[0])
		}
		c.StrokeLines(pts.LineStyle, c.ClipLinesXY(ring)...)
	}
}

// DataRange returns the minimum and maximum
// x and y values, implementing the plot.DataRanger
// interface.
func (pts *Polygon) DataRange() (xmin, xmax, ymin, ymax float64) {
	xmin = math.Inf(1)
	xmax = math.Inf(-1)
	ymin = math.Inf(1)
	ymax = math.Inf(-1)
	for _, ring := range pts.XYs {
		xmini, xmaxi := Range(XValues{ring})
		ymini, ymaxi := Range(YValues{ring})
		xmin = math.Min(xmin, xmini)
		xmax = math.Max(xmax, xmaxi)
		ymin = math.Min(ymin, ymini)
		ymax = math.Max(ymax, ymaxi)
	}
	return
}

// Thumbnail creates the thumbnail for the Polygon,
// implementing the plot.Thumbnailer interface.
func (pts *Polygon) Thumbnail(c *draw.Canvas) {
	if pts.Color != nil {
		points := []vg.Point{
			{X: c.Min.X, Y: c.Min.Y},
			{X: c.Min.X, Y: c.Max.Y},
			{X: c.Max.X, Y: c.Max.Y},
			{X: c.Max.X, Y: c.Min.Y},
		}
		poly := c.ClipPolygonY(points)
		c.FillPolygon(pts.Color, poly)

		points = append(points, vg.Point{X: c.Min.X, Y: c.Min.Y})
		c.StrokeLines(pts.LineStyle, points)
	} else {
		y := c.Center().Y
		c.StrokeLine2(pts.LineStyle, c.Min.X, y, c.Max.X, y)
	}
}