package geoimport ()typeEllipsestruct { Center *Point Rx float64 Ry float64}func ( *Point, , float64) *Ellipse {return &Ellipse{Center: ,Rx: ,Ry: , }}func ( Ellipse) ( Segment) []*Point {// we check for intersections between the ellipse and line segment in the following manner: // 0. we compute ignoring the ellipse's position, as if it were centered at 0,0 for a simpler computation // 1. translate the line segment variables to match the ellipse's "translation" to 0,0 // 2. get the (infinite) line equation for the given line segment // 3. compute the intersections between the line and ellipse // 4. filter out intersections that are on the line but not on the line segment // 5. apply the inverse translation to the intersection to get the result relative to where the ellipse and line actually are := []*Point{}// ellipse equation: (x-cx)^2/rx^2 + (y-cy)^2/ry^2 = 1 // in the form: x^2/a^2 + y^2/b^2 = 1 := .Rx := .Ry := * := * if <= 0 || <= 0 {returnnil }// line for a line segment between (x1,y1) and (x2, y2): (see https://en.wikipedia.org/wiki/Linear_equation#Two-point_form) // y - y1 = ((y2 - y1)/(x2 - x1))(x - x1) := .Start.X - .Center.X := .Start.Y - .Center.Y := .End.X - .Center.X := .End.Y - .Center.Y// Handle the edge case of a vertical line (avoiding dividing by 0)if == {// Ellipse solutions for a given x (from wolfram "(x^2)/(a^2)+(y^2)/(b^2)=1"): // 1. y = +b*root(a^2 - x^2)/a := NewPoint(, +*math.Sqrt(-*)/)// 2. y = -b*root(a^2 - x^2)/a := .Copy() .Y *= -1 := func( *Point) bool { := []float64{.Y, , }sort.Slice(, func(, int) bool {return [] < [] })return [1] == .Y }if () { = append(, ) }// when y = 0, intersection2 will be a duplicate of intersection1if .Y != 0.0 && () { = append(, ) }for , := range { .X += .Center.X .Y += .Center.Y }return }// converting line to form: y = mx + c // from: y - y1 = ((y2-y1)/(x2-x1))(x - x1) // m = (y2-y1)/(x2-x1), c = y1 - m*x1 := ( - ) / ( - ) := - * := func( *Point) bool {returnPrecisionCompare(.DistanceToLine(NewPoint(, ), NewPoint(, )), 0, PRECISION) == 0 }// "(x^2)/(a^2)+(y^2)/(b^2) =1, y = mx + c" solutions from wolfram: // if (a^2)(m^2) + b^2 != 0, and ab != 0 // 2 solutions 1 with +, 1 with - // x = ( -c m a^2 {+/-} root(a^2 b^2 (a^2 m^2 + b^2 - c^2)) ) / (a^2 m^2 + b^2) // y = ( c b^2 {+/-} m root(a^2 b^2 (a^2 m^2 + b^2 - c^2)) ) / (a^2 m^2 + b^2) := ** + // Note: we already checked a and b != 0 so denom == 0 is impossible (assuming no imaginary numbers) := math.Sqrt( * * ( - *)) := NewPoint((-**+)/, (*+*)/) := NewPoint((-**-)/, (*-*)/)if () { = append(, ) }if !.Equals() && () { = append(, ) }for , := range { .X += .Center.X .Y += .Center.Y }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.