package spore
import (
"math"
"github.com/d2lang/elk-go/internal/geometry"
)
func overlap(first , second geometry .Rectangle ) float64 {
horizontalOverlap := math .Min (
math .Abs (first .X -(second .X +second .Width )),
math .Abs (first .X +first .Width -second .X ),
)
verticalOverlap := math .Min (
math .Abs (first .Y -(second .Y +second .Height )),
math .Abs (first .Y +first .Height -second .Y ),
)
horizontalCenterDistance := math .Abs (first .Center ().X - second .Center ().X )
if horizontalCenterDistance > first .Width /2 +second .Width /2 {
return 1
}
verticalCenterDistance := math .Abs (first .Center ().Y - second .Center ().Y )
if verticalCenterDistance > first .Height /2 +second .Height /2 {
return 1
}
if horizontalCenterDistance == 0 && verticalCenterDistance == 0 {
return 0
}
if horizontalCenterDistance == 0 {
return verticalOverlap /verticalCenterDistance + 1
}
if verticalCenterDistance == 0 {
return horizontalOverlap /horizontalCenterDistance + 1
}
return math .Min (horizontalOverlap /horizontalCenterDistance , verticalOverlap /verticalCenterDistance ) + 1
}
func shortestDistance(first , second geometry .Rectangle ) float64 {
rightDistance := second .X - (first .X + first .Width )
leftDistance := first .X - (second .X + second .Width )
topDistance := first .Y - (second .Y + second .Height )
bottomDistance := second .Y - (first .Y + first .Height )
horizontalDistance := math .Max (leftDistance , rightDistance )
verticalDistance := math .Max (topDistance , bottomDistance )
if (fuzzyCompare (horizontalDistance , 0 , doubleEpsilon ) >= 0 ) !=
(fuzzyCompare (verticalDistance , 0 , doubleEpsilon ) >= 0 ) {
return math .Max (verticalDistance , horizontalDistance )
}
if fuzzyCompare (horizontalDistance , 0 , doubleEpsilon ) > 0 {
return math .Hypot (verticalDistance , horizontalDistance )
}
return -math .Hypot (verticalDistance , horizontalDistance )
}
func clipVector(vector geometry .Point , width , height float64 ) geometry .Point {
halfWidth , halfHeight := width /2 , height /2
xScale , yScale := 1.0 , 1.0
if math .Abs (vector .X ) > halfWidth {
xScale = halfWidth / math .Abs (vector .X )
}
if math .Abs (vector .Y ) > halfHeight {
yScale = halfHeight / math .Abs (vector .Y )
}
scale := math .Min (xScale , yScale )
return geometry .Point {X : float64 (vector .X * scale ), Y : float64 (vector .Y * scale )}
}
func sporeVectorLength(vector geometry .Point ) float64 {
xSquared := float64 (vector .X * vector .X )
ySquared := float64 (vector .Y * vector .Y )
return math .Sqrt (xSquared + ySquared )
}
func sporeScaleToLength(vector geometry .Point , target float64 ) geometry .Point {
length := sporeVectorLength (vector )
if length > 0 {
vector .X = float64 (vector .X / length )
vector .Y = float64 (vector .Y / length )
}
vector .X = float64 (vector .X * target )
vector .Y = float64 (vector .Y * target )
return vector
}
func rectangleEdges(rect geometry .Rectangle ) []*tEdgePoint {
topLeft := rect .Position ()
topRight := rect .TopRight ()
bottomLeft := rect .BottomLeft ()
bottomRight := rect .BottomRight ()
return []*tEdgePoint {
{u : topLeft , v : topRight },
{u : topLeft , v : bottomLeft },
{u : bottomRight , v : topRight },
{u : bottomRight , v : bottomLeft },
}
}
type tEdgePoint struct {
u, v geometry .Point
}
func segmentDistance(a1 , a2 , b1 , b2 , direction geometry .Point ) float64 {
return math .Min (
traceRays (a1 , a2 , b1 , b2 , direction ),
traceRays (b1 , b2 , a1 , a2 , direction .Negate ()),
)
}
func traceRays(a1 , a2 , b1 , b2 , direction geometry .Point ) float64 {
result := math .Inf (1 )
edgeIntersection , intersects := segmentIntersection (
a1 ,
a2 .Sub (a1 ),
b1 .Add (direction ),
b2 .Sub (b1 ),
)
edgeCase := intersects && !fuzzyPointEqual (edgeIntersection , a1 ) && !fuzzyPointEqual (edgeIntersection , a2 )
intersection , intersects := segmentIntersection (a1 , a2 .Sub (a1 ), b1 , direction )
endpointHit := false
if intersects {
if fuzzyPointEqual (intersection , a1 ) == fuzzyPointEqual (intersection , a2 ) || edgeCase {
result = math .Min (result , intersection .Sub (b1 ).Length ())
} else {
endpointHit = true
}
}
intersection , intersects = segmentIntersection (a1 , a2 .Sub (a1 ), b2 , direction )
if intersects && (endpointHit || fuzzyPointEqual (intersection , a1 ) == fuzzyPointEqual (intersection , a2 ) || edgeCase ) {
result = math .Min (result , intersection .Sub (b2 ).Length ())
}
return result
}
func segmentIntersection(p , r , q , s geometry .Point ) (geometry .Point , bool ) {
pq := q .Sub (p )
pqCrossR := pq .Cross (r )
rCrossS := r .Cross (s )
t := pq .Cross (s ) / rCrossS
u := pqCrossR / rCrossS
if rCrossS == 0 {
if pqCrossR != 0 {
return geometry .Point {}, false
}
center := q .Add (s .Scale (0.5 ))
d1 := p .Distance (center )
d2 := p .Add (r ).Distance (center )
length := s .Length () * 0.5
if d1 < d2 && d1 <= length {
return p , true
}
if d2 <= length {
return p .Add (r ), true
}
return geometry .Point {}, false
}
if t >= 0 && t <= 1 && u >= 0 && u <= 1 {
return p .Add (r .Scale (t )), true
}
return geometry .Point {}, false
}
func fuzzyPointEqual(first , second geometry .Point ) bool {
return math .Abs (first .X -second .X ) <= 0.05 && math .Abs (first .Y -second .Y ) <= 0.05
}
The pages are generated with Golds v0.8.7 . (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 .