// bezier.go is a manual translation of the code from (including some amendments in the comments section)
// https://www.particleincell.com/2013/cubic-line-intersection/

package geo

import (
	

	
	
	
)

// How precise should comparisons be, avoid being too precise due to floating point issues
const PRECISION = 0.0001

type BezierCurve struct {
	Curve  *bezier.Curve
	points []*Point
}

func ( []*Point) *BezierCurve {
	 := make([]vg.Point, len())
	for  := 0;  < len(); ++ {
		[] = vg.Point{
			X: font.Length([].X),
			Y: font.Length([].Y),
		}
	}
	 := bezier.New(...)
	 := &BezierCurve{
		Curve: &,
	}
	.points = 
	return 
}

func ( BezierCurve) ( Segment) []*Point {
	return ComputeIntersections(
		[]float64{
			.points[0].X,
			.points[1].X,
			.points[2].X,
			.points[3].X,
		},
		[]float64{
			.points[0].Y,
			.points[1].Y,
			.points[2].Y,
			.points[3].Y,
		},
		[]float64{
			.Start.X,
			.End.X,
		},
		[]float64{
			.Start.Y,
			.End.Y,
		},
	)
}

func ( BezierCurve) ( float64) *Point {
	 := .Curve.Point()
	return NewPoint(float64(.X), float64(.Y))
}

// nolint
func (, , ,  []float64) []*Point {
	 := make([]*Point, 0)

	var  = [1] - [0]
	var  = [0] - [1]
	var  = [0]*([0]-[1]) + [0]*([1]-[0])

	var  = bezierCoeffs([0], [1], [2], [3])
	var  = bezierCoeffs([0], [1], [2], [3])

	 := make([]float64, 4)
	[0] = *[0] + *[0]
	[1] = *[1] + *[1]
	[2] = *[2] + *[2]
	[3] = *[3] + *[3] + 

	var  = cubicRoots()

	for  := 0;  < 3; ++ {
		 := []

		 := &Point{
			X: [0]*** + [1]** + [2]* + [3],
			Y: [0]*** + [1]** + [2]* + [3],
		}

		var  float64
		if ([1] - [0]) != 0 {
			 = (.X - [0]) / ([1] - [0])
		} else {
			 = (.Y - [0]) / ([1] - [0])
		}

		 := PrecisionCompare(, 0, PRECISION) < 0
		 := PrecisionCompare(, 1, PRECISION) > 0
		 := PrecisionCompare(, 0, PRECISION) < 0
		 := PrecisionCompare(, 1, PRECISION) > 0
		if !( ||  ||  || ) {
			 = append(, )
		}
	}

	return 
}

// nolint
func cubicRoots( []float64) []float64 {
	if PrecisionCompare([0], 0, PRECISION) == 0 {
		if PrecisionCompare([1], 0, PRECISION) == 0 {
			 := make([]float64, 3)
			[0] = -1 * ([3] / [2])
			[1] = -1
			[2] = -1

			for  := 0;  < 1; ++ {
				 := PrecisionCompare([], 0, PRECISION) < 0
				 := PrecisionCompare([], 1, PRECISION) > 0
				if  ||  {
					[] = -1
				}
			}

			 = sortSpecial()
			return 
		}

		var  = math.Pow([2], 2) - 4*[1]*[3]
		if PrecisionCompare(, 0, PRECISION) >= 0 {
			 = math.Sqrt()
			 := make([]float64, 3)
			[0] = -1 * (( + [2]) / (2 * [1]))
			[1] = (( - [2]) / (2 * [1]))
			[2] = -1

			//lint:ignore SA4008 TODO this returns before looping?
			for  := 0;  < 2; ++ {
				 := PrecisionCompare([], 0, PRECISION) < 0
				 := PrecisionCompare([], 1, PRECISION) > 0
				if  ||  {
					[] = -1
				}

				 = sortSpecial()

				//lint:ignore SA4004 TODO this always returns on the first iteration
				return 
			}
		}
	}

	var  = [0]
	var  = [1]
	var  = [2]
	var  = [3]

	var  =  / 
	var  =  / 
	var  =  / 

	var , , ,  float64

	 = (3* - math.Pow(, 2)) / 9
	 = (9** - 27* - 2*math.Pow(, 3)) / 54
	 = math.Pow(, 3) + math.Pow(, 2)

	 := make([]float64, 3)

	if PrecisionCompare(, 0, PRECISION) >= 0 {
		var  = sgn(+math.Sqrt()) * math.Pow(math.Abs(+math.Sqrt()), (1/3.0))
		var  = sgn(-math.Sqrt()) * math.Pow(math.Abs(-math.Sqrt()), (1/3.0))

		[0] = -/3 + ( + )
		[1] = -/3 - (+)/2
		[2] = -/3 - (+)/2
		 = math.Abs(math.Sqrt(3) * ( - ) / 2)

		if PrecisionCompare(, 0, PRECISION) != 0 {
			[1] = -1
			[2] = -1
		}

	} else {
		var  = math.Acos( / math.Sqrt(-math.Pow(, 3)))

		[0] = 2*math.Sqrt(-)*math.Cos(/3) - /3
		[1] = 2*math.Sqrt(-)*math.Cos((+2*math.Pi)/3) - /3
		[2] = 2*math.Sqrt(-)*math.Cos((+4*math.Pi)/3) - /3
		 = 0.0
	}

	for  := 0;  < 3; ++ {
		 := PrecisionCompare([], 0, PRECISION) < 0
		 := PrecisionCompare([], 1, PRECISION) > 0
		if  ||  {
			[] = -1
		}
	}

	 = sortSpecial()

	return 
}

// nolint
func sortSpecial( []float64) []float64 {
	var  bool
	var  float64

	for {
		 = false
		for  := 0;  < len()-1; ++ {
			 := PrecisionCompare([+1], 0, PRECISION) >= 0
			 := PrecisionCompare([], [+1], PRECISION) > 0
			 := PrecisionCompare([], 0, PRECISION) < 0
			if ( && ) || ( && ) {
				 = true
				 = []
				[] = [+1]
				[+1] = 

			}
		}
		if ! {
			break
		}
	}
	return 
}

// nolint
func sgn( float64) float64 {
	if  < 0.0 {
		return -1
	}
	return 1
}

// nolint
func bezierCoeffs(, , ,  float64) []float64 {
	 := make([]float64, 4)
	[0] = - + 3* + -3* + 
	[1] = 3* - 6* + 3*
	[2] = -3* + 3*
	[3] = 
	return 
}