// Copyright (c) 2017 Kiel University and others.
// Copyright (c) 2026 The elk-go Authors.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

package spore

import (
	

	
)

func overlap(,  geometry.Rectangle) float64 {
	 := math.Min(
		math.Abs(.X-(.X+.Width)),
		math.Abs(.X+.Width-.X),
	)
	 := math.Min(
		math.Abs(.Y-(.Y+.Height)),
		math.Abs(.Y+.Height-.Y),
	)
	 := math.Abs(.Center().X - .Center().X)
	if  > .Width/2+.Width/2 {
		return 1
	}
	 := math.Abs(.Center().Y - .Center().Y)
	if  > .Height/2+.Height/2 {
		return 1
	}
	if  == 0 &&  == 0 {
		return 0
	}
	if  == 0 {
		return / + 1
	}
	if  == 0 {
		return / + 1
	}
	return math.Min(/, /) + 1
}

func shortestDistance(,  geometry.Rectangle) float64 {
	 := .X - (.X + .Width)
	 := .X - (.X + .Width)
	 := .Y - (.Y + .Height)
	 := .Y - (.Y + .Height)
	 := math.Max(, )
	 := math.Max(, )
	if (fuzzyCompare(, 0, doubleEpsilon) >= 0) !=
		(fuzzyCompare(, 0, doubleEpsilon) >= 0) {
		return math.Max(, )
	}
	if fuzzyCompare(, 0, doubleEpsilon) > 0 {
		return math.Hypot(, )
	}
	return -math.Hypot(, )
}

func clipVector( geometry.Point, ,  float64) geometry.Point {
	,  := /2, /2
	,  := 1.0, 1.0
	if math.Abs(.X) >  {
		 =  / math.Abs(.X)
	}
	if math.Abs(.Y) >  {
		 =  / math.Abs(.Y)
	}
	 := math.Min(, )
	return geometry.Point{X: float64(.X * ), Y: float64(.Y * )}
}

func sporeVectorLength( geometry.Point) float64 {
	// Preserve KVector.length's generated-JavaScript operation boundaries.
	 := float64(.X * .X)
	 := float64(.Y * .Y)
	return math.Sqrt( + )
}

func sporeScaleToLength( geometry.Point,  float64) geometry.Point {
	 := sporeVectorLength()
	if  > 0 {
		.X = float64(.X / )
		.Y = float64(.Y / )
	}
	.X = float64(.X * )
	.Y = float64(.Y * )
	return 
}

func rectangleEdges( geometry.Rectangle) []*tEdgePoint {
	 := .Position()
	 := .TopRight()
	 := .BottomLeft()
	 := .BottomRight()
	return []*tEdgePoint{
		{u: , v: },
		{u: , v: },
		{u: , v: },
		{u: , v: },
	}
}

type tEdgePoint struct {
	u, v geometry.Point
}

func segmentDistance(, , , ,  geometry.Point) float64 {
	return math.Min(
		traceRays(, , , , ),
		traceRays(, , , , .Negate()),
	)
}

func traceRays(, , , ,  geometry.Point) float64 {
	 := math.Inf(1)
	,  := segmentIntersection(
		,
		.Sub(),
		.Add(),
		.Sub(),
	)
	 :=  && !fuzzyPointEqual(, ) && !fuzzyPointEqual(, )

	,  := segmentIntersection(, .Sub(), , )
	 := false
	if  {
		if fuzzyPointEqual(, ) == fuzzyPointEqual(, ) ||  {
			 = math.Min(, .Sub().Length())
		} else {
			 = true
		}
	}

	,  = segmentIntersection(, .Sub(), , )
	if  && ( || fuzzyPointEqual(, ) == fuzzyPointEqual(, ) || ) {
		 = math.Min(, .Sub().Length())
	}
	return 
}

func segmentIntersection(, , ,  geometry.Point) (geometry.Point, bool) {
	 := .Sub()
	 := .Cross()
	 := .Cross()
	 := .Cross() / 
	 :=  / 
	if  == 0 {
		if  != 0 {
			return geometry.Point{}, false
		}
		 := .Add(.Scale(0.5))
		 := .Distance()
		 := .Add().Distance()
		 := .Length() * 0.5
		if  <  &&  <=  {
			return , true
		}
		if  <=  {
			return .Add(), true
		}
		return geometry.Point{}, false
	}
	if  >= 0 &&  <= 1 &&  >= 0 &&  <= 1 {
		return .Add(.Scale()), true
	}
	return geometry.Point{}, false
}

func fuzzyPointEqual(,  geometry.Point) bool {
	return math.Abs(.X-.X) <= 0.05 && math.Abs(.Y-.Y) <= 0.05
}