Golang实现检测某坐标点在区域范围内

实现某坐标点是否在某区域范围内
代码

package cronjob

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

//实例化一个面
func NewGISArea(points []Point) *Area {
	area := new(Area)
	area.Points = points
	return area
}

type Point struct {
	Lng float64 `json:"lng"` //经度(180°W-180°E) -180 - 0 - 180
	Lat float64 `json:"lat"` //纬度(90°S-90°N)-90 -0 -90
}
type Area struct {
	Points []Point //多边形坐标 顺时针方向
}

//判断一个点是否在一个面内
//如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
//@param point  指定点坐标
func (a *Area) PointInArea(point Point) bool {
	pointNum := len(a.Points) //点个数
	intersectCount := 0 //cross points count of x
	precision := 2e-10  //浮点类型计算时候与0比较时候的容差
	p1 := Point{}       //neighbour bound vertices
	p2 := Point{}
	p := point //测试点

	p1 = a.Points[0] //left vertex
	for i := 0; i < pointNum; i++ {
		if (p.Lng == p1.Lng && p.Lat == p1.Lat) {
			return true
		}
		p2 = a.Points[i%pointNum]
		if (p.Lat < math.Min(p1.Lat, p2.Lat) || p.Lat > math.Max(p1.Lat, p2.Lat)) {
			p1 = p2
			continue //next ray left point
		}

		if (p.Lat > math.Min(p1.Lat, p2.Lat) && p.Lat < math.Max(p1.Lat, p2.Lat)) {
			if (p.Lng <= math.Max(p1.Lng, p2.Lng)) { //x is before of ray
				if (p1.Lat == p2.Lat && p.Lng >= math.Min(p1.Lng, p2.Lng)) {
					return true
				}

				if (p1.Lng == p2.Lng) { //ray is vertical
					if (p1.Lng == p.Lng) { //overlies on a vertical ray
						return true
					} else { //before ray
						intersectCount++
					}
				} else { //cross point on the left side
					xinters := (p.Lat-p1.Lat)*(p2.Lng-p1.Lng)/(p2.Lat-p1.Lat) + p1.Lng
					if (math.Abs(p.Lng-xinters) < precision) {
						return true
					}

					if (p.Lng < xinters) { //before ray
						intersectCount++
					}
				}
			}
		} else {                                      //special case when ray is crossing through the vertex
			if (p.Lat == p2.Lat && p.Lng <= p2.Lng) { //p crossing over p2
				p3 := a.Points[(i+1)%pointNum]
				if (p.Lat >= math.Min(p1.Lat, p3.Lat) && p.Lat <= math.Max(p1.Lat, p3.Lat)) {
					intersectCount++
				} else {
					intersectCount += 2
				}
			}
		}
		p1 = p2 //next ray left point
	}
	if intersectCount%2 == 0 { //偶数在多边形外
		return false
	} else { //奇数在多边形内
		return true
	}
}

/**
	CheckNewGISArea 检测坐标点是否在某一区域内
	Param:	areastring 	区域范围       string
		   	pointLng   	检测坐标点 经度 string
		   	pointLat   	检测坐标点 纬度 string
	Return:	bool
			false  		否
           	true  		是
 */
func CheckNewGISArea(areastring string,pointLng string,pointLat string) bool {
	var poi string
	poi = "118.183506,39.626009,118.190501,39.626009,118.190501,39.618406,118.183506,39.618406,118.152262,39.709224,118.16106,39.709224,118.16106,39.704288,118.152262,39.704288"
	poi = areastring
	strpoi := strings.Split(poi,",")
	var pois []Point
	for i:=0; i<len(strpoi); i=i+2 {
		fmt.Println("Lng:" + strpoi[i] + ",Lat:" + strpoi[i+1])
		//string到float64/32
		float64a,_ := strconv.ParseFloat(strpoi[i], 64)
		float64b,_ := strconv.ParseFloat(strpoi[i+1], 64)
		pois = append(pois, Point{float64a,float64b})	//结构体数组赋值
		fmt.Println(pois)
	}
	//points := []Point{{Lng:1,Lat:1},{Lng:-1,Lat:2},{Lng:-3,Lat:8},{Lng:0,Lat:4},{Lng:2.1,Lat:6.8},{Lng:9,Lat:-3.1}}
	fmt.Println(pois)
	area := NewGISArea(pois)
	var positionLng float64
	var positionLat float64
	positionLng,_ = strconv.ParseFloat(pointLng,64)
	positionLat,_ = strconv.ParseFloat(pointLat,64)
	point := Point{Lng:positionLng,Lat:positionLat}
	rt := area.PointInArea(point)
	fmt.Print("点是否在多边形内:",rt)
	return rt
}

测试代码:

package cronjob

// 作测试文件名要注意 需要带_test字样
import (
	"fmt"
	"strconv"
	"strings"
	"testing"
)

func TestNewGISArea(t *testing.T) {
	var poi string
	poi = "118.183506,39.626009,118.190501,39.626009,118.190501,39.618406,118.183506,39.618406,118.152262,39.709224,118.16106,39.709224,118.16106,39.704288,118.152262,39.704288"
	strpoi := strings.Split(poi,",")
	var pois []Point
	for i:=0; i<len(strpoi); i=i+2 {
		fmt.Println("Lng:" + strpoi[i] + ",Lat:" + strpoi[i+1])
		//string到float64/32
		float64a,_ := strconv.ParseFloat(strpoi[i], 64)
		float64b,_ := strconv.ParseFloat(strpoi[i+1], 64)
		pois = append(pois, Point{float64a,float64b})	//结构体数组赋值
		fmt.Println(pois)
	}
	//points := []Point{{Lng:1,Lat:1},{Lng:-1,Lat:2},{Lng:-3,Lat:8},{Lng:0,Lat:4},{Lng:2.1,Lat:6.8},{Lng:9,Lat:-3.1}}
	fmt.Println(pois)
	area := NewGISArea(pois)
	var positionLng float64
	var positionLat float64
	positionLng = 118.183506
	positionLat = 39.626009
	point := Point{Lng:positionLng,Lat:positionLat}
	rt := area.PointInArea(point)
	fmt.Print("点是否在多边形内:",rt)
}


上一篇:Linux 安装 JDK(以 JDK8 为例)


下一篇:JDK的卸载与安装(简洁流程)