package geo

import (
	
	
)

type Ellipse struct {
	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 {
		return nil
	}

	// 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 intersection1
		if .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 {
		return PrecisionCompare(.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 
}