fixed dependencies
This commit is contained in:
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
|
||||
}
|
||||
Reference in New Issue
Block a user