fixed dependencies
This commit is contained in:
40
vendor/github.com/paulmach/orb/planar/README.md
generated
vendored
Normal file
40
vendor/github.com/paulmach/orb/planar/README.md
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# orb/planar [](https://pkg.go.dev/github.com/paulmach/orb/planar)
|
||||
|
||||
The geometries defined in the `orb` package are generic 2d geometries.
|
||||
Depending on what projection they're in, e.g. lon/lat or flat on the plane,
|
||||
area and distance calculations are different. This package implements methods
|
||||
that assume the planar or Euclidean context.
|
||||
|
||||
## Examples
|
||||
|
||||
Area of 3-4-5 triangle:
|
||||
|
||||
```go
|
||||
r := orb.Ring{{0, 0}, {3, 0}, {0, 4}, {0, 0}}
|
||||
a := planar.Area(r)
|
||||
|
||||
fmt.Println(a)
|
||||
// Output:
|
||||
// 6
|
||||
```
|
||||
|
||||
Distance between two points:
|
||||
|
||||
```go
|
||||
d := planar.Distance(orb.Point{0, 0}, orb.Point{3, 4})
|
||||
|
||||
fmt.Println(d)
|
||||
// Output:
|
||||
// 5
|
||||
```
|
||||
|
||||
Length/circumference of a 3-4-5 triangle:
|
||||
|
||||
```go
|
||||
r := orb.Ring{{0, 0}, {3, 0}, {0, 4}, {0, 0}}
|
||||
l := planar.Length(r)
|
||||
|
||||
fmt.Println(l)
|
||||
// Output:
|
||||
// 12
|
||||
```
|
||||
284
vendor/github.com/paulmach/orb/planar/area.go
generated
vendored
Normal file
284
vendor/github.com/paulmach/orb/planar/area.go
generated
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
// Package planar computes properties on geometries assuming they are
|
||||
// in 2d euclidean space.
|
||||
package planar
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/paulmach/orb"
|
||||
)
|
||||
|
||||
// Area returns the area of the geometry in the 2d plane.
|
||||
func Area(g orb.Geometry) float64 {
|
||||
// TODO: make faster non-centroid version.
|
||||
_, a := CentroidArea(g)
|
||||
return a
|
||||
}
|
||||
|
||||
// CentroidArea returns both the centroid and the area in the 2d plane.
|
||||
// Since the area is need for the centroid, return both.
|
||||
// Polygon area will always be >= zero. Ring area my be negative if it has
|
||||
// a clockwise winding orider.
|
||||
func CentroidArea(g orb.Geometry) (orb.Point, float64) {
|
||||
if g == nil {
|
||||
return orb.Point{}, 0
|
||||
}
|
||||
|
||||
switch g := g.(type) {
|
||||
case orb.Point:
|
||||
return multiPointCentroid(orb.MultiPoint{g}), 0
|
||||
case orb.MultiPoint:
|
||||
return multiPointCentroid(g), 0
|
||||
case orb.LineString:
|
||||
return multiLineStringCentroid(orb.MultiLineString{g}), 0
|
||||
case orb.MultiLineString:
|
||||
return multiLineStringCentroid(g), 0
|
||||
case orb.Ring:
|
||||
return ringCentroidArea(g)
|
||||
case orb.Polygon:
|
||||
return polygonCentroidArea(g)
|
||||
case orb.MultiPolygon:
|
||||
return multiPolygonCentroidArea(g)
|
||||
case orb.Collection:
|
||||
return collectionCentroidArea(g)
|
||||
case orb.Bound:
|
||||
return CentroidArea(g.ToRing())
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("geometry type not supported: %T", g))
|
||||
}
|
||||
|
||||
func multiPointCentroid(mp orb.MultiPoint) orb.Point {
|
||||
if len(mp) == 0 {
|
||||
return orb.Point{}
|
||||
}
|
||||
|
||||
x, y := 0.0, 0.0
|
||||
for _, p := range mp {
|
||||
x += p[0]
|
||||
y += p[1]
|
||||
}
|
||||
|
||||
num := float64(len(mp))
|
||||
return orb.Point{x / num, y / num}
|
||||
}
|
||||
|
||||
func multiLineStringCentroid(mls orb.MultiLineString) orb.Point {
|
||||
point := orb.Point{}
|
||||
dist := 0.0
|
||||
|
||||
if len(mls) == 0 {
|
||||
return orb.Point{}
|
||||
}
|
||||
|
||||
validCount := 0
|
||||
for _, ls := range mls {
|
||||
c, d := lineStringCentroidDist(ls)
|
||||
if d == math.Inf(1) {
|
||||
continue
|
||||
}
|
||||
|
||||
dist += d
|
||||
validCount++
|
||||
|
||||
if d == 0 {
|
||||
d = 1.0
|
||||
}
|
||||
|
||||
point[0] += c[0] * d
|
||||
point[1] += c[1] * d
|
||||
}
|
||||
|
||||
if validCount == 0 {
|
||||
return orb.Point{}
|
||||
}
|
||||
|
||||
if dist == math.Inf(1) || dist == 0.0 {
|
||||
point[0] /= float64(validCount)
|
||||
point[1] /= float64(validCount)
|
||||
return point
|
||||
}
|
||||
|
||||
point[0] /= dist
|
||||
point[1] /= dist
|
||||
|
||||
return point
|
||||
}
|
||||
|
||||
func lineStringCentroidDist(ls orb.LineString) (orb.Point, float64) {
|
||||
dist := 0.0
|
||||
point := orb.Point{}
|
||||
|
||||
if len(ls) == 0 {
|
||||
return orb.Point{}, math.Inf(1)
|
||||
}
|
||||
|
||||
// implicitly move everything to near the origin to help with roundoff
|
||||
offset := ls[0]
|
||||
for i := 0; i < len(ls)-1; i++ {
|
||||
p1 := orb.Point{
|
||||
ls[i][0] - offset[0],
|
||||
ls[i][1] - offset[1],
|
||||
}
|
||||
|
||||
p2 := orb.Point{
|
||||
ls[i+1][0] - offset[0],
|
||||
ls[i+1][1] - offset[1],
|
||||
}
|
||||
|
||||
d := Distance(p1, p2)
|
||||
|
||||
point[0] += (p1[0] + p2[0]) / 2.0 * d
|
||||
point[1] += (p1[1] + p2[1]) / 2.0 * d
|
||||
dist += d
|
||||
}
|
||||
|
||||
if dist == 0 {
|
||||
return ls[0], 0
|
||||
}
|
||||
|
||||
point[0] /= dist
|
||||
point[1] /= dist
|
||||
|
||||
point[0] += ls[0][0]
|
||||
point[1] += ls[0][1]
|
||||
return point, dist
|
||||
}
|
||||
|
||||
func ringCentroidArea(r orb.Ring) (orb.Point, float64) {
|
||||
centroid := orb.Point{}
|
||||
area := 0.0
|
||||
|
||||
if len(r) == 0 {
|
||||
return orb.Point{}, 0
|
||||
}
|
||||
|
||||
// implicitly move everything to near the origin to help with roundoff
|
||||
offsetX := r[0][0]
|
||||
offsetY := r[0][1]
|
||||
for i := 1; i < len(r)-1; i++ {
|
||||
a := (r[i][0]-offsetX)*(r[i+1][1]-offsetY) -
|
||||
(r[i+1][0]-offsetX)*(r[i][1]-offsetY)
|
||||
area += a
|
||||
|
||||
centroid[0] += (r[i][0] + r[i+1][0] - 2*offsetX) * a
|
||||
centroid[1] += (r[i][1] + r[i+1][1] - 2*offsetY) * a
|
||||
}
|
||||
|
||||
if area == 0 {
|
||||
return r[0], 0
|
||||
}
|
||||
|
||||
// no need to deal with first and last vertex since we "moved"
|
||||
// that point the origin (multiply by 0 == 0)
|
||||
|
||||
area /= 2
|
||||
centroid[0] /= 6 * area
|
||||
centroid[1] /= 6 * area
|
||||
|
||||
centroid[0] += offsetX
|
||||
centroid[1] += offsetY
|
||||
|
||||
return centroid, area
|
||||
}
|
||||
|
||||
func polygonCentroidArea(p orb.Polygon) (orb.Point, float64) {
|
||||
if len(p) == 0 {
|
||||
return orb.Point{}, 0
|
||||
}
|
||||
|
||||
centroid, area := ringCentroidArea(p[0])
|
||||
area = math.Abs(area)
|
||||
if len(p) == 1 {
|
||||
if area == 0 {
|
||||
c, _ := lineStringCentroidDist(orb.LineString(p[0]))
|
||||
return c, 0
|
||||
}
|
||||
return centroid, area
|
||||
}
|
||||
|
||||
holeArea := 0.0
|
||||
weightedHoleCentroid := orb.Point{}
|
||||
for i := 1; i < len(p); i++ {
|
||||
hc, ha := ringCentroidArea(p[i])
|
||||
ha = math.Abs(ha)
|
||||
|
||||
holeArea += ha
|
||||
weightedHoleCentroid[0] += hc[0] * ha
|
||||
weightedHoleCentroid[1] += hc[1] * ha
|
||||
}
|
||||
|
||||
totalArea := area - holeArea
|
||||
if totalArea == 0 {
|
||||
c, _ := lineStringCentroidDist(orb.LineString(p[0]))
|
||||
return c, 0
|
||||
}
|
||||
|
||||
centroid[0] = (area*centroid[0] - weightedHoleCentroid[0]) / totalArea
|
||||
centroid[1] = (area*centroid[1] - weightedHoleCentroid[1]) / totalArea
|
||||
|
||||
return centroid, totalArea
|
||||
}
|
||||
|
||||
func multiPolygonCentroidArea(mp orb.MultiPolygon) (orb.Point, float64) {
|
||||
point := orb.Point{}
|
||||
area := 0.0
|
||||
|
||||
for _, p := range mp {
|
||||
c, a := polygonCentroidArea(p)
|
||||
|
||||
point[0] += c[0] * a
|
||||
point[1] += c[1] * a
|
||||
|
||||
area += a
|
||||
}
|
||||
|
||||
if area == 0 {
|
||||
return orb.Point{}, 0
|
||||
}
|
||||
|
||||
point[0] /= area
|
||||
point[1] /= area
|
||||
|
||||
return point, area
|
||||
}
|
||||
|
||||
func collectionCentroidArea(c orb.Collection) (orb.Point, float64) {
|
||||
point := orb.Point{}
|
||||
area := 0.0
|
||||
|
||||
max := maxDim(c)
|
||||
for _, g := range c {
|
||||
if g.Dimensions() != max {
|
||||
continue
|
||||
}
|
||||
|
||||
c, a := CentroidArea(g)
|
||||
|
||||
point[0] += c[0] * a
|
||||
point[1] += c[1] * a
|
||||
|
||||
area += a
|
||||
}
|
||||
|
||||
if area == 0 {
|
||||
return orb.Point{}, 0
|
||||
}
|
||||
|
||||
point[0] /= area
|
||||
point[1] /= area
|
||||
|
||||
return point, area
|
||||
}
|
||||
|
||||
func maxDim(c orb.Collection) int {
|
||||
max := 0
|
||||
for _, g := range c {
|
||||
if d := g.Dimensions(); d > max {
|
||||
max = d
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
122
vendor/github.com/paulmach/orb/planar/contains.go
generated
vendored
Normal file
122
vendor/github.com/paulmach/orb/planar/contains.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package planar
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/paulmach/orb"
|
||||
)
|
||||
|
||||
// RingContains returns true if the point is inside the ring.
|
||||
// Points on the boundary are considered in.
|
||||
func RingContains(r orb.Ring, point orb.Point) bool {
|
||||
if !r.Bound().Contains(point) {
|
||||
return false
|
||||
}
|
||||
|
||||
c, on := rayIntersect(point, r[0], r[len(r)-1])
|
||||
if on {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := 0; i < len(r)-1; i++ {
|
||||
inter, on := rayIntersect(point, r[i], r[i+1])
|
||||
if on {
|
||||
return true
|
||||
}
|
||||
|
||||
if inter {
|
||||
c = !c
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// PolygonContains checks if the point is within the polygon.
|
||||
// Points on the boundary are considered in.
|
||||
func PolygonContains(p orb.Polygon, point orb.Point) bool {
|
||||
if !RingContains(p[0], point) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 1; i < len(p); i++ {
|
||||
if RingContains(p[i], point) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// MultiPolygonContains checks if the point is within the multi-polygon.
|
||||
// Points on the boundary are considered in.
|
||||
func MultiPolygonContains(mp orb.MultiPolygon, point orb.Point) bool {
|
||||
for _, p := range mp {
|
||||
if PolygonContains(p, point) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Original implementation: http://rosettacode.org/wiki/Ray-casting_algorithm#Go
|
||||
func rayIntersect(p, s, e orb.Point) (intersects, on bool) {
|
||||
if s[0] > e[0] {
|
||||
s, e = e, s
|
||||
}
|
||||
|
||||
if p[0] == s[0] {
|
||||
if p[1] == s[1] {
|
||||
// p == start
|
||||
return false, true
|
||||
} else if s[0] == e[0] {
|
||||
// vertical segment (s -> e)
|
||||
// return true if within the line, check to see if start or end is greater.
|
||||
if s[1] > e[1] && s[1] >= p[1] && p[1] >= e[1] {
|
||||
return false, true
|
||||
}
|
||||
|
||||
if e[1] > s[1] && e[1] >= p[1] && p[1] >= s[1] {
|
||||
return false, true
|
||||
}
|
||||
}
|
||||
|
||||
// Move the y coordinate to deal with degenerate case
|
||||
p[0] = math.Nextafter(p[0], math.Inf(1))
|
||||
} else if p[0] == e[0] {
|
||||
if p[1] == e[1] {
|
||||
// matching the end point
|
||||
return false, true
|
||||
}
|
||||
|
||||
p[0] = math.Nextafter(p[0], math.Inf(1))
|
||||
}
|
||||
|
||||
if p[0] < s[0] || p[0] > e[0] {
|
||||
return false, false
|
||||
}
|
||||
|
||||
if s[1] > e[1] {
|
||||
if p[1] > s[1] {
|
||||
return false, false
|
||||
} else if p[1] < e[1] {
|
||||
return true, false
|
||||
}
|
||||
} else {
|
||||
if p[1] > e[1] {
|
||||
return false, false
|
||||
} else if p[1] < s[1] {
|
||||
return true, false
|
||||
}
|
||||
}
|
||||
|
||||
rs := (p[1] - s[1]) / (p[0] - s[0])
|
||||
ds := (e[1] - s[1]) / (e[0] - s[0])
|
||||
|
||||
if rs == ds {
|
||||
return false, true
|
||||
}
|
||||
|
||||
return rs <= ds, false
|
||||
}
|
||||
21
vendor/github.com/paulmach/orb/planar/distance.go
generated
vendored
Normal file
21
vendor/github.com/paulmach/orb/planar/distance.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package planar
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/paulmach/orb"
|
||||
)
|
||||
|
||||
// Distance returns the distance between two points in 2d euclidean geometry.
|
||||
func Distance(p1, p2 orb.Point) float64 {
|
||||
d0 := (p1[0] - p2[0])
|
||||
d1 := (p1[1] - p2[1])
|
||||
return math.Sqrt(d0*d0 + d1*d1)
|
||||
}
|
||||
|
||||
// DistanceSquared returns the square of the distance between two points in 2d euclidean geometry.
|
||||
func DistanceSquared(p1, p2 orb.Point) float64 {
|
||||
d0 := (p1[0] - p2[0])
|
||||
d1 := (p1[1] - p2[1])
|
||||
return d0*d0 + d1*d1
|
||||
}
|
||||
173
vendor/github.com/paulmach/orb/planar/distance_from.go
generated
vendored
Normal file
173
vendor/github.com/paulmach/orb/planar/distance_from.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package planar
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/paulmach/orb"
|
||||
)
|
||||
|
||||
// DistanceFromSegment returns the point's distance from the segment [a, b].
|
||||
func DistanceFromSegment(a, b, point orb.Point) float64 {
|
||||
return math.Sqrt(DistanceFromSegmentSquared(a, b, point))
|
||||
}
|
||||
|
||||
// DistanceFromSegmentSquared returns point's squared distance from the segement [a, b].
|
||||
func DistanceFromSegmentSquared(a, b, point orb.Point) float64 {
|
||||
x := a[0]
|
||||
y := a[1]
|
||||
dx := b[0] - x
|
||||
dy := b[1] - y
|
||||
|
||||
if dx != 0 || dy != 0 {
|
||||
t := ((point[0]-x)*dx + (point[1]-y)*dy) / (dx*dx + dy*dy)
|
||||
|
||||
if t > 1 {
|
||||
x = b[0]
|
||||
y = b[1]
|
||||
} else if t > 0 {
|
||||
x += dx * t
|
||||
y += dy * t
|
||||
}
|
||||
}
|
||||
|
||||
dx = point[0] - x
|
||||
dy = point[1] - y
|
||||
|
||||
return dx*dx + dy*dy
|
||||
}
|
||||
|
||||
// DistanceFrom returns the distance from the boundary of the geometry in
|
||||
// the units of the geometry.
|
||||
func DistanceFrom(g orb.Geometry, p orb.Point) float64 {
|
||||
d, _ := DistanceFromWithIndex(g, p)
|
||||
return d
|
||||
}
|
||||
|
||||
// DistanceFromWithIndex returns the minimum euclidean distance
|
||||
// from the boundary of the geometry plus the index of the sub-geometry
|
||||
// that was the match.
|
||||
func DistanceFromWithIndex(g orb.Geometry, p orb.Point) (float64, int) {
|
||||
if g == nil {
|
||||
return math.Inf(1), -1
|
||||
}
|
||||
|
||||
switch g := g.(type) {
|
||||
case orb.Point:
|
||||
return Distance(g, p), 0
|
||||
case orb.MultiPoint:
|
||||
return multiPointDistanceFrom(g, p)
|
||||
case orb.LineString:
|
||||
return lineStringDistanceFrom(g, p)
|
||||
case orb.MultiLineString:
|
||||
dist := math.Inf(1)
|
||||
index := -1
|
||||
for i, ls := range g {
|
||||
if d, _ := lineStringDistanceFrom(ls, p); d < dist {
|
||||
dist = d
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return dist, index
|
||||
case orb.Ring:
|
||||
return lineStringDistanceFrom(orb.LineString(g), p)
|
||||
case orb.Polygon:
|
||||
return polygonDistanceFrom(g, p)
|
||||
case orb.MultiPolygon:
|
||||
dist := math.Inf(1)
|
||||
index := -1
|
||||
for i, poly := range g {
|
||||
if d, _ := polygonDistanceFrom(poly, p); d < dist {
|
||||
dist = d
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return dist, index
|
||||
case orb.Collection:
|
||||
dist := math.Inf(1)
|
||||
index := -1
|
||||
for i, ge := range g {
|
||||
if d, _ := DistanceFromWithIndex(ge, p); d < dist {
|
||||
dist = d
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return dist, index
|
||||
case orb.Bound:
|
||||
return DistanceFromWithIndex(g.ToRing(), p)
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("geometry type not supported: %T", g))
|
||||
}
|
||||
|
||||
func multiPointDistanceFrom(mp orb.MultiPoint, p orb.Point) (float64, int) {
|
||||
dist := math.Inf(1)
|
||||
index := -1
|
||||
|
||||
for i := range mp {
|
||||
if d := DistanceSquared(mp[i], p); d < dist {
|
||||
dist = d
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return math.Sqrt(dist), index
|
||||
}
|
||||
|
||||
func lineStringDistanceFrom(ls orb.LineString, p orb.Point) (float64, int) {
|
||||
dist := math.Inf(1)
|
||||
index := -1
|
||||
|
||||
for i := 0; i < len(ls)-1; i++ {
|
||||
if d := segmentDistanceFromSquared(ls[i], ls[i+1], p); d < dist {
|
||||
dist = d
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return math.Sqrt(dist), index
|
||||
}
|
||||
|
||||
func polygonDistanceFrom(p orb.Polygon, point orb.Point) (float64, int) {
|
||||
if len(p) == 0 {
|
||||
return math.Inf(1), -1
|
||||
}
|
||||
|
||||
dist, index := lineStringDistanceFrom(orb.LineString(p[0]), point)
|
||||
for i := 1; i < len(p); i++ {
|
||||
d, i := lineStringDistanceFrom(orb.LineString(p[i]), point)
|
||||
if d < dist {
|
||||
dist = d
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return dist, index
|
||||
}
|
||||
|
||||
func segmentDistanceFromSquared(p1, p2, point orb.Point) float64 {
|
||||
x := p1[0]
|
||||
y := p1[1]
|
||||
dx := p2[0] - x
|
||||
dy := p2[1] - y
|
||||
|
||||
if dx != 0 || dy != 0 {
|
||||
t := ((point[0]-x)*dx + (point[1]-y)*dy) / (dx*dx + dy*dy)
|
||||
|
||||
if t > 1 {
|
||||
x = p2[0]
|
||||
y = p2[1]
|
||||
} else if t > 0 {
|
||||
x += dx * t
|
||||
y += dy * t
|
||||
}
|
||||
}
|
||||
|
||||
dx = point[0] - x
|
||||
dy = point[1] - y
|
||||
|
||||
return dx*dx + dy*dy
|
||||
}
|
||||
12
vendor/github.com/paulmach/orb/planar/length.go
generated
vendored
Normal file
12
vendor/github.com/paulmach/orb/planar/length.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package planar
|
||||
|
||||
import (
|
||||
"github.com/paulmach/orb"
|
||||
"github.com/paulmach/orb/internal/length"
|
||||
)
|
||||
|
||||
// Length returns the length of the boundary of the geometry
|
||||
// using 2d euclidean geometry.
|
||||
func Length(g orb.Geometry) float64 {
|
||||
return length.Length(g, Distance)
|
||||
}
|
||||
Reference in New Issue
Block a user