package memory import ( "encoding/hex" "fmt" "strings" "joylink.club/bj-rtsts-server/dto" "joylink.club/bj-rtsts-server/dto/data_proto" "joylink.club/bj-rtsts-server/sys_error" "joylink.club/rtsssimulation/component" "joylink.club/rtsssimulation/component/component_data" "joylink.club/rtsssimulation/entity" "joylink.club/rtsssimulation/repository" "joylink.club/rtsssimulation/repository/model/proto" "joylink.club/rtsssimulation/util/number" "sort" ) // BalisePositionModify 应答器移位 func BalisePositionModify(simulation *VerifySimulation, req *dto.BaliseMoveReqDto) *sys_error.BusinessError { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid transponder := simulation.Repo.FindTransponder(uid) if transponder == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } //将请求参数中的公里标转为rtss仿真所用的公里标 km := &proto.Kilometer{ Value: req.Km.Kilometer, CoordinateSystem: req.Km.CoordinateSystem, } if req.Km.Direction == data_proto.KilometerSystem_LEFT { km.Direction = proto.Direction_LEFT } else if req.Km.Direction == data_proto.KilometerSystem_RIGHT { km.Direction = proto.Direction_RIGHT } else { panic(fmt.Sprintf("未知的公里标方向[%d]", req.Km.Direction)) } //将应答器所在Link的两端公里标转为请求参数中公里标的坐标系 link := transponder.LinkPosition().Link() akm, err := repository.ConvertKilometer(simulation.Repo, link.AKm(), km.CoordinateSystem) if err != nil { panic(sys_error.New("应答器所在Link的起点公里标转换失败")) } bkm, err := repository.ConvertKilometer(simulation.Repo, link.BKm(), km.CoordinateSystem) if err != nil { panic(sys_error.New("应答器所在Link的终点公里标转换失败")) } //筛选出Link上所有的应答器,并按公里标大小排序 var transponders []*repository.Transponder for _, device := range link.Devices() { t, ok := device.(*repository.Transponder) if ok { transponders = append(transponders, t) } } sort.Slice(transponders, func(i, j int) bool { aT := transponders[i] bT := transponders[j] aTKm, err := repository.ConvertKilometer(simulation.Repo, aT.Km(), km.CoordinateSystem) if err != nil { panic(sys_error.New(fmt.Sprintf("应答器[id:%s]公里标转换失败", aT.Id()))) } bTKm, err := repository.ConvertKilometer(simulation.Repo, bT.Km(), km.CoordinateSystem) if err != nil { panic(sys_error.New(fmt.Sprintf("应答器[id:%s]公里标转换失败", bT.Id()))) } return aTKm.Value < bTKm.Value }) //确保请求的公里标没有超出Link范围且在相邻的应答器之间 var minKm *proto.Kilometer var maxKm *proto.Kilometer if akm.Value < bkm.Value { minKm = akm maxKm = bkm } else { minKm = bkm maxKm = akm } for i, t := range transponders { if t == transponder { if i > 0 { minKm, err = repository.ConvertKilometer(simulation.Repo, transponders[i-1].Km(), km.CoordinateSystem) } if i < len(transponders)-1 { maxKm, err = repository.ConvertKilometer(simulation.Repo, transponders[i+1].Km(), km.CoordinateSystem) } } } //更新应答器公里标和Link位置 entry, _ := entity.GetEntityByUid(simulation.World, uid) if km.Value <= minKm.Value || km.Value >= maxKm.Value { return sys_error.New("位置设置错误,必须在相邻的应答器/道岔/轨道边界之间") } component.KmType.Set(entry, km) offset := number.Abs(km.Value - akm.Value) component.LinkPositionType.Set(entry, &component_data.LinkPosition{ LinkId: link.Id(), Offset: offset, }) return nil } // BalisePositionReset 应答器复位 func BalisePositionReset(simulation *VerifySimulation, req *dto.BaliseReqDto) error { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid balise := simulation.Repo.FindTransponder(uid) if balise == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } return balisePositionReset(simulation, balise) } func balisePositionReset(simulation *VerifySimulation, balise *repository.Transponder) error { entry, _ := entity.GetEntityByUid(simulation.World, balise.Id()) component.KmType.Set(entry, balise.Km()) component.LinkPositionType.SetValue(entry, component_data.LinkPosition{ LinkId: balise.LinkPosition().Link().Id(), Offset: balise.LinkPosition().Offset(), }) return nil } // BaliseTelegramModify 修改应答器报文 func BaliseTelegramModify(simulation *VerifySimulation, req *dto.BaliseModifyTelegramReqDto) error { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid entry, ok := entity.GetEntityByUid(simulation.World, uid) if !ok { return sys_error.New(fmt.Sprintf("没有[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } if len(req.Telegram) != 256 { return sys_error.New(fmt.Sprintf("报文长度必须为[%d]", 256)) } bytes, err := hex.DecodeString(req.Telegram) if err != nil { return sys_error.New("报文解析出错", err) } component.BaliseStateType.SetValue(entry, component.BaliseState{ValidTelegram: bytes}) return nil } // BaliseTelegramReset 重置应答器报文 func BaliseTelegramReset(simulation *VerifySimulation, req *dto.BaliseReqDto) error { uid := QueryMapUidMapByType(req.MapId, &data_proto.Transponder{})[req.BaliseId].Uid worldData := entity.GetWorldData(simulation.World) balise := worldData.Repo.FindTransponder(uid) if balise == nil { return sys_error.New(fmt.Sprintf("未找到[mapId:%d id:%d]的应答器", req.MapId, req.BaliseId)) } return baliseTelegramReset(simulation, balise) } func baliseTelegramReset(simulation *VerifySimulation, balise *repository.Transponder) error { entry, _ := entity.GetEntityByUid(simulation.World, balise.Id()) component.BaliseStateType.SetValue(entry, component.BaliseState{ ValidTelegram: balise.FixedTelegram(), }) return nil } // BaliseReset 重置应答器所有状态 func BaliseReset(simulation *VerifySimulation) error { var errs []error for _, balise := range simulation.Repo.ResponderList() { err := baliseTelegramReset(simulation, balise) if err != nil { errs = append(errs, err) } err = balisePositionReset(simulation, balise) if err != nil { errs = append(errs, err) } } if len(errs) > 0 { var userMsg []string for _, err := range errs { be, ok := err.(*sys_error.BusinessError) if ok { userMsg = append(userMsg, be.UserMsg) } } return sys_error.New(strings.Join(userMsg, "\n")) } return nil }