rts-sim-testing-service/ts/simulation/wayside/memory/wayside_memory_map.go

391 lines
12 KiB
Go
Raw Normal View History

2023-08-01 14:54:11 +08:00
package memory
import (
"fmt"
2023-08-11 16:48:21 +08:00
"math"
"sort"
"strconv"
2023-09-21 14:54:27 +08:00
"strings"
2023-08-01 14:54:11 +08:00
"sync"
2023-09-21 14:54:27 +08:00
"joylink.club/rtsssimulation/repository"
proto2 "joylink.club/rtsssimulation/repository/model/proto"
2023-09-21 14:54:27 +08:00
2023-08-01 14:54:11 +08:00
"google.golang.org/protobuf/proto"
2023-10-17 17:51:26 +08:00
"joylink.club/bj-rtsts-server/db/dbquery"
2023-08-01 14:54:11 +08:00
"joylink.club/bj-rtsts-server/db/model"
2023-08-10 14:18:55 +08:00
"joylink.club/bj-rtsts-server/dto"
2023-10-26 10:05:28 +08:00
"joylink.club/bj-rtsts-server/sys_error"
2023-10-26 17:16:07 +08:00
"joylink.club/bj-rtsts-server/ts/protos/graphicData"
"joylink.club/bj-rtsts-server/ts/protos/state"
2023-08-01 14:54:11 +08:00
)
var (
2023-09-22 15:15:04 +08:00
giTypeMap sync.Map
giNameMap sync.Map
2023-09-22 15:15:04 +08:00
giDataMap sync.Map
)
2023-08-01 14:54:11 +08:00
2023-08-02 15:50:46 +08:00
// 将发布的地图数据放入内存中
2023-09-21 14:54:27 +08:00
func PublishMapVerifyStructure(graphic *model.PublishedGi) {
giTypeMap.Store(graphic.ID, graphicData.PictureType(graphic.Type))
giNameMap.Store(graphic.Name, graphic.ID)
var message proto.Message
switch graphicData.PictureType(graphic.Type) {
case graphicData.PictureType_StationLayout:
message = &graphicData.RtssGraphicStorage{}
case graphicData.PictureType_RelayCabinetLayout:
message = &graphicData.RelayCabinetGraphicStorage{}
case graphicData.PictureType_Psl:
message = &graphicData.PslGraphicStorage{}
2023-10-13 15:19:17 +08:00
case graphicData.PictureType_IBP:
message = &graphicData.IBPGraphicStorage{}
}
err := proto.Unmarshal(graphic.Proto, message)
if err != nil {
2023-09-26 14:12:26 +08:00
panic(&dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("[id:%d]proto数据反序列化失败:%s", graphic.ID, err)})
}
giDataMap.Store(graphic.ID, message)
2023-08-02 15:50:46 +08:00
// 初始化地图结构
2023-09-22 15:15:04 +08:00
switch graphicData.PictureType(graphic.Type) {
case graphicData.PictureType_StationLayout:
graphicStorage := message.(*graphicData.RtssGraphicStorage)
2023-09-22 15:15:04 +08:00
giUidMap.Store(graphic.ID, initStationUid(graphicStorage))
case graphicData.PictureType_RelayCabinetLayout:
graphicStorage := message.(*graphicData.RelayCabinetGraphicStorage)
giUidMap.Store(graphic.ID, initRelayCabinetUid(graphicStorage))
2023-09-21 14:54:27 +08:00
}
2023-08-01 14:54:11 +08:00
}
func GenerateElementUid(city, lineId string, stationIndexList []string, code string) string {
sort.Strings(stationIndexList)
var idArr []string
idArr = append(idArr, city, lineId)
idArr = append(idArr, stationIndexList...)
2023-09-21 14:54:27 +08:00
idArr = append(idArr, code)
return strings.Join(idArr, "_")
2023-08-01 14:54:11 +08:00
}
// 移除内存中的地图信息
func DeleteMapVerifyStructure(mapId int32) {
2023-09-26 14:12:26 +08:00
giTypeMap.Delete(mapId)
giDataMap.Delete(mapId)
giUidMap.Delete(mapId)
2023-08-01 14:54:11 +08:00
}
func QueryGiType(mapId int32) graphicData.PictureType {
2023-09-26 14:12:26 +08:00
value, ok := giTypeMap.Load(mapId)
if !ok {
2023-10-17 17:51:26 +08:00
graphic, err := dbquery.PublishedGi.Debug().Where(dbquery.PublishedGi.ID.Eq(mapId)).First() // 当缓存缺失新地图时,查询一次
if err != nil {
panic(&dto.ErrorDto{Code: dto.LogicError, Message: fmt.Sprintf("[mapId:%d]类型映射错误 :%v", mapId, value)})
}
PublishMapVerifyStructure(graphic)
return graphicData.PictureType(graphic.Type)
2023-09-26 14:12:26 +08:00
}
return value.(graphicData.PictureType)
}
func QueryOnlyGiType(mapId int32) graphicData.PictureType {
value, ok := giTypeMap.Load(mapId)
if !ok {
panic(sys_error.New(fmt.Sprintf("[mapId:%d]不存在", mapId)))
}
return value.(graphicData.PictureType)
}
func QueryGiData[T proto.Message](mapId int32) T {
value, _ := giDataMap.Load(mapId)
return value.(T)
}
func QueryGiId(name string) int32 {
value, _ := giNameMap.Load(name)
return value.(int32)
}
2023-08-10 14:18:55 +08:00
// 根据区段道岔偏移量返回linkID和link相对偏移量
2023-10-26 10:05:28 +08:00
func QueryEcsLinkByDeviceInfo(repo *repository.Repository, mapId int32, status *state.TrainState) (int32, int64, bool, bool, int64) {
id := status.HeadDeviceId
if status.DevicePort == "" {
2023-09-27 18:11:16 +08:00
uid := QueryUidByMidAndComId(mapId, id, &graphicData.Section{})
2023-10-26 10:05:28 +08:00
return sectionMapToEcsLink(repo, uid, status)
} else {
2023-09-27 18:11:16 +08:00
uid := QueryUidByMidAndComId(mapId, id, &graphicData.Turnout{})
2023-10-26 10:05:28 +08:00
return turnoutMapToEcsLink(repo, uid, status)
}
2023-08-11 16:48:21 +08:00
}
func GetStorageIBPMapData(mapCode string) *graphicData.IBPGraphicStorage {
// 处理关联的IBP盘信息
if mapCode == "" {
return nil
}
ibpId, ok := giNameMap.Load(mapCode)
if !ok {
return nil
}
ibpMapData, ok := giDataMap.Load(ibpId)
if !ok {
return nil
}
return ibpMapData.(*graphicData.IBPGraphicStorage)
}
2023-08-11 16:48:21 +08:00
// 根据物理区段上的偏移量基于区段A端找到所在link的linkId与偏移量
2023-10-26 10:05:28 +08:00
func sectionMapToEcsLink(repo *repository.Repository, id string, status *state.TrainState) (int32, int64, bool, bool, int64) {
runDirection := status.RunDirection
2023-09-28 09:29:04 +08:00
section := repo.FindPhysicalSection(id)
if section == nil {
2023-10-26 10:05:28 +08:00
panic(sys_error.New(fmt.Sprintf("地图不存在uid:%s缓存", id)))
2023-08-11 16:48:21 +08:00
}
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
2023-10-26 15:48:17 +08:00
// 检查区段长度是否足够放下列车
status.HeadOffset = checkDeviceContainTrain(status.HeadOffset, status.TrainLength, bo-ao, id)
2023-10-26 15:48:17 +08:00
link := section.ALinkPosition().Link()
2023-10-19 17:42:01 +08:00
// 是否从A到B统一坐标
ak, bk := convertRepoBaseKm(repo, section.AKilometer()), convertRepoBaseKm(repo, section.BKilometer())
akv, bkv := ak.Value, bk.Value
// 上行
var up, abDirection bool
if runDirection {
2023-10-19 17:42:01 +08:00
abDirection = akv < bkv
if abDirection {
up = ao < bo
} else {
up = ao > bo
}
} else {
2023-10-19 17:42:01 +08:00
abDirection = akv > bkv
if abDirection {
up = ao < bo
} else {
up = ao > bo
}
}
2023-10-26 10:05:28 +08:00
linkId, _ := strconv.Atoi(link.Identity.Id())
trainKilometer := concertTrainKilometer(akv, status.HeadOffset, up)
2023-10-09 15:03:01 +08:00
if ao < bo {
2023-10-26 10:05:28 +08:00
return int32(linkId), ao + status.HeadOffset, up, abDirection, trainKilometer
2023-08-10 14:18:55 +08:00
} else {
2023-10-26 10:05:28 +08:00
return int32(linkId), ao - status.HeadOffset, up, abDirection, trainKilometer
2023-08-11 16:48:21 +08:00
}
}
// 根据道岔上的偏移量基于岔心位置找到所在link的linkId与偏移量
2023-10-26 10:05:28 +08:00
func turnoutMapToEcsLink(repo *repository.Repository, id string, status *state.TrainState) (int32, int64, bool, bool, int64) {
port, runDirection := status.DevicePort, status.RunDirection
2023-09-28 09:29:04 +08:00
turnout := repo.FindTurnout(id)
if turnout == nil {
2023-10-26 10:05:28 +08:00
panic(sys_error.New(fmt.Sprintf("不存在道岔【uid:%s】", id)))
}
var portPosition *repository.LinkPosition
var crossKm, portKm *proto2.Kilometer
switch port {
case "A":
portPosition = turnout.FindLinkPositionByPort(proto2.Port_A)
portKm = turnout.GetTurnoutKm(proto2.Port_A)
case "B":
portPosition = turnout.FindLinkPositionByPort(proto2.Port_B)
portKm = turnout.GetTurnoutKm(proto2.Port_B)
case "C":
portPosition = turnout.FindLinkPositionByPort(proto2.Port_C)
portKm = turnout.GetTurnoutKm(proto2.Port_C)
default:
2023-10-26 10:05:28 +08:00
panic(sys_error.New(fmt.Sprintf("无效端口【%s】偏移量", port)))
}
// 岔心公里标
crossKm = turnout.GetTurnoutKm(proto2.Port_None)
portKm, err := repo.ConvertKilometer(portKm, crossKm.CoordinateSystem)
if err != nil {
2023-10-26 10:05:28 +08:00
panic(sys_error.New("公里标转换出错", err))
}
2023-10-26 15:48:17 +08:00
// 检查link偏移
status.HeadOffset = checkDeviceContainTrain(status.HeadOffset, status.TrainLength, crossKm.Value-portKm.Value, id)
2023-10-26 15:48:17 +08:00
// 关联link
link := portPosition.Link()
isStart := link.ARelation().Device().Id() == id
up := runDirection
if (portKm.Value > crossKm.Value) != isStart {
up = !runDirection
}
pointTo := (portKm.Value > crossKm.Value) == runDirection
2023-10-26 10:05:28 +08:00
trainKilometer := concertTrainKilometer(crossKm.Value, status.HeadOffset, pointTo)
linkId, _ := strconv.Atoi(link.Identity.Id())
if isStart {
2023-10-26 10:05:28 +08:00
return int32(linkId), status.HeadOffset, up, pointTo, trainKilometer
} else {
// 道岔长度
turnoutLen := int64(math.Abs(float64(portKm.Value - crossKm.Value)))
2023-10-26 10:05:28 +08:00
return int32(linkId), portPosition.Offset() + turnoutLen - status.HeadOffset, up, pointTo, trainKilometer
2023-08-10 14:18:55 +08:00
}
}
// 根据linkID和link相对偏移量返回区段道岔偏移量
2023-08-15 10:18:39 +08:00
// 设备ID、端口、偏移量、上下行、AB走向
2023-09-20 18:21:00 +08:00
func QueryDeviceByCalcLink(repo *repository.Repository, id string, offset int64, up bool) (
deviceId, port string, deviceOffset int64, runDirection, pointTo bool, km int64) {
link := repo.FindLink(id)
if link == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("未找到link【%s】", id)})
}
if offset > link.Length() {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("偏移【%d】超出link范围【%d】", offset, link.Length())})
}
2023-09-27 16:49:10 +08:00
// 判断是否在道岔上
onTurnout, isA := isOnLinkTurnout(link, offset)
if onTurnout {
2023-09-28 15:43:20 +08:00
return ecsLinkMapToTurnout(repo, isA, offset, up, link)
2023-09-27 16:49:10 +08:00
} else {
2023-10-19 17:42:01 +08:00
return ecsLinkMapToSection(repo, offset, up, link)
2023-09-27 16:49:10 +08:00
}
}
// 是否在link的道岔上
func isOnLinkTurnout(link *repository.Link, offset int64) (bool, bool) {
2023-09-20 18:21:00 +08:00
aTp := link.ARelation()
2023-09-27 16:49:10 +08:00
var turnoutOffset int64
if aTp != nil {
turnoutOffset = aTp.Turnout().FindLinkPositionByPort(aTp.Port()).Offset()
}
if offset <= turnoutOffset {
return true, true
}
2023-09-20 18:21:00 +08:00
bTp := link.BRelation()
2023-09-27 16:49:10 +08:00
if bTp != nil {
turnoutOffset = bTp.Turnout().FindLinkPositionByPort(bTp.Port()).Offset()
return offset >= turnoutOffset, false
}
return false, false
}
// 处理在道岔上link映射
2023-09-28 15:43:20 +08:00
func ecsLinkMapToTurnout(repo *repository.Repository, isA bool, offset int64, up bool, link *repository.Link) (
2023-09-27 16:49:10 +08:00
deviceId, port string, deviceOffset int64, runDirection, pointTo bool, km int64) {
tp := link.ARelation()
if !isA {
tp = link.BRelation()
}
deviceId = tp.Turnout().Id()
tpOffset := tp.Turnout().FindLinkPositionByPort(tp.Port()).Offset()
2023-09-28 15:43:20 +08:00
crossKmInfo, portKmInfo := tp.Turnout().GetTurnoutKm(proto2.Port_None), tp.Turnout().GetTurnoutKm(tp.Port())
portKmInfo, err := repo.ConvertKilometer(portKmInfo, crossKmInfo.CoordinateSystem)
if err != nil {
panic(err)
}
2023-09-28 15:43:20 +08:00
crossKm, portKm := crossKmInfo.Value, portKmInfo.Value
2023-09-27 16:49:10 +08:00
if isA {
deviceOffset = tpOffset - (tpOffset - offset)
pointTo = !up
} else {
2023-09-20 18:21:00 +08:00
deviceOffset = link.Length() - offset
2023-09-27 16:49:10 +08:00
pointTo = up
}
// 查询公里标大于端口公里标
if crossKm > portKm {
km = crossKm - deviceOffset
} else {
km = crossKm + deviceOffset
2023-09-28 15:43:20 +08:00
}
if up && isA { // link offset 趋大A端岔心 ---> 边界
runDirection = crossKm < portKm
} else if up && !isA { // link offset 趋大B端边界 ---> 岔心
runDirection = crossKm > portKm
} else if !up && isA { // link offset 趋小A端边界 ---> 岔心
runDirection = crossKm > portKm
} else { // link offset 趋小B端岔心 ---> 边界
runDirection = crossKm < portKm
2023-09-27 16:49:10 +08:00
}
switch tp.Port() {
case proto2.Port_A:
port = "A"
case proto2.Port_B:
port = "B"
case proto2.Port_C:
port = "C"
}
return
}
// 处理在道岔上link映射
2023-10-19 17:42:01 +08:00
func ecsLinkMapToSection(repo *repository.Repository, offset int64, up bool, link *repository.Link) (
2023-09-27 16:49:10 +08:00
deviceId, port string, deviceOffset int64, runDirection, pointTo bool, km int64) {
var section *repository.PhysicalSection
for _, s := range link.PhysicalSections() {
ao, bo := s.ALinkPosition().Offset(), s.BLinkPosition().Offset()
2023-10-19 18:04:21 +08:00
if (ao < offset && offset <= bo) || (bo < offset && offset <= ao) {
2023-09-27 16:49:10 +08:00
section = s
break
2023-09-20 18:21:00 +08:00
}
}
2023-09-27 16:49:10 +08:00
if section == nil {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("未找到link设备偏移【%d】", offset)})
}
// 元素ID
deviceId = section.Id()
// link偏移变大方向
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
2023-10-19 17:42:01 +08:00
ak, bk := convertRepoBaseKm(repo, section.AKilometer()), convertRepoBaseKm(repo, section.BKilometer())
akv, bkv := ak.Value, bk.Value
2023-09-27 16:49:10 +08:00
if up {
if ao < bo {
2023-10-19 17:42:01 +08:00
runDirection = akv < bkv
} else {
2023-10-19 17:42:01 +08:00
runDirection = akv > bkv
}
2023-09-27 16:49:10 +08:00
} else {
if ao > bo {
2023-10-19 17:42:01 +08:00
runDirection = akv < bkv
} else {
2023-10-19 17:42:01 +08:00
runDirection = akv > bkv
}
2023-09-27 16:49:10 +08:00
}
2023-10-19 17:42:01 +08:00
pointTo = runDirection == (akv < bkv)
2023-09-27 16:49:10 +08:00
// a点偏移 大于 b点偏移
if ao > bo {
deviceOffset = ao - offset
} else {
deviceOffset = offset - ao
}
// a点公里标 大于 b点公里标
2023-10-19 17:42:01 +08:00
if akv > bkv {
km = akv - deviceOffset
2023-09-27 16:49:10 +08:00
} else {
2023-10-19 17:42:01 +08:00
km = akv + deviceOffset
2023-09-27 16:49:10 +08:00
}
2023-09-20 18:21:00 +08:00
return
2023-08-11 16:48:21 +08:00
}
// 查找列车的公里标
func concertTrainKilometer(kilometer, offset int64, tendTo bool) int64 {
if tendTo {
return kilometer - offset
} else {
return kilometer + offset
}
}
2023-10-19 17:42:01 +08:00
// 转换成统一坐标公里标
func convertRepoBaseKm(r *repository.Repository, km *proto2.Kilometer) *proto2.Kilometer {
k, err := r.ConvertKilometer(km, r.GetCoordinateInfo().Coordinate)
if err != nil {
panic(err)
}
return k
2023-10-19 17:42:01 +08:00
}
2023-10-26 10:05:28 +08:00
2023-10-26 15:48:17 +08:00
// 检查列车是否可以放到设备上
func checkDeviceContainTrain(offset, trainLen, deviceLen int64, deviceName string) int64 {
2023-10-26 15:48:17 +08:00
l := int64(math.Abs(float64(deviceLen)))
if offset > l {
panic(sys_error.New(fmt.Sprintf("偏移【%d】超出【%s】范围【%d】", offset, deviceName, l)))
2023-10-26 10:05:28 +08:00
}
if trainLen > offset { // 如果列车长度超过设置offset
offset = trainLen
}
2023-10-26 15:48:17 +08:00
if offset > l {
panic(sys_error.New(fmt.Sprintf("列车长度【%d】超出【%s】范围【%d】", trainLen, deviceName, l)))
2023-10-26 10:05:28 +08:00
}
return offset
}