mirror of https://github.com/tidwall/tile38.git
171 lines
3.6 KiB
Go
171 lines
3.6 KiB
Go
|
// Copyright 2018 Joshua J Baker. All rights reserved.
|
||
|
// Use of this source code is governed by an MIT-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package geometry
|
||
|
|
||
|
// Line is a open series of points
|
||
|
type Line struct {
|
||
|
baseSeries
|
||
|
}
|
||
|
|
||
|
// Valid ...
|
||
|
func (line *Line) Valid() bool {
|
||
|
if !WorldPolygon.ContainsLine(line) {
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// NewLine creates a new Line
|
||
|
func NewLine(points []Point, opts *IndexOptions) *Line {
|
||
|
line := new(Line)
|
||
|
line.baseSeries = makeSeries(points, true, false, opts)
|
||
|
return line
|
||
|
}
|
||
|
|
||
|
// Move ...
|
||
|
func (line *Line) Move(deltaX, deltaY float64) *Line {
|
||
|
if line == nil {
|
||
|
return nil
|
||
|
}
|
||
|
nline := new(Line)
|
||
|
nline.baseSeries = *line.baseSeries.Move(deltaX, deltaY).(*baseSeries)
|
||
|
return nline
|
||
|
}
|
||
|
|
||
|
// ContainsPoint ...
|
||
|
func (line *Line) ContainsPoint(point Point) bool {
|
||
|
if line == nil {
|
||
|
return false
|
||
|
}
|
||
|
contains := false
|
||
|
line.Search(Rect{point, point}, func(seg Segment, index int) bool {
|
||
|
if seg.Raycast(point).On {
|
||
|
contains = true
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
})
|
||
|
return contains
|
||
|
}
|
||
|
|
||
|
// IntersectsPoint ...
|
||
|
func (line *Line) IntersectsPoint(point Point) bool {
|
||
|
if line == nil {
|
||
|
return false
|
||
|
}
|
||
|
return line.ContainsPoint(point)
|
||
|
}
|
||
|
|
||
|
// ContainsRect ...
|
||
|
func (line *Line) ContainsRect(rect Rect) bool {
|
||
|
if line == nil {
|
||
|
return false
|
||
|
}
|
||
|
// Convert rect into a poly
|
||
|
return line.ContainsPoly(&Poly{Exterior: rect})
|
||
|
}
|
||
|
|
||
|
// IntersectsRect ...
|
||
|
func (line *Line) IntersectsRect(rect Rect) bool {
|
||
|
if line == nil {
|
||
|
return false
|
||
|
}
|
||
|
return rect.IntersectsLine(line)
|
||
|
}
|
||
|
|
||
|
// ContainsLine ...
|
||
|
func (line *Line) ContainsLine(other *Line) bool {
|
||
|
if line == nil || other == nil || line.Empty() || other.Empty() {
|
||
|
return false
|
||
|
}
|
||
|
// locate the first "other" segment that contains the first "line" segment.
|
||
|
lineNumSegments := line.NumSegments()
|
||
|
segIdx := -1
|
||
|
for j := 0; j < lineNumSegments; j++ {
|
||
|
if line.SegmentAt(j).ContainsSegment(other.SegmentAt(0)) {
|
||
|
segIdx = j
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if segIdx == -1 {
|
||
|
return false
|
||
|
}
|
||
|
otherNumSegments := other.NumSegments()
|
||
|
for i := 1; i < otherNumSegments; i++ {
|
||
|
lineSeg := line.SegmentAt(segIdx)
|
||
|
otherSeg := other.SegmentAt(i)
|
||
|
if lineSeg.ContainsSegment(otherSeg) {
|
||
|
continue
|
||
|
}
|
||
|
if otherSeg.A == lineSeg.A {
|
||
|
// reverse it
|
||
|
if segIdx == 0 {
|
||
|
return false
|
||
|
}
|
||
|
segIdx--
|
||
|
i--
|
||
|
} else if otherSeg.A == lineSeg.B {
|
||
|
// forward it
|
||
|
if segIdx == lineNumSegments-1 {
|
||
|
return false
|
||
|
}
|
||
|
segIdx++
|
||
|
i--
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// IntersectsLine ...
|
||
|
func (line *Line) IntersectsLine(other *Line) bool {
|
||
|
if line == nil || other == nil || line.Empty() || other.Empty() {
|
||
|
return false
|
||
|
}
|
||
|
if !line.Rect().IntersectsRect(other.Rect()) {
|
||
|
return false
|
||
|
}
|
||
|
if line.NumPoints() > other.NumPoints() {
|
||
|
line, other = other, line
|
||
|
}
|
||
|
lineNumSegments := line.NumSegments()
|
||
|
for i := 0; i < lineNumSegments; i++ {
|
||
|
segA := line.SegmentAt(i)
|
||
|
var intersects bool
|
||
|
other.Search(segA.Rect(), func(segB Segment, _ int) bool {
|
||
|
if segA.IntersectsSegment(segB) {
|
||
|
intersects = true
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
})
|
||
|
if intersects {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// ContainsPoly ...
|
||
|
func (line *Line) ContainsPoly(poly *Poly) bool {
|
||
|
if line == nil || poly == nil || line.Empty() || poly.Empty() {
|
||
|
return false
|
||
|
}
|
||
|
rect := poly.Rect()
|
||
|
if rect.Min.X != rect.Max.X && rect.Min.Y != rect.Max.Y {
|
||
|
return false
|
||
|
}
|
||
|
// polygon can fit in a straight (vertial or horizontal) line
|
||
|
points := [2]Point{rect.Min, rect.Max}
|
||
|
var other Line
|
||
|
other.baseSeries.points = points[:]
|
||
|
other.baseSeries.rect = rect
|
||
|
return line.ContainsLine(&other)
|
||
|
}
|
||
|
|
||
|
// IntersectsPoly ...
|
||
|
func (line *Line) IntersectsPoly(poly *Poly) bool {
|
||
|
return poly.IntersectsLine(line)
|
||
|
}
|