3 Star 0 Fork 0

江苏岚江智能科技有限公司 / supply-point

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
types.go 9.51 KB
一键复制 编辑 原始数据 按行查看 历史
吴文凯 提交于 2023-05-08 10:51 . update
package supply_point
import (
"bytes"
"github.com/fogleman/gg"
"image/png"
"io"
"net/http"
"strconv"
"strings"
)
type PathPoint struct {
X, Y int
Lat, Lng float64
Tim int64 // 毫秒时间戳
IsSupplyPoint int // 是否补给点
Yaw float64
}
type supplyPoint struct {
p []*PathPoint
maxX, maxY, minX, minY int
IsManualSetSupplyPoint bool
}
func (sp *supplyPoint) GetPathPoint() []*PathPoint {
return sp.p
}
func NewSupplyPoint(csv []byte) *supplyPoint {
p, maxX, maxY, minX, minY := getPointFromCsv(csv)
sp := &supplyPoint{
p: p,
maxX: maxX,
maxY: maxY,
minX: minX,
minY: minY,
}
for _, t := range p {
if t.IsSupplyPoint != 0 {
sp.IsManualSetSupplyPoint = true
}
}
return sp
}
func NewSupplyPointByCsvPath(url string) (*supplyPoint, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return NewSupplyPoint(data), nil
}
// getPointFromCsv 从csv中获取坐标点
func getPointFromCsv(csv []byte) ([]*PathPoint, int, int, int, int) {
points := strings.Split(string(csv), "\r\n") // 处理csv格式
var pathPoint []*PathPoint
for i, point := range points {
if i == 0 {
continue
}
//fmt.Println(point, points[i-1], point == points[i-1])
//if point == points[i-1] {
// continue
//}
if point == "" {
continue
}
xy := strings.Split(point, ",") // 处理csv格式
if len(xy) < 3 {
continue
}
lat, _ := strconv.ParseFloat(xy[0], 64) // string to float64
lng, _ := strconv.ParseFloat(xy[1], 64)
yaw, _ := strconv.ParseFloat(xy[2], 64)
var (
isSupplyPoint = 0
tim int64
)
if len(xy) >= 4 {
isSupplyPoint, _ = strconv.Atoi(xy[3])
}
if len(xy) >= 5 {
tim, _ = strconv.ParseInt(xy[4], 10, 64)
}
// 将坐标*10000000 (相当于保留坐标的7位小数)
pathPoint = append(pathPoint, &PathPoint{X: int(lat * 1000000), Y: int(lng * 1000000), Lat: lat, Lng: lng, Yaw: yaw, Tim: tim, IsSupplyPoint: isSupplyPoint})
}
// 从坐标点集中找到边界点
// 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, maxX, maxY, minX, minY
}
// GetCorner 找到所有的拐点
// 返回拐点的index
func (sp *supplyPoint) GetCorner() []int {
var (
corner []int
)
// 三个点可以连成一个三角形,通过判断三角形三边的比例,来判断是否是直线
var isLine = func(p1, p2, p3 int) bool {
// 临边
d0 := getEuclideanDistance(sp.p[p1], sp.p[p2])
d1 := getEuclideanDistance(sp.p[p2], sp.p[p3])
// 斜边
d2 := getEuclideanDistance(sp.p[p1], sp.p[p3])
if d0 == 0 || d1 == 0 || d2 == 0 {
return true
}
// 计算三角形三边的比例
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, prevPointIndex)
prevPointIndex, i = prevPointIndex+1, prevPointIndex+1
recallCount = -1
}
recallCount++
}
}
//lines = append(lines, line)
}
recall(sp.p, 4)
return corner
}
// GroupByCorner 将拐点分组
func (sp *supplyPoint) GroupByCorner(corner []int) [][]int {
if len(corner) <= 0 {
return nil
}
var (
group [][]int
g = []int{corner[0]}
)
for i := 1; i < len(corner); i++ {
// todo 根据距离判断
if corner[i]-corner[i-1] < 4 {
for j := corner[i-1] + 1; j <= corner[i]; j++ {
g = append(g, j)
}
} else {
// todo 根据曲率判断是否真的是拐点
if len(g) >= 2 {
// 拐点的个数大于等于2个,才能分组,否则当作噪音去掉
group = append(group, g)
}
g = []int{corner[i]}
}
}
if len(g) >= 2 {
group = append(group, g)
}
return group
}
// GetAllSupplyPointForXy 获取全部补给点-xy坐标版(直接取中间的一个就好了)
// referenceValue 参考值,用来决策取哪一边的点
func (sp *supplyPoint) GetAllSupplyPointForXy(cornerGroup [][]int, referenceValue int) []int {
// 取单数
var (
cornerGroupNew [][]int
whichSide = 0 // 假设拐点存在且只存在路径的两侧,并且按照规则一边一个依次排列(【cornerGroupIndex%2 == whichSide】)
)
if referenceValue >= 0 {
// 寻找距离最近的点
var (
minDistance = getEuclideanDistance(
&PathPoint{
X: 0,
Y: 0,
},
&PathPoint{
X: sp.maxX - sp.minX,
Y: sp.maxY - sp.minY,
},
)
minDistanceIndex = 0
)
for i := 0; i < len(cornerGroup); i++ {
d := getEuclideanDistance(sp.p[cornerGroup[i][0]], sp.p[referenceValue])
if d < minDistance {
minDistance = d
minDistanceIndex = i
}
}
whichSide = minDistanceIndex % 2
}
// todo 判断是否是按照规则一边一个依次排列,将异常的cornerGroup去掉
for i := 0; i < len(cornerGroup); i++ {
if i%2 == whichSide {
cornerGroupNew = append(cornerGroupNew, cornerGroup[i])
}
}
var (
supplyPoint []int
)
for _, g := range cornerGroupNew {
supplyPoint = append(supplyPoint, g[len(g)/2])
}
return supplyPoint
}
// GetSupplyPointWithDisByXy 根据距离和xy版的全部补给点筛选出符合条件的补给点
func (sp *supplyPoint) GetSupplyPointWithDisByXy(xy []int, dis float64) []*PathPoint {
var (
defaultSupplyDistance = dis // 默认最大补给距离
surplusSupplyDistance = dis // 剩余补给距离
supplyPoint []*PathPoint
prevPointIndex = 1 // 上一个点的index 用于遍历路径所有的点计算距离
supplyPointDistance []float64 // 对应每个补给点之间的距离
)
for _, t := range xy {
dis := 0.0
for i := prevPointIndex; i <= t; i++ {
dis += GetDistance(sp.p[i-1].Lat, sp.p[i-1].Lng, sp.p[i].Lat, sp.p[i].Lng)
}
supplyPointDistance = append(supplyPointDistance, dis)
prevPointIndex = t + 1
}
var addSupplyPoint = func(index int) {
supplyPoint = append(supplyPoint, sp.p[xy[index]])
surplusSupplyDistance = defaultSupplyDistance
}
for i := 0; i < len(supplyPointDistance)-1; i++ {
if supplyPointDistance[i] > surplusSupplyDistance {
addSupplyPoint(i)
continue
}
if supplyPointDistance[i]+supplyPointDistance[i+1] > surplusSupplyDistance {
addSupplyPoint(i)
continue
}
surplusSupplyDistance = surplusSupplyDistance - supplyPointDistance[i]
}
return supplyPoint
}
// GetSupplyPointWithTimeByXy 根据时间和xy版的全部补给点筛选出符合条件的补给点
func (sp *supplyPoint) GetSupplyPointWithTimeByXy(xy []int, tim int64) []*PathPoint {
var (
defaultSupplyTime = tim // 默认最大补给时间
surplusSupplyTime = tim // 剩余补给时间
supplyPoint []*PathPoint
prevPointIndex = 1 // 上一个点的index 用于遍历路径所有的点计算时间
supplyPointTime []int64 // 对应每个补给点之间的时间
)
for _, t := range xy {
var tim int64 = 0
for i := prevPointIndex; i <= t; i++ {
tim += sp.p[i].Tim - sp.p[i-1].Tim
}
supplyPointTime = append(supplyPointTime, tim)
prevPointIndex = t + 1
}
var addSupplyPoint = func(index int) {
supplyPoint = append(supplyPoint, sp.p[xy[index]])
surplusSupplyTime = defaultSupplyTime
}
for i := 0; i < len(supplyPointTime)-1; i++ {
if supplyPointTime[i] > surplusSupplyTime {
addSupplyPoint(i)
continue
}
if supplyPointTime[i]+supplyPointTime[i+1] > surplusSupplyTime {
addSupplyPoint(i)
continue
}
surplusSupplyTime = surplusSupplyTime - supplyPointTime[i]
}
return supplyPoint
}
func (sp *supplyPoint) GetManualSupplyPoint() []*PathPoint {
var supplyPoint []*PathPoint
for _, p := range sp.p {
if p.IsSupplyPoint != 0 {
supplyPoint = append(supplyPoint, p)
}
}
return supplyPoint
}
// GetThumbnail 获取缩略图
func (sp *supplyPoint) GetThumbnail() []byte {
dc := gg.NewContext(sp.maxX-sp.minX+20, sp.maxY-sp.minY+20)
dc.SetRGB(0, 0, 0)
dc.Clear()
for i := 1; i < len(sp.p); i++ {
dc.SetRGBA(1, 0, 0, 1)
dc.SetLineWidth(5)
dc.DrawLine(float64(sp.p[i-1].X+10), float64(sp.p[i-1].Y+10), float64(sp.p[i].X+10), float64(sp.p[i].Y+10))
dc.Stroke()
}
data := bytes.NewBuffer(nil)
//jpeg.Encode(data, dc.Image(), &jpeg.Options{Quality: 100})
png.Encode(data, dc.Image())
return data.Bytes()
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/jiangsu-lanjiang-intelligent/supply-point.git
git@gitee.com:jiangsu-lanjiang-intelligent/supply-point.git
jiangsu-lanjiang-intelligent
supply-point
supply-point
v0.1.12

搜索帮助

344bd9b3 5694891 D2dac590 5694891