github.com/richardwilkes/toolbox@v1.121.0/xmath/geom/poly/shapes.go (about)

     1  // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, version 2.0. If a copy of the MPL was not distributed with
     5  // this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  //
     7  // This Source Code Form is "Incompatible With Secondary Licenses", as
     8  // defined by the Mozilla Public License, version 2.0.
     9  
    10  package poly
    11  
    12  import (
    13  	"math"
    14  
    15  	"github.com/richardwilkes/toolbox/xmath"
    16  	"github.com/richardwilkes/toolbox/xmath/geom"
    17  	"golang.org/x/exp/constraints"
    18  )
    19  
    20  // FromRect returns a Polygon in the shape of the specified rectangle.
    21  func FromRect[T constraints.Float](r geom.Rect[T]) Polygon[T] {
    22  	right := r.Right() - 1
    23  	bottom := r.Bottom() - 1
    24  	return Polygon[T]{Contour[T]{r.Point, geom.NewPoint(r.X, bottom), geom.NewPoint(right, bottom), geom.NewPoint(right, r.Y)}}
    25  }
    26  
    27  // FromEllipse returns a Polygon that approximates an ellipse filling the given Rect. 'sections' indicates how many
    28  // segments to break the ellipse contour into. Passing a value less than 4 for 'sections' will result in an automatic
    29  // choice based on a call to EllipseSegmentCount, using half of the longest dimension for the 'r' parameter and 0.2 for
    30  // the 'e' parameter.
    31  func FromEllipse[T constraints.Float](r geom.Rect[T], sections int) Polygon[T] {
    32  	if sections < 4 {
    33  		sections = EllipseSegmentCount(max(r.Width, r.Height)/2, 0.2)
    34  	}
    35  	halfWidth := r.Width / 2
    36  	halfHeight := r.Height / 2
    37  	inc := math.Pi * 2 / T(sections)
    38  	center := r.Center()
    39  	contour := make(Contour[T], sections)
    40  	var angle T
    41  	for i := 0; i < sections; i++ {
    42  		contour[i] = geom.NewPoint(center.X+xmath.Cos(angle)*halfWidth, center.Y+xmath.Sin(angle)*halfHeight)
    43  		angle += inc
    44  	}
    45  	return Polygon[T]{contour}
    46  }
    47  
    48  // EllipseSegmentCount returns a suggested number of segments to use when generating an ellipse. 'r' is the largest
    49  // radius of the ellipse. 'e' is the acceptable error, typically 1 or less.
    50  func EllipseSegmentCount[T constraints.Float](r, e T) int {
    51  	d := 1 - e/r
    52  	return max(int(xmath.Ceil(2*math.Pi/xmath.Acos(2*d*d-1))), 4)
    53  }