代码拉取完成,页面将自动刷新
package supply_point
import (
"fmt"
"io"
"math"
"os"
"strconv"
"strings"
)
// readPathPoint 从文件中读取坐标点
// 会将坐标缩小,用于图形展示和计算
func readPathPoint(name string) []*PathPoint {
//filep, _ := filepath.Abs(name)
f, err := os.Open(name) // 打开文件 - 不用管
if err != nil {
panic("open path point error:" + err.Error() + ". name:" + name)
}
data, _ := io.ReadAll(f) // 读取文件
points := strings.Split(string(data), "\r\n") // 处理csv格式
var pathPoint []*PathPoint
for i, point := range points {
// 跳过第一行数据,第一行是列名
if i == 0 {
continue
}
// 排除掉重复的点
if point == points[i-1] {
continue
}
// 排除掉空行
if point == "" {
continue
}
xy := strings.Split(point, ",") // 处理csv格式
lat, _ := strconv.ParseFloat(xy[0], 64) // string to float64
lng, _ := strconv.ParseFloat(xy[1], 64)
// 将坐标*1000000 (相当于保留坐标的6位小数)
pathPoint = append(pathPoint, &PathPoint{X: int(lat * 1000000), Y: int(lng * 1000000)})
}
// 从坐标点集中找到边界点
// maxX, minX, maxY, minY 组成一个矩形,可以包含所有的坐标点
var (
maxX = -90000000
minX = 90000000
maxY = -180000000
minY = 180000000
)
for _, p := range pathPoint {
if p.X > maxX {
maxX = p.X
}
if p.X < minX {
minX = p.X
}
if p.Y > maxY {
maxY = p.Y
}
if p.Y < minY {
minY = p.Y
}
}
// 适配maxX, minX, maxY, minY 组成的矩形,使坐标可以包含在一个矩形中
for i := 0; i < len(pathPoint); i++ {
pathPoint[i].X = pathPoint[i].X - minX
pathPoint[i].Y = pathPoint[i].Y - minY
}
return pathPoint
}
// getCorner 从坐标点集中找到拐点
func getCorner(p []*PathPoint) ([][]*PathPoint, []*PathPoint) {
var (
lines [][]*PathPoint
line []*PathPoint
corner []*PathPoint
)
line = append(line, p[0], p[1])
// 三个点可以连成一个三角形,通过判断三角形三边的比例,来判断是否是直线
var isLine = func(p1, p2, p3 int) bool {
// 临边
d0 := getEuclideanDistance(p[p1], p[p2])
d1 := getEuclideanDistance(p[p2], p[p3])
// 斜边
d2 := getEuclideanDistance(p[p1], p[p3])
// 计算三角形三边的比例
fmt.Println(p1, p2, p3, "isline", d0, d1, d2, d2/(d0+d1), math.Acos((d0*d0+d1*d1-d2*d2)/(2*d0*d1)))
criticalValue := 0.999 // 值越大,越敏感
return d2/(d0+d1) > criticalValue
}
// 用来找拐点的方法
// p 所有的坐标集合
// needRecallCount 需要回溯的次数(需要经历多少个点才能证明这个点是真的拐点)
var recall = func(p []*PathPoint, needRecallCount int) {
var (
recallCount = 0 // 回溯次数
lineStart = 0 // 直线的起点index
prevPointIndex = 1 // 上一个点的index(遇到拐角时,这个就等于拐角的index)
)
// 从第三个点开始遍历坐标集合
for i := 2; i < len(p); i++ {
// 判断是否是直线
isline := isLine(lineStart, prevPointIndex, i)
if isline {
prevPointIndex = i // 设置当前index为prevPointIndex
recallCount = 0 // 回溯次数清零
line = append(line, p[i]) // 将当前点加入到直线中
} else {
if recallCount >= needRecallCount {
fmt.Println("corner", prevPointIndex)
lines = append(lines, line)
line = []*PathPoint{p[prevPointIndex], p[prevPointIndex+1]}
lineStart = prevPointIndex
corner = append(corner, p[prevPointIndex])
prevPointIndex, i = prevPointIndex+1, prevPointIndex+1
recallCount = -1
}
recallCount++
}
}
lines = append(lines, line)
}
recall(p, 4)
return lines, corner
}
// 计算欧式距离
func getEuclideanDistance(p1, p2 *PathPoint) float64 {
return math.Sqrt(math.Pow(float64(p1.X-p2.X), 2) + math.Pow(float64(p1.Y-p2.Y), 2))
}
// GetDistance 根据经纬度获取距离
func GetDistance(lat1, lng1, lat2, lng2 float64) float64 {
radius := 6378137.0 // 赤道半径 (单位m)
rad := float64(57.2957795130823)
lat1 = lat1 / rad
lng1 = lng1 / rad
lat2 = lat2 / rad
lng2 = lng2 / rad
s := math.Acos(math.Cos(lat1)*math.Cos(lat2)*math.Cos(lng2-lng1)+math.Sin(lat1)*math.Sin(lat2)) * radius
if math.IsNaN(s) {
return 0
}
return s
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。