...
1 package geo
2
3 import (
4 "math"
5 "sort"
6 )
7
8 type Ellipse struct {
9 Center *Point
10 Rx float64
11 Ry float64
12 }
13
14 func NewEllipse(center *Point, rx, ry float64) *Ellipse {
15 return &Ellipse{
16 Center: center,
17 Rx: rx,
18 Ry: ry,
19 }
20 }
21
22 func (e Ellipse) Intersections(segment Segment) []*Point {
23
24
25
26
27
28
29
30 intersections := []*Point{}
31
32
33
34 a := e.Rx
35 b := e.Ry
36 a2 := a * a
37 b2 := b * b
38 if a <= 0 || b <= 0 {
39 return nil
40 }
41
42
43
44 x1 := segment.Start.X - e.Center.X
45 y1 := segment.Start.Y - e.Center.Y
46 x2 := segment.End.X - e.Center.X
47 y2 := segment.End.Y - e.Center.Y
48
49
50 if x1 == x2 {
51
52
53 intersection1 := NewPoint(x1, +b*math.Sqrt(a2-x1*x1)/a)
54
55 intersection2 := intersection1.Copy()
56 intersection2.Y *= -1
57
58 isPointOnLine := func(p *Point) bool {
59 ps := []float64{p.Y, y1, y2}
60 sort.Slice(ps, func(i, j int) bool {
61 return ps[i] < ps[j]
62 })
63 return ps[1] == p.Y
64 }
65
66 if isPointOnLine(intersection1) {
67 intersections = append(intersections, intersection1)
68 }
69
70 if intersection2.Y != 0.0 && isPointOnLine(intersection2) {
71 intersections = append(intersections, intersection2)
72 }
73
74 for _, p := range intersections {
75 p.X += e.Center.X
76 p.Y += e.Center.Y
77 }
78 return intersections
79 }
80
81
82
83
84 m := (y2 - y1) / (x2 - x1)
85 c := y1 - m*x1
86 isPointOnLine := func(p *Point) bool {
87 return PrecisionCompare(p.DistanceToLine(NewPoint(x1, y1), NewPoint(x2, y2)), 0, PRECISION) == 0
88 }
89
90
91
92
93
94
95 denom := a2*m*m + b2
96
97 root := math.Sqrt(a2 * b2 * (denom - c*c))
98
99 intersection1 := NewPoint((-m*c*a2+root)/denom, (c*b2+m*root)/denom)
100 intersection2 := NewPoint((-m*c*a2-root)/denom, (c*b2-m*root)/denom)
101
102 if isPointOnLine(intersection1) {
103 intersections = append(intersections, intersection1)
104 }
105 if !intersection1.Equals(intersection2) && isPointOnLine(intersection2) {
106 intersections = append(intersections, intersection2)
107 }
108
109 for _, p := range intersections {
110 p.X += e.Center.X
111 p.Y += e.Center.Y
112 }
113 return intersections
114 }
115
View as plain text