forked from go-spatial/tegola
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathline.go
140 lines (122 loc) · 3.35 KB
/
line.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package basic
import (
"fmt"
"github.com/go-spatial/tegola"
"github.com/go-spatial/tegola/maths"
)
// Line is a basic line type which is made up of two or more points that don't
// intersect.
// TODO: We don't really check to make sure the points don't intersect.
type Line []Point
// Just to make basic collection only usable with basic types.
func (Line) basicType() {}
func (Line) String() string { return "Line" }
func (l Line) Direction() maths.WindingOrder { return maths.WindingOrderOfLine(l) }
func (l Line) AsPts() []maths.Pt {
var line []maths.Pt
for _, p := range l {
line = append(line, p.AsPt())
}
return line
}
// TODO: gdey remove this function when we have moved over to geomLinestring.
func (l Line) AsGeomLineString() (ln [][2]float64) {
for i := range l {
ln = append(ln, [2]float64{l[i].X(), l[i].Y()})
}
return ln
}
// Contains tells you weather the given point is contained by the Linestring.
// This assumes the linestring is a connected linestring.
func (l Line) Contains(pt Point) bool {
pt0 := l[len(l)-1]
ptln := maths.Line{pt.AsPt(), maths.Pt{pt.X() + 1, pt.Y()}}
count := 0
for _, pt1 := range l {
ln := maths.Line{pt0.AsPt(), pt1.AsPt()}
if ipt, ok := maths.Intersect(ln, ptln); ok {
if ipt.IsEqual(pt.AsPt()) {
return false
}
if ln.InBetween(ipt) && ipt.X < pt.X() {
count++
}
}
pt0 = pt1
}
return count%2 != 0
}
func (l Line) ContainsLine(ln Line) bool {
for _, pt := range ln {
if !l.Contains(pt) {
return false
}
}
return true
}
// NewLine creates a line given pairs for floats.
func NewLine(pointPairs ...float64) Line {
var line Line
if (len(pointPairs) % 2) != 0 {
panic(fmt.Sprintf("NewLine requires pair of points. %v", len(pointPairs)%2))
}
for i := 0; i < len(pointPairs); i += 2 {
line = append(line, Point{pointPairs[i], pointPairs[i+1]})
}
return line
}
func NewLineFromPt(points ...maths.Pt) Line {
var line Line
for _, p := range points {
line = append(line, Point{p.X, p.Y})
}
return line
}
func NewLineTruncatedFromPt(points ...maths.Pt) Line {
var line Line
for _, p := range points {
line = append(line, Point{float64(int64(p.X)), float64(int64(p.Y))})
}
return line
}
func NewLineFromSubPoints(points ...tegola.Point) (l Line) {
l = make(Line, 0, len(points))
for i := range points {
l = append(l, Point{points[i].X(), points[i].Y()})
}
return l
}
func NewLineFrom2Float64(points ...[2]float64) (l Line) {
l = make(Line, 0, len(points))
for i := range points {
l = append(l, Point{points[i][0], points[i][1]})
}
return l
}
// Subpoints return the points in a line.
func (l Line) Subpoints() (points []tegola.Point) {
points = make([]tegola.Point, 0, len(l))
for i := range l {
points = append(points, tegola.Point(l[i]))
}
return points
}
// MultiLine is a set of lines.
type MultiLine []Line
func NewMultiLine(pointPairLines ...[]float64) (ml MultiLine) {
for _, pp := range pointPairLines {
ml = append(ml, NewLine(pp...))
}
return ml
}
func (MultiLine) String() string { return "MultiLine" }
// Just to make basic collection only usable with basic types.
func (MultiLine) basicType() {}
// Lines are the lines in a Multiline
func (ml MultiLine) Lines() (lines []tegola.LineString) {
lines = make([]tegola.LineString, 0, len(ml))
for i := range ml {
lines = append(lines, tegola.LineString(ml[i]))
}
return lines
}