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 }