forked from go-spatial/tegola
-
Notifications
You must be signed in to change notification settings - Fork 0
/
line.go
124 lines (108 loc) · 2.96 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
package basic
import (
"fmt"
"github.com/terranodo/tegola"
"github.com/terranodo/tegola/maths"
)
// Line is a basic line type which is made up of two or more points that don't
// interect.
// 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
}
// 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
}
// 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
}