...

Source file src/gonum.org/v1/plot/plotter/polygon.go

Documentation: gonum.org/v1/plot/plotter

     1  // Copyright ©2016 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package plotter
     6  
     7  import (
     8  	"image/color"
     9  	"math"
    10  
    11  	"gonum.org/v1/plot"
    12  	"gonum.org/v1/plot/vg"
    13  	"gonum.org/v1/plot/vg/draw"
    14  )
    15  
    16  // Polygon implements the Plotter interface, drawing a polygon.
    17  type Polygon struct {
    18  	// XYs is a copy of the vertices of this polygon.
    19  	// Each item in the array holds one ring in the
    20  	// Polygon.
    21  	XYs []XYs
    22  
    23  	// LineStyle is the style of the line around the edge
    24  	// of the polygon.
    25  	draw.LineStyle
    26  
    27  	// Color is the fill color of the polygon.
    28  	Color color.Color
    29  }
    30  
    31  // NewPolygon returns a polygon that uses the default line style and
    32  // no fill color, where xys are the rings of the polygon.
    33  // Different backends may render overlapping rings and self-intersections
    34  // differently, but all built-in backends treat inner rings
    35  // with the opposite winding order from the outer ring as
    36  // holes.
    37  func NewPolygon(xys ...XYer) (*Polygon, error) {
    38  	data := make([]XYs, len(xys))
    39  	for i, d := range xys {
    40  		var err error
    41  		data[i], err = CopyXYs(d)
    42  		if err != nil {
    43  			return nil, err
    44  		}
    45  	}
    46  	return &Polygon{
    47  		XYs:       data,
    48  		LineStyle: DefaultLineStyle,
    49  	}, nil
    50  }
    51  
    52  // Plot draws the polygon, implementing the plot.Plotter
    53  // interface.
    54  func (pts *Polygon) Plot(c draw.Canvas, plt *plot.Plot) {
    55  	trX, trY := plt.Transforms(&c)
    56  	ps := make([][]vg.Point, len(pts.XYs))
    57  
    58  	for i, ring := range pts.XYs {
    59  		ps[i] = make([]vg.Point, len(ring))
    60  		for j, p := range ring {
    61  			ps[i][j].X = trX(p.X)
    62  			ps[i][j].Y = trY(p.Y)
    63  		}
    64  		ps[i] = c.ClipPolygonXY(ps[i])
    65  	}
    66  	if pts.Color != nil && len(ps) > 0 {
    67  		c.SetColor(pts.Color)
    68  		// allocate enough space for at least 4 path components per ring.
    69  		// 3 is the minimum but 4 is more common.
    70  		pa := make(vg.Path, 0, 4*len(ps))
    71  		for _, ring := range ps {
    72  			if len(ring) == 0 {
    73  				continue
    74  			}
    75  			pa.Move(ring[0])
    76  			for _, p := range ring[1:] {
    77  				pa.Line(p)
    78  			}
    79  			pa.Close()
    80  		}
    81  		c.Fill(pa)
    82  	}
    83  
    84  	for _, ring := range ps {
    85  		if len(ring) > 0 && ring[len(ring)-1] != ring[0] {
    86  			ring = append(ring, ring[0])
    87  		}
    88  		c.StrokeLines(pts.LineStyle, c.ClipLinesXY(ring)...)
    89  	}
    90  }
    91  
    92  // DataRange returns the minimum and maximum
    93  // x and y values, implementing the plot.DataRanger
    94  // interface.
    95  func (pts *Polygon) DataRange() (xmin, xmax, ymin, ymax float64) {
    96  	xmin = math.Inf(1)
    97  	xmax = math.Inf(-1)
    98  	ymin = math.Inf(1)
    99  	ymax = math.Inf(-1)
   100  	for _, ring := range pts.XYs {
   101  		xmini, xmaxi := Range(XValues{ring})
   102  		ymini, ymaxi := Range(YValues{ring})
   103  		xmin = math.Min(xmin, xmini)
   104  		xmax = math.Max(xmax, xmaxi)
   105  		ymin = math.Min(ymin, ymini)
   106  		ymax = math.Max(ymax, ymaxi)
   107  	}
   108  	return
   109  }
   110  
   111  // Thumbnail creates the thumbnail for the Polygon,
   112  // implementing the plot.Thumbnailer interface.
   113  func (pts *Polygon) Thumbnail(c *draw.Canvas) {
   114  	if pts.Color != nil {
   115  		points := []vg.Point{
   116  			{X: c.Min.X, Y: c.Min.Y},
   117  			{X: c.Min.X, Y: c.Max.Y},
   118  			{X: c.Max.X, Y: c.Max.Y},
   119  			{X: c.Max.X, Y: c.Min.Y},
   120  		}
   121  		poly := c.ClipPolygonY(points)
   122  		c.FillPolygon(pts.Color, poly)
   123  
   124  		points = append(points, vg.Point{X: c.Min.X, Y: c.Min.Y})
   125  		c.StrokeLines(pts.LineStyle, points)
   126  	} else {
   127  		y := c.Center().Y
   128  		c.StrokeLine2(pts.LineStyle, c.Min.X, y, c.Max.X, y)
   129  	}
   130  }
   131  

View as plain text