2023-08-01 14:54:11 +08:00
|
|
|
|
package memory
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2023-08-09 15:34:19 +08:00
|
|
|
|
"sort"
|
2023-09-21 14:54:27 +08:00
|
|
|
|
"strings"
|
2023-08-01 14:54:11 +08:00
|
|
|
|
"sync"
|
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
"joylink.club/rtsssimulation/component"
|
|
|
|
|
"joylink.club/rtsssimulation/entity"
|
2023-09-21 14:54:27 +08:00
|
|
|
|
"joylink.club/rtsssimulation/repository"
|
2023-09-21 14:57:57 +08:00
|
|
|
|
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"
|
2023-08-01 14:54:11 +08:00
|
|
|
|
)
|
|
|
|
|
|
2023-09-20 15:14:40 +08:00
|
|
|
|
var (
|
2023-09-22 15:15:04 +08:00
|
|
|
|
giTypeMap sync.Map
|
2023-10-16 14:52:58 +08:00
|
|
|
|
giNameMap sync.Map
|
2023-09-22 15:15:04 +08:00
|
|
|
|
giDataMap sync.Map
|
2023-09-20 15:14:40 +08:00
|
|
|
|
)
|
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) {
|
2023-09-25 10:34:31 +08:00
|
|
|
|
giTypeMap.Store(graphic.ID, graphicData.PictureType(graphic.Type))
|
2023-10-16 14:52:58 +08:00
|
|
|
|
giNameMap.Store(graphic.Name, graphic.ID)
|
2023-09-22 10:29:42 +08:00
|
|
|
|
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{}
|
2023-09-22 10:29:42 +08:00
|
|
|
|
}
|
|
|
|
|
err := proto.Unmarshal(graphic.Proto, message)
|
2023-09-20 15:14:40 +08:00
|
|
|
|
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)})
|
2023-09-20 15:14:40 +08:00
|
|
|
|
}
|
2023-09-22 10:29:42 +08:00
|
|
|
|
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:
|
2023-09-22 10:29:42 +08:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2023-09-22 15:13:25 +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
|
|
|
|
}
|
|
|
|
|
|
2023-09-22 15:13:25 +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 {
|
2023-11-07 10:49:15 +08:00
|
|
|
|
panic(sys_error.New(fmt.Sprintf("[mapId:%d]类型映射错误 :%v", mapId, value), err))
|
2023-10-17 17:51:26 +08:00
|
|
|
|
}
|
|
|
|
|
PublishMapVerifyStructure(graphic)
|
|
|
|
|
return graphicData.PictureType(graphic.Type)
|
2023-09-26 14:12:26 +08:00
|
|
|
|
}
|
2023-09-22 15:13:25 +08:00
|
|
|
|
return value.(graphicData.PictureType)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func QueryGiData[T proto.Message](mapId int32) T {
|
|
|
|
|
value, _ := giDataMap.Load(mapId)
|
|
|
|
|
return value.(T)
|
2023-09-20 15:14:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-19 17:09:57 +08:00
|
|
|
|
func QueryGiId(name string) int32 {
|
|
|
|
|
value, _ := giNameMap.Load(name)
|
|
|
|
|
return value.(int32)
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-27 14:57:37 +08:00
|
|
|
|
func GetStorageIBPMapData(mapCode string) *graphicData.IBPGraphicStorage {
|
2023-10-16 14:52:58 +08:00
|
|
|
|
// 处理关联的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-11-08 11:02:41 +08:00
|
|
|
|
// 转换成统一坐标公里标
|
|
|
|
|
func convertRepoBaseKm(r *repository.Repository, km *proto2.Kilometer) *proto2.Kilometer {
|
|
|
|
|
k, err := r.ConvertKilometer(km, r.GetCoordinateInfo().Coordinate)
|
2023-10-20 15:08:47 +08:00
|
|
|
|
if err != nil {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
panic(sys_error.New(fmt.Sprintf("公里标转换【%s->%s】错误", km.CoordinateSystem, r.GetCoordinateInfo().Coordinate)))
|
2023-08-10 14:18:55 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
return k
|
2023-08-10 14:18:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 根据传入link、偏移、link运行方向,查找所在设备信息
|
|
|
|
|
// 入参:仿真、linkId、link偏移量、link运行方向
|
|
|
|
|
// 输出:linkId、设备Id、设备端口、link偏移量、设备上偏移量、偏移量对应的公里标
|
|
|
|
|
func CalcInitializeLink(sim *VerifySimulation, linkId string, offset int64, up bool) (
|
2023-11-09 17:54:31 +08:00
|
|
|
|
outLinkId, deviceId, port string, outLinkOffset, deviceOffset int64, km *proto2.Kilometer, err error) {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
link := sim.Repo.FindLink(linkId)
|
2023-09-20 18:21:00 +08:00
|
|
|
|
if link == nil {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New(fmt.Sprintf("未找到link【%s】", linkId))
|
2023-09-20 18:21:00 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 获取计算link与所在偏移
|
2023-11-09 17:54:31 +08:00
|
|
|
|
outLinkId, outLinkOffset, err = findCalcLinkIdAndOffset(sim, link, offset)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
calcLink := sim.Repo.FindLink(outLinkId)
|
2023-09-27 16:49:10 +08:00
|
|
|
|
// 判断是否在道岔上
|
2023-11-08 11:02:41 +08:00
|
|
|
|
onTurnout, isA := isOnLinkTurnout(calcLink, outLinkOffset)
|
2023-09-27 16:49:10 +08:00
|
|
|
|
if onTurnout {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
deviceId, port, deviceOffset, km = calcTurnoutOffset(sim.Repo, calcLink, isA, outLinkOffset, up)
|
2023-09-27 16:49:10 +08:00
|
|
|
|
} else {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
deviceId, port, deviceOffset, km = calcSectionOffset(sim.Repo, calcLink, outLinkOffset, up)
|
2023-09-27 16:49:10 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 输出当前所在设备、端口、设备偏移
|
|
|
|
|
return
|
2023-09-27 16:49:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 列车是否在link的道岔上
|
2023-09-27 16:49:10 +08:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 查找最终的linkId与link偏移
|
|
|
|
|
// 入参:仿真、link、link偏移量
|
|
|
|
|
// 输出:linkId、link偏移量
|
2023-11-09 17:54:31 +08:00
|
|
|
|
func findCalcLinkIdAndOffset(sim *VerifySimulation, link *repository.Link, offset int64) (outId string, outOffset int64, err error) {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
if 0 <= offset && offset <= link.Length() {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
outId, outOffset, err = link.Id(), offset, nil
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
|
|
|
|
// 超出端、超出长度
|
|
|
|
|
tp, length := link.ARelation(), 0-offset
|
|
|
|
|
if offset > 0 {
|
|
|
|
|
tp, length = link.BRelation(), offset-link.Length()
|
|
|
|
|
}
|
|
|
|
|
if tp == nil {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New("列车偏移超出link位置")
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort, er1 := getTurnoutNextPort(sim, tp.Device().Id(), tp.Port().String())
|
|
|
|
|
if er1 != nil {
|
|
|
|
|
err = er1
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
|
|
|
|
var nextLink *repository.Link
|
|
|
|
|
var isB bool
|
|
|
|
|
// 寻找匹配到的link
|
|
|
|
|
for _, l := range sim.Repo.LinkList() {
|
|
|
|
|
if l.ARelation() != nil && l.ARelation().Port() == nextPort && l.ARelation().Device().Id() == tp.Device().Id() {
|
|
|
|
|
nextLink = l
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if l.BRelation() != nil && l.BRelation().Port() == nextPort && l.BRelation().Device().Id() == tp.Device().Id() {
|
|
|
|
|
nextLink = l
|
|
|
|
|
isB = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 没有找到连接信息,说明已经到尽头找不到位置
|
|
|
|
|
if nextLink == nil {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New(fmt.Sprintf("未找到对应的link信息, linkId=%s, offset=%d", link.Id(), offset))
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
|
|
|
|
// 下个link偏移
|
|
|
|
|
nextOffset := length
|
|
|
|
|
if isB {
|
|
|
|
|
nextOffset = nextLink.Length() - length
|
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
outId, outOffset, err = findCalcLinkIdAndOffset(sim, nextLink, nextOffset)
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据当前link端,寻找下一个link连接端端口
|
|
|
|
|
// 入参:仿真、道岔端口
|
|
|
|
|
// 输出:道岔端口
|
2023-11-09 17:54:31 +08:00
|
|
|
|
func getTurnoutNextPort(sim *VerifySimulation, turnoutId string, port string) (nextPort proto2.Port, err error) {
|
2023-11-09 14:19:48 +08:00
|
|
|
|
entry, ok := entity.GetEntityByUid(sim.World, turnoutId)
|
2023-11-08 11:02:41 +08:00
|
|
|
|
if !ok {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New(fmt.Sprintf("道岔不存在: World id=%d,道岔id=%s", sim.World.Id(), turnoutId))
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
|
|
|
|
if !entry.HasComponent(component.TurnoutPositionType) {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New(fmt.Sprintf("道岔没有TurnoutPosition组件: World id=%d,道岔id=%s", sim.World.Id(), turnoutId))
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
|
|
|
|
// 获取定反数据
|
|
|
|
|
pos := component.TurnoutPositionType.Get(entry)
|
2023-11-09 14:19:48 +08:00
|
|
|
|
switch port {
|
|
|
|
|
case "A":
|
2023-11-08 11:02:41 +08:00
|
|
|
|
if pos.Dw {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort = proto2.Port_B
|
2023-11-08 11:02:41 +08:00
|
|
|
|
} else {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort = proto2.Port_C
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
return
|
2023-11-09 14:19:48 +08:00
|
|
|
|
case "B":
|
2023-11-08 11:02:41 +08:00
|
|
|
|
if pos.Dw {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort = proto2.Port_A
|
2023-11-08 11:02:41 +08:00
|
|
|
|
} else {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort = proto2.Port_None
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
return
|
2023-11-09 14:19:48 +08:00
|
|
|
|
case "C":
|
2023-11-08 11:02:41 +08:00
|
|
|
|
if pos.Dw {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort = proto2.Port_None
|
2023-11-08 11:02:41 +08:00
|
|
|
|
} else {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort = proto2.Port_A
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New(fmt.Sprintf("非法端口:端口=%s", port))
|
|
|
|
|
return
|
2023-11-08 11:02:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算link offset 在道岔上的位置
|
|
|
|
|
// 入参:仿真Repository、link、是否从A端开始、link偏移量、link运行方向
|
|
|
|
|
// 输出:设备Id、设备所在端口、设备偏移量、公里标信息(地图主坐标系)
|
|
|
|
|
func calcTurnoutOffset(repo *repository.Repository, link *repository.Link, isA bool, offset int64, up bool) (
|
|
|
|
|
deviceId, port string, deviceOffset int64, km *proto2.Kilometer) {
|
2023-09-27 16:49:10 +08:00
|
|
|
|
tp := link.ARelation()
|
|
|
|
|
if !isA {
|
|
|
|
|
tp = link.BRelation()
|
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 设备ID
|
2023-09-27 16:49:10 +08:00
|
|
|
|
deviceId = tp.Turnout().Id()
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 端口信息
|
|
|
|
|
port = tp.Port().String()
|
|
|
|
|
// 设备上的偏移量
|
2023-09-27 16:49:10 +08:00
|
|
|
|
if isA {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
deviceOffset = offset
|
2023-09-27 16:49:10 +08:00
|
|
|
|
} else {
|
2023-09-20 18:21:00 +08:00
|
|
|
|
deviceOffset = link.Length() - offset
|
2023-09-27 16:49:10 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 公里标计算
|
|
|
|
|
crossKmInfo := convertRepoBaseKm(repo, tp.Turnout().GetTurnoutKm(proto2.Port_None))
|
|
|
|
|
portKmInfo := convertRepoBaseKm(repo, tp.Turnout().GetTurnoutKm(tp.Port()))
|
|
|
|
|
km = &proto2.Kilometer{CoordinateSystem: crossKmInfo.CoordinateSystem}
|
|
|
|
|
if crossKmInfo.Value > portKmInfo.Value {
|
|
|
|
|
km.Value = crossKmInfo.Value - deviceOffset
|
2023-09-27 16:49:10 +08:00
|
|
|
|
} else {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
km.Value = crossKmInfo.Value + deviceOffset
|
2023-09-27 16:49:10 +08:00
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 计算link offset 在区段上的位置
|
|
|
|
|
// 入参:仿真Repository、link、link偏移量、link运行方向
|
|
|
|
|
// 输出:设备Id、设备所在端口、设备偏移量、公里标信息(地图主坐标系)
|
|
|
|
|
func calcSectionOffset(repo *repository.Repository, link *repository.Link, offset int64, up bool) (
|
|
|
|
|
deviceId, port string, deviceOffset int64, km *proto2.Kilometer) {
|
2023-09-27 16:49:10 +08:00
|
|
|
|
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 {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
panic(sys_error.New(fmt.Sprintf("未找到link设备偏移【%d】", offset)))
|
2023-09-27 16:49:10 +08:00
|
|
|
|
}
|
|
|
|
|
// 元素ID
|
|
|
|
|
deviceId = section.Id()
|
|
|
|
|
// a点偏移 大于 b点偏移
|
2023-11-08 11:02:41 +08:00
|
|
|
|
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
|
2023-09-27 16:49:10 +08:00
|
|
|
|
if ao > bo {
|
|
|
|
|
deviceOffset = ao - offset
|
|
|
|
|
} else {
|
|
|
|
|
deviceOffset = offset - ao
|
|
|
|
|
}
|
|
|
|
|
// a点公里标 大于 b点公里标
|
2023-11-08 11:02:41 +08:00
|
|
|
|
ak, bk := convertRepoBaseKm(repo, section.AKilometer()), convertRepoBaseKm(repo, section.BKilometer())
|
|
|
|
|
km = &proto2.Kilometer{CoordinateSystem: ak.CoordinateSystem}
|
|
|
|
|
if ak.Value > bk.Value {
|
|
|
|
|
km.Value = ak.Value - deviceOffset
|
2023-09-27 16:49:10 +08:00
|
|
|
|
} else {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
km.Value = ak.Value + 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
|
|
|
|
}
|
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 根据设备查找link
|
|
|
|
|
// 入参:设备ID、端口、设备偏移
|
|
|
|
|
// 输出:linkId、link偏移
|
|
|
|
|
func QueryLinkAndOffsetByDevice(repo *repository.Repository, uid, port string, offset int64) (linkId string, linkOffset int64) {
|
|
|
|
|
if port == "" {
|
|
|
|
|
linkId, linkOffset = sectionToLink(repo, uid, offset)
|
2023-09-12 16:33:31 +08:00
|
|
|
|
} else {
|
2023-11-08 11:02:41 +08:00
|
|
|
|
linkId, linkOffset = turnoutToLink(repo, uid, port, offset)
|
2023-09-12 16:33:31 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
return
|
2023-09-12 16:33:31 +08:00
|
|
|
|
}
|
2023-10-19 17:42:01 +08:00
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 根据区段设备查找link
|
|
|
|
|
// 入参:仿真Repository、设备ID、设备偏移
|
|
|
|
|
// 输出:linkId、link偏移、公里标
|
|
|
|
|
func sectionToLink(repo *repository.Repository, uid string, offset int64) (string, int64) {
|
|
|
|
|
section := repo.FindPhysicalSection(uid)
|
|
|
|
|
if section == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("地图不存在uid:%s缓存", uid)))
|
2023-10-20 15:13:29 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
|
|
|
|
|
if ao < bo {
|
|
|
|
|
return section.ALinkPosition().Link().Id(), ao + offset
|
|
|
|
|
} else {
|
|
|
|
|
return section.ALinkPosition().Link().Id(), ao - offset
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据道岔设备查找link
|
|
|
|
|
// 入参:仿真Repository、道岔设备ID、道岔端口、设备偏移
|
|
|
|
|
// 输出:linkId、link偏移
|
|
|
|
|
func turnoutToLink(repo *repository.Repository, uid, port string, offset int64) (string, int64) {
|
|
|
|
|
turnout := repo.FindTurnout(uid)
|
|
|
|
|
if turnout == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("不存在道岔【uid:%s】", uid)))
|
|
|
|
|
}
|
|
|
|
|
var portPosition *repository.LinkPosition
|
|
|
|
|
switch port {
|
|
|
|
|
case "A":
|
|
|
|
|
portPosition = turnout.FindLinkPositionByPort(proto2.Port_A)
|
|
|
|
|
case "B":
|
|
|
|
|
portPosition = turnout.FindLinkPositionByPort(proto2.Port_B)
|
|
|
|
|
case "C":
|
|
|
|
|
portPosition = turnout.FindLinkPositionByPort(proto2.Port_C)
|
|
|
|
|
default:
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("无效端口【%s】偏移量", port)))
|
|
|
|
|
}
|
|
|
|
|
// 关联link
|
|
|
|
|
link := portPosition.Link()
|
|
|
|
|
isStart := link.ARelation().Device().Id() == uid
|
|
|
|
|
if isStart {
|
|
|
|
|
return link.Id(), offset
|
|
|
|
|
} else {
|
|
|
|
|
return link.Id(), link.Length() - offset
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据设备信息、上下行,获取link运行方向,ab指向
|
|
|
|
|
// 入参:仿真Repository、uid、端口、上下行
|
|
|
|
|
// 输出:link运行方向、设备上的指向
|
|
|
|
|
func QueryUpAndABByDevice(repo *repository.Repository, uid, port string, runDirection bool) (up, ab bool) {
|
|
|
|
|
if port == "" {
|
|
|
|
|
up, ab = runDirectionSectionToUpAndAB(repo, uid, runDirection)
|
|
|
|
|
} else {
|
|
|
|
|
up, ab = runDirectionTurnoutToUpAndAB(repo, uid, port, runDirection)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据区段及上下行,获取link运行方向,ab指向
|
|
|
|
|
// 入参:仿真Repository、区段UID、上下行
|
|
|
|
|
// 输出:link运行方向、设备上的指向
|
|
|
|
|
func runDirectionSectionToUpAndAB(repo *repository.Repository, id string, runDirection bool) (up, ab bool) {
|
|
|
|
|
section := repo.FindPhysicalSection(id)
|
|
|
|
|
if section == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("地图不存在uid:%s缓存", id)))
|
|
|
|
|
}
|
|
|
|
|
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
|
|
|
|
|
// 是否从A到B,统一坐标
|
|
|
|
|
ak, bk := convertRepoBaseKm(repo, section.AKilometer()), convertRepoBaseKm(repo, section.BKilometer())
|
|
|
|
|
ab = (runDirection == (ak.Value <= bk.Value))
|
|
|
|
|
up = (ab == (ao < bo))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据区段及上下行,获取link运行方向,ab指向
|
|
|
|
|
// 入参:仿真Repository、道岔UID、道岔端口、上下行
|
|
|
|
|
// 输出:link运行方向,设备上的指向
|
|
|
|
|
func runDirectionTurnoutToUpAndAB(repo *repository.Repository, id, port string, runDirection bool) (up, ab bool) {
|
|
|
|
|
turnout := repo.FindTurnout(id)
|
|
|
|
|
if turnout == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("不存在道岔【uid:%s】", id)))
|
|
|
|
|
}
|
|
|
|
|
var portKm *proto2.Kilometer
|
|
|
|
|
var portPosition *repository.LinkPosition
|
|
|
|
|
switch port {
|
|
|
|
|
case "A":
|
|
|
|
|
portKm = convertRepoBaseKm(repo, turnout.GetTurnoutKm(proto2.Port_A))
|
|
|
|
|
portPosition = turnout.FindLinkPositionByPort(proto2.Port_A)
|
|
|
|
|
case "B":
|
|
|
|
|
portKm = convertRepoBaseKm(repo, turnout.GetTurnoutKm(proto2.Port_B))
|
|
|
|
|
portPosition = turnout.FindLinkPositionByPort(proto2.Port_B)
|
|
|
|
|
case "C":
|
|
|
|
|
portKm = convertRepoBaseKm(repo, turnout.GetTurnoutKm(proto2.Port_C))
|
|
|
|
|
portPosition = turnout.FindLinkPositionByPort(proto2.Port_C)
|
|
|
|
|
default:
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("无效端口【%s】偏移量", port)))
|
|
|
|
|
}
|
|
|
|
|
// 岔心公里标
|
|
|
|
|
crossKm := convertRepoBaseKm(repo, turnout.GetTurnoutKm(proto2.Port_None))
|
|
|
|
|
// 是否是link的起始断点
|
|
|
|
|
isStart := (portPosition.Link().ARelation() != nil && portPosition.Link().ARelation().Device().Id() == id)
|
|
|
|
|
up = runDirection
|
|
|
|
|
if (portKm.Value > crossKm.Value) != isStart {
|
|
|
|
|
up = !runDirection
|
|
|
|
|
}
|
|
|
|
|
ab = (portKm.Value > crossKm.Value) == runDirection
|
|
|
|
|
return
|
2023-10-19 17:42:01 +08:00
|
|
|
|
}
|
2023-10-26 10:05:28 +08:00
|
|
|
|
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 根据设备以及link运行方向,获取上下行、设备上的运行指向
|
|
|
|
|
// 入参:仿真Repository、道岔UID、道岔端口、上下行
|
|
|
|
|
// 输出:link运行方向,设备上的指向
|
|
|
|
|
func QueryDirectionAndABByDevice(repo *repository.Repository, uid, port string, up bool) (runDirection, ab bool) {
|
|
|
|
|
if port == "" {
|
|
|
|
|
runDirection, ab = upSectionToDirectionAndAB(repo, uid, up)
|
|
|
|
|
} else {
|
|
|
|
|
runDirection, ab = upTurnoutToDirectionAndAB(repo, uid, port, up)
|
2023-10-26 10:05:28 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据区段以及link运行方向,获取上下行、设备上的运行指向
|
|
|
|
|
// 入参:仿真Repository、道岔UID、道岔端口、上下行
|
|
|
|
|
// 输出:link运行方向,设备上的指向
|
|
|
|
|
func upSectionToDirectionAndAB(repo *repository.Repository, uid string, up bool) (runDirection, ab bool) {
|
|
|
|
|
section := repo.FindPhysicalSection(uid)
|
|
|
|
|
if section == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("地图不存在uid:%s缓存", uid)))
|
2023-10-26 10:05:28 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// a点偏移、b点偏移
|
|
|
|
|
ao, bo := section.ALinkPosition().Offset(), section.BLinkPosition().Offset()
|
|
|
|
|
// a点公里标、b点公里标
|
|
|
|
|
ak, bk := convertRepoBaseKm(repo, section.AKilometer()), convertRepoBaseKm(repo, section.BKilometer())
|
|
|
|
|
if up {
|
|
|
|
|
runDirection = ((ao < bo) == (ak.Value < bk.Value))
|
|
|
|
|
} else {
|
|
|
|
|
runDirection = ((ao > bo) == (ak.Value < bk.Value))
|
|
|
|
|
}
|
|
|
|
|
ab = (runDirection == (ak.Value < bk.Value))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据道岔以及link运行方向,获取上下行、设备上的运行指向
|
|
|
|
|
// 入参:仿真Repository、道岔UID、道岔端口、上下行
|
|
|
|
|
// 输出:link运行方向,设备上的指向
|
|
|
|
|
func upTurnoutToDirectionAndAB(repo *repository.Repository, uid, port string, up bool) (runDirection, ab bool) {
|
|
|
|
|
turnout := repo.FindTurnout(uid)
|
|
|
|
|
if turnout == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("不存在道岔【uid:%s】", uid)))
|
|
|
|
|
}
|
|
|
|
|
var port_enum proto2.Port
|
|
|
|
|
switch port {
|
|
|
|
|
case "A":
|
|
|
|
|
port_enum = proto2.Port_A
|
|
|
|
|
case "B":
|
|
|
|
|
port_enum = proto2.Port_B
|
|
|
|
|
case "C":
|
|
|
|
|
port_enum = proto2.Port_C
|
|
|
|
|
default:
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("无效端口【%s】偏移量", port)))
|
2023-10-26 10:05:28 +08:00
|
|
|
|
}
|
2023-11-08 11:02:41 +08:00
|
|
|
|
tpo := turnout.FindLinkPositionByPort(port_enum)
|
|
|
|
|
isA := tpo.Link().ARelation() != nil && tpo.Link().ARelation().Device().Id() == uid
|
|
|
|
|
crossKmInfo := convertRepoBaseKm(repo, turnout.GetTurnoutKm(proto2.Port_None))
|
|
|
|
|
portKmInfo := convertRepoBaseKm(repo, turnout.GetTurnoutKm(port_enum))
|
|
|
|
|
if isA {
|
|
|
|
|
ab = !up
|
|
|
|
|
runDirection = (up == (crossKmInfo.Value < portKmInfo.Value))
|
|
|
|
|
} else {
|
|
|
|
|
ab = up
|
|
|
|
|
runDirection = (up == (crossKmInfo.Value > portKmInfo.Value))
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据设备获取列车公里标
|
2023-11-09 10:20:50 +08:00
|
|
|
|
// 入参:仿真Repository、UID、端口、上下行、设备偏移
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 输出:公里标信息
|
|
|
|
|
func CalcTrainKilometer(repo *repository.Repository, uid, port string, runDirection bool, offset int64) (
|
|
|
|
|
km *proto2.Kilometer) {
|
|
|
|
|
if port == "" {
|
|
|
|
|
km = sectionOffsetToKilometer(repo, uid, runDirection, offset)
|
|
|
|
|
} else {
|
|
|
|
|
km = turnoutOffsetToKilometer(repo, uid, runDirection, offset)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取区段的上公里标
|
2023-11-09 10:20:50 +08:00
|
|
|
|
// 入参:仿真Repository、UID、上下行、设备偏移
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 输出:公里标信息
|
|
|
|
|
func sectionOffsetToKilometer(repo *repository.Repository, uid string, runDirection bool, offset int64) (km *proto2.Kilometer) {
|
|
|
|
|
section := repo.FindPhysicalSection(uid)
|
|
|
|
|
if section == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("地图不存在uid:%s缓存", uid)))
|
|
|
|
|
}
|
|
|
|
|
km = convertRepoBaseKm(repo, section.AKilometer())
|
|
|
|
|
if runDirection {
|
|
|
|
|
km.Value = km.Value + offset
|
|
|
|
|
} else {
|
|
|
|
|
km.Value = km.Value - offset
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取道岔的公里标
|
2023-11-09 10:20:50 +08:00
|
|
|
|
// 入参:仿真Repository、UID、上下行、设备偏移
|
2023-11-08 11:02:41 +08:00
|
|
|
|
// 输出:公里标信息
|
|
|
|
|
func turnoutOffsetToKilometer(repo *repository.Repository, uid string, runDirection bool, offset int64) (km *proto2.Kilometer) {
|
|
|
|
|
turnout := repo.FindTurnout(uid)
|
|
|
|
|
if turnout == nil {
|
|
|
|
|
panic(sys_error.New(fmt.Sprintf("不存在道岔【uid:%s】", uid)))
|
|
|
|
|
}
|
|
|
|
|
// 岔心公里标
|
|
|
|
|
km = convertRepoBaseKm(repo, turnout.GetTurnoutKm(proto2.Port_None))
|
|
|
|
|
if runDirection {
|
|
|
|
|
km.Value = km.Value + offset
|
|
|
|
|
} else {
|
|
|
|
|
km.Value = km.Value - offset
|
|
|
|
|
}
|
|
|
|
|
return
|
2023-10-26 10:05:28 +08:00
|
|
|
|
}
|
2023-11-09 14:19:48 +08:00
|
|
|
|
|
|
|
|
|
// 根据起始与末尾端查找经过的设备ID列表
|
|
|
|
|
// 入参:起始设备uid、起始设备端口、终点设备uid、在区段(a->b)或道岔(->岔心)上的找寻方向
|
|
|
|
|
// 输出:占用物理区段的ID
|
2023-11-09 17:54:31 +08:00
|
|
|
|
func QueryDeviceRoutePath(sim *VerifySimulation, startUid, endUid, startPort string, pointTo bool) (paths []string, err error) {
|
|
|
|
|
suid, port, direction := startUid, startPort, pointTo
|
2023-11-10 10:54:35 +08:00
|
|
|
|
pathMap := make(map[string]bool)
|
2023-11-09 14:19:48 +08:00
|
|
|
|
for {
|
|
|
|
|
device := sim.Repo.FindById(suid)
|
|
|
|
|
var nextRelation repository.DevicePort
|
|
|
|
|
switch device.Type() {
|
|
|
|
|
case proto2.DeviceType_DeviceType_PhysicalSection: // 区段
|
|
|
|
|
d := device.(*repository.PhysicalSection)
|
2023-11-10 10:54:35 +08:00
|
|
|
|
pathMap[d.Id()] = true
|
2023-11-09 14:19:48 +08:00
|
|
|
|
nextRelation = d.ARelation()
|
|
|
|
|
if direction {
|
|
|
|
|
nextRelation = d.BRelation()
|
|
|
|
|
}
|
|
|
|
|
case proto2.DeviceType_DeviceType_Turnout: // 道岔
|
|
|
|
|
d := device.(*repository.Turnout)
|
2023-11-10 10:54:35 +08:00
|
|
|
|
physicalSection := d.GetPhysicalSection()
|
|
|
|
|
if physicalSection == nil {
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New(fmt.Sprintf("道岔%s没有绑定物理区段", device.Id()))
|
2023-11-10 10:54:35 +08:00
|
|
|
|
break
|
2023-11-09 14:19:48 +08:00
|
|
|
|
}
|
2023-11-10 10:54:35 +08:00
|
|
|
|
pathMap[physicalSection.Id()] = true
|
2023-11-09 14:19:48 +08:00
|
|
|
|
var nextPort proto2.Port
|
|
|
|
|
switch port {
|
|
|
|
|
case "A":
|
|
|
|
|
nextPort = proto2.Port_A
|
|
|
|
|
case "B":
|
|
|
|
|
nextPort = proto2.Port_B
|
|
|
|
|
case "C":
|
|
|
|
|
nextPort = proto2.Port_C
|
|
|
|
|
}
|
2023-11-10 10:54:35 +08:00
|
|
|
|
if direction { // -> 岔心
|
2023-11-09 17:54:31 +08:00
|
|
|
|
nextPort, err = getTurnoutNextPort(sim, d.Id(), port)
|
2023-11-09 14:19:48 +08:00
|
|
|
|
}
|
|
|
|
|
nextRelation = d.GindDevicePortByPort(nextPort)
|
|
|
|
|
default:
|
2023-11-09 17:54:31 +08:00
|
|
|
|
err = sys_error.New(fmt.Sprintf("查找路径设备类型%s无处理处理", device.Type().String()))
|
2023-11-09 14:19:48 +08:00
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
if err != nil {
|
2023-11-10 10:54:35 +08:00
|
|
|
|
break
|
2023-11-09 14:19:48 +08:00
|
|
|
|
}
|
2023-11-09 17:54:31 +08:00
|
|
|
|
if suid == endUid {
|
2023-11-10 10:54:35 +08:00
|
|
|
|
break
|
2023-11-09 17:54:31 +08:00
|
|
|
|
}
|
|
|
|
|
if nextRelation == nil {
|
2023-11-10 10:54:35 +08:00
|
|
|
|
break
|
2023-11-09 14:19:48 +08:00
|
|
|
|
}
|
|
|
|
|
suid = nextRelation.Device().Id() // 下一个设备ID
|
|
|
|
|
port = nextRelation.Port().String() // 下一个道岔端
|
|
|
|
|
switch nextRelation.Device().Type() { // 查找方向
|
|
|
|
|
case proto2.DeviceType_DeviceType_PhysicalSection:
|
|
|
|
|
direction = nextRelation.Port() == proto2.Port_A
|
|
|
|
|
case proto2.DeviceType_DeviceType_Turnout:
|
|
|
|
|
direction = true
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-10 10:54:35 +08:00
|
|
|
|
for k := range pathMap {
|
|
|
|
|
paths = append(paths, k)
|
|
|
|
|
}
|
|
|
|
|
return
|
2023-11-09 14:19:48 +08:00
|
|
|
|
}
|